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

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	log "github.com/sirupsen/logrus"

	"github.com/bboozzoo/viadown/assets"
)

var (
	ErrUpstreamFailed    = errors.New("upstream request failed")
	ErrUpstreamBadStatus = errors.New("upstream returned unexpected status")
	ErrInternal          = errors.New("internal error")
)

type ViaDownloadServer struct {
	Mirrors       *Mirrors
	Cache         *Cache
	ClientTimeout time.Duration
	Router        *mux.Router
	vfs           http.FileSystem
	httpFs        http.Handler
}

func loggingMiddleware(next http.Handler) http.Handler {
	buf := bytes.Buffer{}
	lh := handlers.LoggingHandler(&buf, next)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lh.ServeHTTP(w, r)
		log.Info(strings.TrimSpace(buf.String()))
		buf.Reset()
	})
}

func NewViaDownloadServer(mirrors *Mirrors, cache *Cache, clientTimeout time.Duration) *ViaDownloadServer {
	vfs := assets.FS(false)
	vs := &ViaDownloadServer{
		Mirrors:       mirrors,
		Cache:         cache,
		ClientTimeout: clientTimeout,
		vfs:           vfs,
		httpFs:        http.FileServer(vfs),
	}
	r := mux.NewRouter()
	r.HandleFunc("/_viadown/count", vs.countHandler).Methods(http.MethodGet)
	r.HandleFunc("/_viadown/stats", vs.statsHandler).Methods(http.MethodGet)
	r.HandleFunc("/_viadown/data", vs.dataDeleteHandler).Methods(http.MethodDelete)
	r.PathPrefix("/_viadown/static").Handler(http.StripPrefix("/_viadown/static", vs.httpFs))
	r.PathPrefix("/_viadown/").Handler(http.StripPrefix("/_viadown/", vs.httpFs))
	r.Handle("/_viadown", http.RedirectHandler("/_viadown/", http.StatusMovedPermanently))
	r.PathPrefix("/").Methods(http.MethodGet).HandlerFunc(vs.maybeCachedHandler)
	r.Use(loggingMiddleware)
	vs.Router = r

	return vs
}

func (v *ViaDownloadServer) indexHandler(w http.ResponseWriter, r *http.Request) {
	log.Info("index handler")
	http.StripPrefix("/_viadown", v.httpFs)
}

func (v *ViaDownloadServer) returnError(w http.ResponseWriter, status int, err error) {
	type apiError struct {
		Error string
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	enc := json.NewEncoder(w)
	enc.Encode(apiError{Error: err.Error()})
}

func (v *ViaDownloadServer) returnOk(w http.ResponseWriter, what interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	enc := json.NewEncoder(w)
	enc.Encode(what)
}

func (v *ViaDownloadServer) statsHandler(w http.ResponseWriter, r *http.Request) {
	log.Infof("stats handler")
	v.returnOk(w, v.Cache.Stats())
}

func (v *ViaDownloadServer) countHandler(w http.ResponseWriter, r *http.Request) {
	log.Infof("count handler")
	count, err := v.Cache.Count()
	if err != nil {
		v.returnError(w, http.StatusInternalServerError, err)
		return
	}
	v.returnOk(w, count)
}

func (v *ViaDownloadServer) dataDeleteHandler(w http.ResponseWriter, r *http.Request) {
	log.Infof("cache purge handler")
	if err := r.ParseForm(); err != nil {
		v.returnError(w, http.StatusBadRequest, errors.New("malformed request"))
		return
	}
	s := r.FormValue("older-than-days")
	if s == "" {
		v.returnError(w, http.StatusBadRequest, errors.New("older-than-days not provided"))
		return
	}
	olderThanDays, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		v.returnError(w, http.StatusBadRequest, errors.New("older-than-days is not an integer"))
		return
	}
	removed, err := v.Cache.Purge(PurgeSelector{
		OlderThan: time.Duration(olderThanDays) * 24 * time.Hour,
	})
	if err != nil {
		v.returnError(w, http.StatusInternalServerError, err)
		return
	}
	type removedInfo struct {
		Removed uint64
	}
	v.returnOk(w, removedInfo{Removed: removed})
}

func (v *ViaDownloadServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	v.Router.ServeHTTP(w, r)
}

func (v *ViaDownloadServer) maybeCachedHandler(w http.ResponseWriter, r *http.Request) {
	upath := r.URL.Path

	if since, err := http.ParseTime(r.Header.Get("If-Modified-Since")); err == nil {
		log.Debugf("has modified since: %v, poke upstream first", since)
	} else {
		// no modified since header, try to get from cache
		found, err := doFromCache(upath, w, r, v.Cache)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
		}
		if found {
			return
		}
	}

	client := http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: v.ClientTimeout,
			}).Dial,
			TLSHandshakeTimeout:   v.ClientTimeout,
			ResponseHeaderTimeout: v.ClientTimeout,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	for _, mirror := range v.Mirrors.List {
		url := buildURL(mirror, upath)
		req, err := http.NewRequest(http.MethodGet, url, nil)
		if err != nil {
			log.Errorf("failed to prepare request: %v", err)
			w.WriteHeader(http.StatusBadGateway)
			return
		}
		// copy some headers from the original request
		copyHeaders(req.Header, r.Header,
			[]string{"Accept", "If-Modified-Since"})

		err = doFromUpstream(upath, &client, req, w, v.Cache)
		switch {
		case err == ErrInternal:
			w.WriteHeader(http.StatusInternalServerError)
			return
		case err == ErrUpstreamBadStatus:
			return
		case err == nil:
			return
		}
	}
}

func doFromCache(name string, w http.ResponseWriter, r *http.Request, cache *Cache) (bool, error) {
	cachedr, sz, err := cache.Get(name)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		log.Errorf("cache get failed: %v", err)
		return false, errors.New("cache access failed")
	}

	log.Debugf("getting from cache, size: %v", sz)
	defer cachedr.Close()

	w.Header().Set("Content-Type", "application/octet-stream")
	http.ServeContent(w, r, name, time.Now(), cachedr)

	return true, nil
}

func doFromUpstream(name string, client *http.Client, req *http.Request,
	w http.ResponseWriter, cache *Cache) error {

	rsp, err := client.Do(req)
	if err != nil {
		return ErrUpstreamFailed
	}
	log.Debugf("got response: %v", rsp)
	defer rsp.Body.Close()

	if rsp.StatusCode != 200 {
		log.Errorf("got status %v from upstream %s",
			rsp.StatusCode, req.URL)
		// TODO be smart, return ErrMirrorTryAnother for 404 requests
		// possibly
		copyHeaders(w.Header(), rsp.Header,
			[]string{"Content-Type", "Content-Length",
				"ETag", "Last-Modified",
				"Date"})
		w.WriteHeader(rsp.StatusCode)
		// got non 200 status, just forward
		io.Copy(w, rsp.Body)
		return ErrUpstreamBadStatus
	}

	out, err := cache.Put(name)
	if err != nil {
		return ErrInternal
	}
	defer out.Commit()

	// setup TeeReader so that the data makes to the disk while it's also
	// sent to the original requester
	tr := io.TeeReader(rsp.Body, out)

	// copy over headers from upstream response
	copyHeaders(w.Header(), rsp.Header,
		[]string{"Content-Type", "Content-Length",
			"ETag", "Last-Modified",
			"Date"})
	// let the client know we're good
	w.WriteHeader(http.StatusOK)

	log.Infof("downloading %v from %s to cache", name, req.URL)
	// send over the data
	if _, err := io.Copy(w, tr); err != nil {
		// we've already sent a status header, we're just streaming data
		// now, if that fails, discard any data cached so far
		log.Errorf("copy failed: %v, discarding cache entry", err)
		if err := out.Abort(); err != nil {
			log.Errorf("failed to discard cache entry: %v", err)
		}
	}
	log.Debugf("upstream download finished")
	return nil
}

func copyHeaders(to http.Header, from http.Header, which []string) {
	for _, hdr := range which {
		hv := from.Get(hdr)
		if hv != "" {
			to.Set(hdr, hv)
		}
	}
}

func buildURL(base, path string) string {
	if !strings.HasSuffix(base, "/") {
		base += "/"
	}

	if strings.HasPrefix(path, "/") {
		path = path[1:]
	}
	return base + path
}
<commit_msg>via: allow direct assets access<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Maciek Borzecki <maciek.borzecki@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	log "github.com/sirupsen/logrus"

	"github.com/bboozzoo/viadown/assets"
)

var (
	ErrUpstreamFailed    = errors.New("upstream request failed")
	ErrUpstreamBadStatus = errors.New("upstream returned unexpected status")
	ErrInternal          = errors.New("internal error")
)

type ViaDownloadServer struct {
	Mirrors       *Mirrors
	Cache         *Cache
	ClientTimeout time.Duration
	Router        *mux.Router
	vfs           http.FileSystem
	httpFs        http.Handler
}

func loggingMiddleware(next http.Handler) http.Handler {
	buf := bytes.Buffer{}
	lh := handlers.LoggingHandler(&buf, next)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		lh.ServeHTTP(w, r)
		log.Info(strings.TrimSpace(buf.String()))
		buf.Reset()
	})
}

func NewViaDownloadServer(mirrors *Mirrors, cache *Cache, clientTimeout time.Duration) *ViaDownloadServer {
	vfs := assets.FS(false)
	if assetsDir := os.Getenv("ASSETS_DIR"); assetsDir != "" {
		log.Infof("using assets directory: %v", assetsDir)
		vfs = http.Dir(assetsDir)
	}
	vs := &ViaDownloadServer{
		Mirrors:       mirrors,
		Cache:         cache,
		ClientTimeout: clientTimeout,
		vfs:           vfs,
		httpFs:        http.FileServer(vfs),
	}
	r := mux.NewRouter()
	r.HandleFunc("/_viadown/count", vs.countHandler).Methods(http.MethodGet)
	r.HandleFunc("/_viadown/stats", vs.statsHandler).Methods(http.MethodGet)
	r.HandleFunc("/_viadown/data", vs.dataDeleteHandler).Methods(http.MethodDelete)
	r.PathPrefix("/_viadown/static").Handler(http.StripPrefix("/_viadown/static", vs.httpFs))
	r.PathPrefix("/_viadown/").Handler(http.StripPrefix("/_viadown/", vs.httpFs))
	r.Handle("/_viadown", http.RedirectHandler("/_viadown/", http.StatusMovedPermanently))
	r.PathPrefix("/").Methods(http.MethodGet).HandlerFunc(vs.maybeCachedHandler)
	r.Use(loggingMiddleware)
	vs.Router = r

	return vs
}

func (v *ViaDownloadServer) indexHandler(w http.ResponseWriter, r *http.Request) {
	log.Info("index handler")
	http.StripPrefix("/_viadown", v.httpFs)
}

func (v *ViaDownloadServer) returnError(w http.ResponseWriter, status int, err error) {
	type apiError struct {
		Error string
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	enc := json.NewEncoder(w)
	enc.Encode(apiError{Error: err.Error()})
}

func (v *ViaDownloadServer) returnOk(w http.ResponseWriter, what interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	enc := json.NewEncoder(w)
	enc.Encode(what)
}

func (v *ViaDownloadServer) statsHandler(w http.ResponseWriter, r *http.Request) {
	log.Infof("stats handler")
	v.returnOk(w, v.Cache.Stats())
}

func (v *ViaDownloadServer) countHandler(w http.ResponseWriter, r *http.Request) {
	log.Infof("count handler")
	count, err := v.Cache.Count()
	if err != nil {
		v.returnError(w, http.StatusInternalServerError, err)
		return
	}
	v.returnOk(w, count)
}

func (v *ViaDownloadServer) dataDeleteHandler(w http.ResponseWriter, r *http.Request) {
	log.Infof("cache purge handler")
	if err := r.ParseForm(); err != nil {
		v.returnError(w, http.StatusBadRequest, errors.New("malformed request"))
		return
	}
	s := r.FormValue("older-than-days")
	if s == "" {
		v.returnError(w, http.StatusBadRequest, errors.New("older-than-days not provided"))
		return
	}
	olderThanDays, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		v.returnError(w, http.StatusBadRequest, errors.New("older-than-days is not an integer"))
		return
	}
	removed, err := v.Cache.Purge(PurgeSelector{
		OlderThan: time.Duration(olderThanDays) * 24 * time.Hour,
	})
	if err != nil {
		v.returnError(w, http.StatusInternalServerError, err)
		return
	}
	type removedInfo struct {
		Removed uint64
	}
	v.returnOk(w, removedInfo{Removed: removed})
}

func (v *ViaDownloadServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	v.Router.ServeHTTP(w, r)
}

func (v *ViaDownloadServer) maybeCachedHandler(w http.ResponseWriter, r *http.Request) {
	upath := r.URL.Path

	if since, err := http.ParseTime(r.Header.Get("If-Modified-Since")); err == nil {
		log.Debugf("has modified since: %v, poke upstream first", since)
	} else {
		// no modified since header, try to get from cache
		found, err := doFromCache(upath, w, r, v.Cache)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
		}
		if found {
			return
		}
	}

	client := http.Client{
		Transport: &http.Transport{
			Dial: (&net.Dialer{
				Timeout: v.ClientTimeout,
			}).Dial,
			TLSHandshakeTimeout:   v.ClientTimeout,
			ResponseHeaderTimeout: v.ClientTimeout,
			ExpectContinueTimeout: 1 * time.Second,
		},
	}

	for _, mirror := range v.Mirrors.List {
		url := buildURL(mirror, upath)
		req, err := http.NewRequest(http.MethodGet, url, nil)
		if err != nil {
			log.Errorf("failed to prepare request: %v", err)
			w.WriteHeader(http.StatusBadGateway)
			return
		}
		// copy some headers from the original request
		copyHeaders(req.Header, r.Header,
			[]string{"Accept", "If-Modified-Since"})

		err = doFromUpstream(upath, &client, req, w, v.Cache)
		switch {
		case err == ErrInternal:
			w.WriteHeader(http.StatusInternalServerError)
			return
		case err == ErrUpstreamBadStatus:
			return
		case err == nil:
			return
		}
	}
}

func doFromCache(name string, w http.ResponseWriter, r *http.Request, cache *Cache) (bool, error) {
	cachedr, sz, err := cache.Get(name)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		log.Errorf("cache get failed: %v", err)
		return false, errors.New("cache access failed")
	}

	log.Debugf("getting from cache, size: %v", sz)
	defer cachedr.Close()

	w.Header().Set("Content-Type", "application/octet-stream")
	http.ServeContent(w, r, name, time.Now(), cachedr)

	return true, nil
}

func doFromUpstream(name string, client *http.Client, req *http.Request,
	w http.ResponseWriter, cache *Cache) error {

	rsp, err := client.Do(req)
	if err != nil {
		return ErrUpstreamFailed
	}
	log.Debugf("got response: %v", rsp)
	defer rsp.Body.Close()

	if rsp.StatusCode != 200 {
		log.Errorf("got status %v from upstream %s",
			rsp.StatusCode, req.URL)
		// TODO be smart, return ErrMirrorTryAnother for 404 requests
		// possibly
		copyHeaders(w.Header(), rsp.Header,
			[]string{"Content-Type", "Content-Length",
				"ETag", "Last-Modified",
				"Date"})
		w.WriteHeader(rsp.StatusCode)
		// got non 200 status, just forward
		io.Copy(w, rsp.Body)
		return ErrUpstreamBadStatus
	}

	out, err := cache.Put(name)
	if err != nil {
		return ErrInternal
	}
	defer out.Commit()

	// setup TeeReader so that the data makes to the disk while it's also
	// sent to the original requester
	tr := io.TeeReader(rsp.Body, out)

	// copy over headers from upstream response
	copyHeaders(w.Header(), rsp.Header,
		[]string{"Content-Type", "Content-Length",
			"ETag", "Last-Modified",
			"Date"})
	// let the client know we're good
	w.WriteHeader(http.StatusOK)

	log.Infof("downloading %v from %s to cache", name, req.URL)
	// send over the data
	if _, err := io.Copy(w, tr); err != nil {
		// we've already sent a status header, we're just streaming data
		// now, if that fails, discard any data cached so far
		log.Errorf("copy failed: %v, discarding cache entry", err)
		if err := out.Abort(); err != nil {
			log.Errorf("failed to discard cache entry: %v", err)
		}
	}
	log.Debugf("upstream download finished")
	return nil
}

func copyHeaders(to http.Header, from http.Header, which []string) {
	for _, hdr := range which {
		hv := from.Get(hdr)
		if hv != "" {
			to.Set(hdr, hv)
		}
	}
}

func buildURL(base, path string) string {
	if !strings.HasSuffix(base, "/") {
		base += "/"
	}

	if strings.HasPrefix(path, "/") {
		path = path[1:]
	}
	return base + path
}
<|endoftext|>


<commit_before>package web

import (
    "bytes"
    "container/vector"
    "fmt"
    "http"
    "log"
    "os"
    "path"
    "rand"
    "reflect"
    "regexp"
    "strings"
    "time"
)

var rgen = rand.New(rand.NewSource(time.Nanoseconds()))

type conn interface {
    StartResponse(status int)
    SetHeader(hdr string, val string, unique bool)
    Write(data []byte) (n int, err os.Error)
    Close()
}

type Context struct {
    *Request
    *conn
    Session         *session
    responseStarted bool
}

func (ctx *Context) StartResponse(status int) {
    ctx.conn.StartResponse(status)
    ctx.responseStarted = true
}

func (ctx *Context) Write(data []byte) (n int, err os.Error) {
    if !ctx.responseStarted {
        ctx.StartResponse(200)
    }
    return ctx.conn.Write(data)
}
func (ctx *Context) WriteString(content string) {
    ctx.Write(strings.Bytes(content))
}

func (ctx *Context) Abort(status int, body string) {
    ctx.StartResponse(status)
    ctx.WriteString(body)
}

func (ctx *Context) Redirect(status int, url string) {
    //note := "" + statusText[code] + ".\n"

    ctx.SetHeader("Location", url, true)
    ctx.StartResponse(status)
    ctx.WriteString("")
}
//Sets a cookie -- duration is the amount of time in seconds. 0 = forever
func (ctx *Context) SetCookie(name string, value string, duration int64) {
    if duration == 0 {
        //do some really long time
    }

    utctime := time.UTC()
    utc1 := time.SecondsToUTC(utctime.Seconds() + 60*30)
    expires := utc1.RFC1123()
    expires = expires[0:len(expires)-3] + "GMT"
    cookie := fmt.Sprintf("%s=%s; expires=%s", name, value, expires)
    ctx.SetHeader("Set-Cookie", cookie, false)
}

var sessionMap = make(map[string]*session)

func randomString(length int) string {
    pop := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    var res bytes.Buffer

    for i := 0; i < length; i++ {
        rnd := rgen.Intn(len(pop))
        res.WriteByte(pop[rnd])
    }

    return res.String()
}

type session struct {
    Data map[string]interface{}
    Id   string
}

func newSession() *session {
    s := session{
        Data: make(map[string]interface{}),
        Id: randomString(10),
    }

    return &s
}

func (s *session) save() { sessionMap[s.Id] = s }

var contextType reflect.Type
var staticDir string

const sessionKey = "wgosession"

func init() {
    contextType = reflect.Typeof(Context{})
    SetStaticDir("static")
}

type route struct {
    r       string
    cr      *regexp.Regexp
    method  string
    handler *reflect.FuncValue
}

var routes = make(map[*regexp.Regexp]route)

func addRoute(r string, method string, handler interface{}) {
    cr, err := regexp.Compile(r)
    if err != nil {
        log.Stderrf("Error in route regex %q\n", r)
        return
    }
    fv := reflect.NewValue(handler).(*reflect.FuncValue)
    routes[cr] = route{r, cr, method, fv}
}

type httpConn struct {
    conn *http.Conn
}

func (c *httpConn) StartResponse(status int) { c.conn.WriteHeader(status) }

func (c *httpConn) SetHeader(hdr string, val string, unique bool) {
    //right now unique can't be implemented through the http package.
    //see issue 488
    c.conn.SetHeader(hdr, val)
}

func (c *httpConn) WriteString(content string) {
    buf := bytes.NewBufferString(content)
    c.conn.Write(buf.Bytes())
}

func (c *httpConn) Write(content []byte) (n int, err os.Error) {
    return c.conn.Write(content)
}

func (c *httpConn) Close() {
    rwc, buf, _ := c.conn.Hijack()
    if buf != nil {
        buf.Flush()
    }

    if rwc != nil {
        rwc.Close()
    }
}

func httpHandler(c *http.Conn, req *http.Request) {
    conn := httpConn{c}

    wreq := newRequest(req)

    routeHandler(wreq, &conn)
}

func routeHandler(req *Request, c conn) {
    requestPath := req.URL.Path

    //log the request
    if len(req.URL.RawQuery) == 0 {
        log.Stdout(requestPath)
    } else {
        log.Stdout(requestPath + "?" + req.URL.RawQuery)
    }

    //parse the form data (if it exists)
    perr := req.ParseParams()
    if perr != nil {
        log.Stderrf("Failed to parse form data %q", perr.String())
    }

    //check the cookies for a session id
    perr = req.ParseCookies()
    if perr != nil {
        log.Stderrf("Failed to parse cookies %q", perr.String())
    }

    s := newSession()

    for k, v := range (req.Cookies) {
        if k == sessionKey {
            if sess, ok := sessionMap[v]; ok {
                s = sess
            }
        }
    }

    ctx := Context{req, &c, s, false}

    //try to serve a static file
    staticFile := path.Join(staticDir, requestPath)
    if fileExists(staticFile) {
        serveFile(&ctx, staticFile)
        return
    }

    //set default encoding
    ctx.SetHeader("Content-Type", "text/html; charset=utf-8", true)
    ctx.SetHeader("Server", "web.go", true)

    for cr, route := range routes {
        if req.Method != route.method {
            continue
        }

        if !cr.MatchString(requestPath) {
            continue
        }
        match := cr.MatchStrings(requestPath)

        if len(match[0]) != len(requestPath) {
            continue
        }

        var args vector.Vector

        handlerType := route.handler.Type().(*reflect.FuncType)

        //check if the first arg in the handler is a context type
        if handlerType.NumIn() > 0 {
            if a0, ok := handlerType.In(0).(*reflect.PtrType); ok {
                typ := a0.Elem()
                if typ == contextType {
                    args.Push(reflect.NewValue(&ctx))
                }
            }
        }

        for _, arg := range match[1:] {
            args.Push(reflect.NewValue(arg))
        }

        if len(args) != handlerType.NumIn() {
            log.Stderrf("Incorrect number of arguments for %s\n", requestPath)
            ctx.Abort(500, "Server Error")
            return
        }

        valArgs := make([]reflect.Value, len(args))
        for i, j := range (args) {
            valArgs[i] = j.(reflect.Value)
        }

        ret := route.handler.Call(valArgs)

        if len(ret) == 0 {
            return
        }

        sval, ok := ret[0].(*reflect.StringValue)

        if ok && !ctx.responseStarted {
            //check if session data is stored
            if len(s.Data) > 0 {
                s.save()
                //set the session for half an hour
                ctx.SetCookie(sessionKey, s.Id, 1800)
            }

            ctx.StartResponse(200)
            ctx.WriteString(sval.Get())
        }

        return
    }

    ctx.Abort(404, "Page not found")
}

//runs the web application and serves http requests
func Run(addr string) {
    http.Handle("/", http.HandlerFunc(httpHandler))

    log.Stdoutf("web.go serving %s", addr)
    err := http.ListenAndServe(addr, nil)
    if err != nil {
        log.Exit("ListenAndServe:", err)
    }
}

//runs the web application and serves scgi requests
func RunScgi(addr string) {
    log.Stdoutf("web.go serving scgi %s", addr)
    listenAndServeScgi(addr)
}

//runs the web application by serving fastcgi requests
func RunFcgi(addr string) {
    log.Stdoutf("web.go serving fcgi %s", addr)
    listenAndServeFcgi(addr)
}

//Adds a handler for the 'GET' http method.
func Get(route string, handler interface{}) { addRoute(route, "GET", handler) }

//Adds a handler for the 'POST' http method.
func Post(route string, handler interface{}) { addRoute(route, "POST", handler) }

//Adds a handler for the 'PUT' http method.
func Put(route string, handler interface{}) { addRoute(route, "PUT", handler) }

//Adds a handler for the 'DELETE' http method.
func Delete(route string, handler interface{}) {
    addRoute(route, "DELETE", handler)
}

func dirExists(dir string) bool {
    d, e := os.Stat(dir)
    switch {
    case e != nil:
        return false
    case !d.IsDirectory():
        return false
    }

    return true
}

func fileExists(dir string) bool {
    d, e := os.Stat(dir)
    switch {
    case e != nil:
        return false
    case !d.IsRegular():
        return false
    }

    return true
}

type dirError string

func (path dirError) String() string { return "Failed to set directory " + string(path) }

func getCwd() string { return os.Getenv("PWD") }

//changes the location of the static directory. by default, it's under the 'static' folder
//of the directory containing the web application
func SetStaticDir(dir string) os.Error {
    cwd := getCwd()
    sd := path.Join(cwd, dir)
    if !dirExists(sd) {
        return dirError(sd)

    }
    staticDir = sd

    return nil
}

func Urlencode ( data map[string]string ) string {
        var buf bytes.Buffer;
        for k,v := range ( data ) {
                buf.WriteString ( http.URLEscape(k) )
                buf.WriteByte('=' )
                buf.WriteString ( http.URLEscape(v) )
                buf.WriteByte('&' )
        }
        s := buf.String()
        return s[0:len(s) - 1]
}

//copied from go's http package, because it's not public
var statusText = map[int]string{
    http.StatusContinue: "Continue",
    http.StatusSwitchingProtocols: "Switching Protocols",

    http.StatusOK: "OK",
    http.StatusCreated: "Created",
    http.StatusAccepted: "Accepted",
    http.StatusNonAuthoritativeInfo: "Non-Authoritative Information",
    http.StatusNoContent: "No Content",
    http.StatusResetContent: "Reset Content",
    http.StatusPartialContent: "Partial Content",

    http.StatusMultipleChoices: "Multiple Choices",
    http.StatusMovedPermanently: "Moved Permanently",
    http.StatusFound: "Found",
    http.StatusSeeOther: "See Other",
    http.StatusNotModified: "Not Modified",
    http.StatusUseProxy: "Use Proxy",
    http.StatusTemporaryRedirect: "Temporary Redirect",

    http.StatusBadRequest: "Bad Request",
    http.StatusUnauthorized: "Unauthorized",
    http.StatusPaymentRequired: "Payment Required",
    http.StatusForbidden: "Forbidden",
    http.StatusNotFound: "Not Found",
    http.StatusMethodNotAllowed: "Method Not Allowed",
    http.StatusNotAcceptable: "Not Acceptable",
    http.StatusProxyAuthRequired: "Proxy Authentication Required",
    http.StatusRequestTimeout: "Request Timeout",
    http.StatusConflict: "Conflict",
    http.StatusGone: "Gone",
    http.StatusLengthRequired: "Length Required",
    http.StatusPreconditionFailed: "Precondition Failed",
    http.StatusRequestEntityTooLarge: "Request Entity Too Large",
    http.StatusRequestURITooLong: "Request URI Too Long",
    http.StatusUnsupportedMediaType: "Unsupported Media Type",
    http.StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
    http.StatusExpectationFailed: "Expectation Failed",

    http.StatusInternalServerError: "Internal Server Error",
    http.StatusNotImplemented: "Not Implemented",
    http.StatusBadGateway: "Bad Gateway",
    http.StatusServiceUnavailable: "Service Unavailable",
    http.StatusGatewayTimeout: "Gateway Timeout",
    http.StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
}
<commit_msg>Make web.go compile on -release. It was using some new features from the vector package<commit_after>package web

import (
    "bytes"
    "container/vector"
    "fmt"
    "http"
    "log"
    "os"
    "path"
    "rand"
    "reflect"
    "regexp"
    "strings"
    "time"
)

var rgen = rand.New(rand.NewSource(time.Nanoseconds()))

type conn interface {
    StartResponse(status int)
    SetHeader(hdr string, val string, unique bool)
    Write(data []byte) (n int, err os.Error)
    Close()
}

type Context struct {
    *Request
    *conn
    Session         *session
    responseStarted bool
}

func (ctx *Context) StartResponse(status int) {
    ctx.conn.StartResponse(status)
    ctx.responseStarted = true
}

func (ctx *Context) Write(data []byte) (n int, err os.Error) {
    if !ctx.responseStarted {
        ctx.StartResponse(200)
    }
    return ctx.conn.Write(data)
}
func (ctx *Context) WriteString(content string) {
    ctx.Write(strings.Bytes(content))
}

func (ctx *Context) Abort(status int, body string) {
    ctx.StartResponse(status)
    ctx.WriteString(body)
}

func (ctx *Context) Redirect(status int, url string) {
    //note := "" + statusText[code] + ".\n"

    ctx.SetHeader("Location", url, true)
    ctx.StartResponse(status)
    ctx.WriteString("")
}
//Sets a cookie -- duration is the amount of time in seconds. 0 = forever
func (ctx *Context) SetCookie(name string, value string, duration int64) {
    if duration == 0 {
        //do some really long time
    }

    utctime := time.UTC()
    utc1 := time.SecondsToUTC(utctime.Seconds() + 60*30)
    expires := utc1.RFC1123()
    expires = expires[0:len(expires)-3] + "GMT"
    cookie := fmt.Sprintf("%s=%s; expires=%s", name, value, expires)
    ctx.SetHeader("Set-Cookie", cookie, false)
}

var sessionMap = make(map[string]*session)

func randomString(length int) string {
    pop := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    var res bytes.Buffer

    for i := 0; i < length; i++ {
        rnd := rgen.Intn(len(pop))
        res.WriteByte(pop[rnd])
    }

    return res.String()
}

type session struct {
    Data map[string]interface{}
    Id   string
}

func newSession() *session {
    s := session{
        Data: make(map[string]interface{}),
        Id: randomString(10),
    }

    return &s
}

func (s *session) save() { sessionMap[s.Id] = s }

var contextType reflect.Type
var staticDir string

const sessionKey = "wgosession"

func init() {
    contextType = reflect.Typeof(Context{})
    SetStaticDir("static")
}

type route struct {
    r       string
    cr      *regexp.Regexp
    method  string
    handler *reflect.FuncValue
}

var routes = make(map[*regexp.Regexp]route)

func addRoute(r string, method string, handler interface{}) {
    cr, err := regexp.Compile(r)
    if err != nil {
        log.Stderrf("Error in route regex %q\n", r)
        return
    }
    fv := reflect.NewValue(handler).(*reflect.FuncValue)
    routes[cr] = route{r, cr, method, fv}
}

type httpConn struct {
    conn *http.Conn
}

func (c *httpConn) StartResponse(status int) { c.conn.WriteHeader(status) }

func (c *httpConn) SetHeader(hdr string, val string, unique bool) {
    //right now unique can't be implemented through the http package.
    //see issue 488
    c.conn.SetHeader(hdr, val)
}

func (c *httpConn) WriteString(content string) {
    buf := bytes.NewBufferString(content)
    c.conn.Write(buf.Bytes())
}

func (c *httpConn) Write(content []byte) (n int, err os.Error) {
    return c.conn.Write(content)
}

func (c *httpConn) Close() {
    rwc, buf, _ := c.conn.Hijack()
    if buf != nil {
        buf.Flush()
    }

    if rwc != nil {
        rwc.Close()
    }
}

func httpHandler(c *http.Conn, req *http.Request) {
    conn := httpConn{c}

    wreq := newRequest(req)

    routeHandler(wreq, &conn)
}

func routeHandler(req *Request, c conn) {
    requestPath := req.URL.Path

    //log the request
    if len(req.URL.RawQuery) == 0 {
        log.Stdout(requestPath)
    } else {
        log.Stdout(requestPath + "?" + req.URL.RawQuery)
    }

    //parse the form data (if it exists)
    perr := req.ParseParams()
    if perr != nil {
        log.Stderrf("Failed to parse form data %q", perr.String())
    }

    //check the cookies for a session id
    perr = req.ParseCookies()
    if perr != nil {
        log.Stderrf("Failed to parse cookies %q", perr.String())
    }

    s := newSession()

    for k, v := range (req.Cookies) {
        if k == sessionKey {
            if sess, ok := sessionMap[v]; ok {
                s = sess
            }
        }
    }

    ctx := Context{req, &c, s, false}

    //try to serve a static file
    staticFile := path.Join(staticDir, requestPath)
    if fileExists(staticFile) {
        serveFile(&ctx, staticFile)
        return
    }

    //set default encoding
    ctx.SetHeader("Content-Type", "text/html; charset=utf-8", true)
    ctx.SetHeader("Server", "web.go", true)

    for cr, route := range routes {
        if req.Method != route.method {
            continue
        }

        if !cr.MatchString(requestPath) {
            continue
        }
        match := cr.MatchStrings(requestPath)

        if len(match[0]) != len(requestPath) {
            continue
        }

        var args vector.Vector

        handlerType := route.handler.Type().(*reflect.FuncType)

        //check if the first arg in the handler is a context type
        if handlerType.NumIn() > 0 {
            if a0, ok := handlerType.In(0).(*reflect.PtrType); ok {
                typ := a0.Elem()
                if typ == contextType {
                    args.Push(reflect.NewValue(&ctx))
                }
            }
        }

        for _, arg := range match[1:] {
            args.Push(reflect.NewValue(arg))
        }

        if args.Len() != handlerType.NumIn() {
            log.Stderrf("Incorrect number of arguments for %s\n", requestPath)
            ctx.Abort(500, "Server Error")
            return
        }

        valArgs := make([]reflect.Value, args.Len())
        for i := 0; i < args.Len(); i++ {
            valArgs[i] = args.At(i).(reflect.Value)
        }

        ret := route.handler.Call(valArgs)

        if len(ret) == 0 {
            return
        }

        sval, ok := ret[0].(*reflect.StringValue)

        if ok && !ctx.responseStarted {
            //check if session data is stored
            if len(s.Data) > 0 {
                s.save()
                //set the session for half an hour
                ctx.SetCookie(sessionKey, s.Id, 1800)
            }

            ctx.StartResponse(200)
            ctx.WriteString(sval.Get())
        }

        return
    }

    ctx.Abort(404, "Page not found")
}

//runs the web application and serves http requests
func Run(addr string) {
    http.Handle("/", http.HandlerFunc(httpHandler))

    log.Stdoutf("web.go serving %s", addr)
    err := http.ListenAndServe(addr, nil)
    if err != nil {
        log.Exit("ListenAndServe:", err)
    }
}

//runs the web application and serves scgi requests
func RunScgi(addr string) {
    log.Stdoutf("web.go serving scgi %s", addr)
    listenAndServeScgi(addr)
}

//runs the web application by serving fastcgi requests
func RunFcgi(addr string) {
    log.Stdoutf("web.go serving fcgi %s", addr)
    listenAndServeFcgi(addr)
}

//Adds a handler for the 'GET' http method.
func Get(route string, handler interface{}) { addRoute(route, "GET", handler) }

//Adds a handler for the 'POST' http method.
func Post(route string, handler interface{}) { addRoute(route, "POST", handler) }

//Adds a handler for the 'PUT' http method.
func Put(route string, handler interface{}) { addRoute(route, "PUT", handler) }

//Adds a handler for the 'DELETE' http method.
func Delete(route string, handler interface{}) {
    addRoute(route, "DELETE", handler)
}

func dirExists(dir string) bool {
    d, e := os.Stat(dir)
    switch {
    case e != nil:
        return false
    case !d.IsDirectory():
        return false
    }

    return true
}

func fileExists(dir string) bool {
    d, e := os.Stat(dir)
    switch {
    case e != nil:
        return false
    case !d.IsRegular():
        return false
    }

    return true
}

type dirError string

func (path dirError) String() string { return "Failed to set directory " + string(path) }

func getCwd() string { return os.Getenv("PWD") }

//changes the location of the static directory. by default, it's under the 'static' folder
//of the directory containing the web application
func SetStaticDir(dir string) os.Error {
    cwd := getCwd()
    sd := path.Join(cwd, dir)
    if !dirExists(sd) {
        return dirError(sd)

    }
    staticDir = sd

    return nil
}

func Urlencode ( data map[string]string ) string {
        var buf bytes.Buffer;
        for k,v := range ( data ) {
                buf.WriteString ( http.URLEscape(k) )
                buf.WriteByte('=' )
                buf.WriteString ( http.URLEscape(v) )
                buf.WriteByte('&' )
        }
        s := buf.String()
        return s[0:len(s) - 1]
}

//copied from go's http package, because it's not public
var statusText = map[int]string{
    http.StatusContinue: "Continue",
    http.StatusSwitchingProtocols: "Switching Protocols",

    http.StatusOK: "OK",
    http.StatusCreated: "Created",
    http.StatusAccepted: "Accepted",
    http.StatusNonAuthoritativeInfo: "Non-Authoritative Information",
    http.StatusNoContent: "No Content",
    http.StatusResetContent: "Reset Content",
    http.StatusPartialContent: "Partial Content",

    http.StatusMultipleChoices: "Multiple Choices",
    http.StatusMovedPermanently: "Moved Permanently",
    http.StatusFound: "Found",
    http.StatusSeeOther: "See Other",
    http.StatusNotModified: "Not Modified",
    http.StatusUseProxy: "Use Proxy",
    http.StatusTemporaryRedirect: "Temporary Redirect",

    http.StatusBadRequest: "Bad Request",
    http.StatusUnauthorized: "Unauthorized",
    http.StatusPaymentRequired: "Payment Required",
    http.StatusForbidden: "Forbidden",
    http.StatusNotFound: "Not Found",
    http.StatusMethodNotAllowed: "Method Not Allowed",
    http.StatusNotAcceptable: "Not Acceptable",
    http.StatusProxyAuthRequired: "Proxy Authentication Required",
    http.StatusRequestTimeout: "Request Timeout",
    http.StatusConflict: "Conflict",
    http.StatusGone: "Gone",
    http.StatusLengthRequired: "Length Required",
    http.StatusPreconditionFailed: "Precondition Failed",
    http.StatusRequestEntityTooLarge: "Request Entity Too Large",
    http.StatusRequestURITooLong: "Request URI Too Long",
    http.StatusUnsupportedMediaType: "Unsupported Media Type",
    http.StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
    http.StatusExpectationFailed: "Expectation Failed",

    http.StatusInternalServerError: "Internal Server Error",
    http.StatusNotImplemented: "Not Implemented",
    http.StatusBadGateway: "Bad Gateway",
    http.StatusServiceUnavailable: "Service Unavailable",
    http.StatusGatewayTimeout: "Gateway Timeout",
    http.StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
//
// This file originated from: http://opensource.conformal.com/
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

// This file includes wrapers for symbols included since GTK 3.8, and
// and should not be included in a build intended to target any older GTK
// versions.  To target an older build, such as 3.8, use
// 'go build -tags gtk_3_8'.  Otherwise, if no build tags are used, GTK 3.18
// is assumed and this file is built.
// +build !gtk_3_6

package gtk

// #include <gtk/gtk.h>
import "C"

/*
 * Constants
 */

const (
	STATE_FLAG_DIR_LTR StateFlags = C.GTK_STATE_FLAG_DIR_LTR
	STATE_FLAG_DIR_RTL StateFlags = C.GTK_STATE_FLAG_DIR_RTL
)
<commit_msg>Added GtkTickCallback<commit_after>// Copyright (c) 2013-2014 Conformal Systems <info@conformal.com>
//
// This file originated from: http://opensource.conformal.com/
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

// This file includes wrapers for symbols included since GTK 3.8, and
// and should not be included in a build intended to target any older GTK
// versions.  To target an older build, such as 3.8, use
// 'go build -tags gtk_3_8'.  Otherwise, if no build tags are used, GTK 3.18
// is assumed and this file is built.
// +build !gtk_3_6

package gtk

// #include <gtk/gtk.h>
import "C"

/*
 * Constants
 */

const (
	STATE_FLAG_DIR_LTR StateFlags = C.GTK_STATE_FLAG_DIR_LTR
	STATE_FLAG_DIR_RTL StateFlags = C.GTK_STATE_FLAG_DIR_RTL
)

/*
 * GtkTickCallback
 */

type TickCallback func(widget *Widget, frameClock *gdk.FrameClock, userData uintptr) bool
// type ListBoxFilterFunc func(row *ListBoxRow, userData uintptr) bool

type tickCallbackData struct {
	fn       TickCallback
	userData uintptr
}

var (
	tickCallbackRegistry = struct {
		sync.RWMutex
		next int
		m    map[int]tickCallbackData
	}{
		next: 1,
		m:    make(map[int]tickCallbackData),
	}
)
<|endoftext|>


<commit_before>package decoders

import (
	"encoding/gob"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
)

type decoderMap map[string]DecoderGenerator

var defaultDecoders = decoderMap{
	".gob":  func(r io.Reader) Decoder { return gob.NewDecoder(r) },
	".json": func(r io.Reader) Decoder { return json.NewDecoder(r) },
}

func registerDecoder(extension string, decoderGenerator DecoderGenerator) {
	defaultDecoders[extension] = decoderGenerator
}

func (decoders decoderMap) decodeFile(filename string,
	value interface{}) error {
	ext := filepath.Ext(filename)
	if ext == "" {
		return fmt.Errorf("no extension for file: %s", filename)
	}
	decoderGenerator, ok := decoders[filepath.Ext(filename)]
	if !ok {
		return fmt.Errorf("no decoder for .%s extension", ext)
	}
	if file, err := os.Open(filename); err != nil {
		return err
	} else {
		defer file.Close()
		return decoderGenerator(file).Decode(value)
	}
}

func (decoders decoderMap) findAndDecodeFile(basename string,
	value interface{}) error {
	for ext, decoderGenerator := range decoders {
		filename := basename + ext
		if file, err := os.Open(filename); err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return err
		} else {
			defer file.Close()
			return decoderGenerator(file).Decode(value)
		}
	}
	return fmt.Errorf("no matching extension for base file: %s", basename)
}
<commit_msg>Improve error results for lib/repowatch.FindAndDecodeFile() function.<commit_after>package decoders

import (
	"encoding/gob"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
)

type decoderMap map[string]DecoderGenerator

var defaultDecoders = decoderMap{
	".gob":  func(r io.Reader) Decoder { return gob.NewDecoder(r) },
	".json": func(r io.Reader) Decoder { return json.NewDecoder(r) },
}

func registerDecoder(extension string, decoderGenerator DecoderGenerator) {
	defaultDecoders[extension] = decoderGenerator
}

func (decoders decoderMap) decodeFile(filename string,
	value interface{}) error {
	ext := filepath.Ext(filename)
	if ext == "" {
		return fmt.Errorf("no extension for file: %s", filename)
	}
	decoderGenerator, ok := decoders[filepath.Ext(filename)]
	if !ok {
		return fmt.Errorf("no decoder for .%s extension", ext)
	}
	if file, err := os.Open(filename); err != nil {
		return err
	} else {
		defer file.Close()
		return decoderGenerator(file).Decode(value)
	}
}

func (decoders decoderMap) findAndDecodeFile(basename string,
	value interface{}) error {
	for ext, decoderGenerator := range decoders {
		filename := basename + ext
		if file, err := os.Open(filename); err != nil {
			if os.IsNotExist(err) {
				continue
			}
			return err
		} else {
			defer file.Close()
			if err := decoderGenerator(file).Decode(value); err != nil {
				return fmt.Errorf("%s: %s", filename, err)
			}
			return nil
		}
	}
	return os.ErrNotExist
}
<|endoftext|>


<commit_before>package load

import (
	"bytes"
	"io/ioutil"
	"log"
	"shh/mm"
	"time"
)

const (
  Name string = "load"
)

func Poll(now time.Time, measurements chan *mm.Measurement) {
	data, err := ioutil.ReadFile("/proc/loadavg")
	if err != nil {
		log.Fatal(err)
	}
	fields := bytes.Fields(data)
	measurements <- &mm.Measurement{now, "load.1m", fields[0]}
	measurements <- &mm.Measurement{now, "load.5m", fields[1]}
	measurements <- &mm.Measurement{now, "load.15m", fields[2]}
	entities := bytes.Split(fields[3], []byte("/"))
	measurements <- &mm.Measurement{now, "scheduling.entities.executing", entities[0]}
	measurements <- &mm.Measurement{now, "scheduling.entities.total", entities[1]}
	measurements <- &mm.Measurement{now, "pid.last", fields[4]}
	return
}
<commit_msg>go fmt<commit_after>package load

import (
	"bytes"
	"io/ioutil"
	"log"
	"shh/mm"
	"time"
)

const (
	Name string = "load"
)

func Poll(now time.Time, measurements chan *mm.Measurement) {
	data, err := ioutil.ReadFile("/proc/loadavg")
	if err != nil {
		log.Fatal(err)
	}
	fields := bytes.Fields(data)
	measurements <- &mm.Measurement{now, "load.1m", fields[0]}
	measurements <- &mm.Measurement{now, "load.5m", fields[1]}
	measurements <- &mm.Measurement{now, "load.15m", fields[2]}
	entities := bytes.Split(fields[3], []byte("/"))
	measurements <- &mm.Measurement{now, "scheduling.entities.executing", entities[0]}
	measurements <- &mm.Measurement{now, "scheduling.entities.total", entities[1]}
	measurements <- &mm.Measurement{now, "pid.last", fields[4]}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"strconv"

	"github.com/beatgammit/turnpike"
)

const (
	POLONIEX_WEBSOCKET_ADDRESS  = "wss://api.poloniex.com"
	POLONIEX_WEBSOCKET_REALM    = "realm1"
	POLONIEX_WEBSOCKET_TICKER   = "ticker"
	POLONIEX_WEBSOCKET_TROLLBOX = "trollbox"
)

type PoloniexWebsocketTicker struct {
	CurrencyPair  string
	Last          float64
	LowestAsk     float64
	HighestBid    float64
	PercentChange float64
	BaseVolume    float64
	QuoteVolume   float64
	IsFrozen      bool
	High          float64
	Low           float64
}

func PoloniexOnTicker(args []interface{}, kwargs map[string]interface{}) {
	ticker := PoloniexWebsocketTicker{}
	ticker.CurrencyPair = args[0].(string)
	ticker.Last, _ = strconv.ParseFloat(args[1].(string), 64)
	ticker.LowestAsk, _ = strconv.ParseFloat(args[2].(string), 64)
	ticker.HighestBid, _ = strconv.ParseFloat(args[3].(string), 64)
	ticker.PercentChange, _ = strconv.ParseFloat(args[4].(string), 64)
	ticker.BaseVolume, _ = strconv.ParseFloat(args[5].(string), 64)
	ticker.QuoteVolume, _ = strconv.ParseFloat(args[6].(string), 64)

	if args[7].(float64) != 0 {
		ticker.IsFrozen = true
	} else {
		ticker.IsFrozen = false
	}

	ticker.High, _ = strconv.ParseFloat(args[8].(string), 64)
	ticker.Low, _ = strconv.ParseFloat(args[9].(string), 64)
}

type PoloniexWebsocketTrollboxMessage struct {
	MessageNumber float64
	Username      string
	Message       string
	Reputation    float64
}

func PoloniexOnTrollbox(args []interface{}, kwargs map[string]interface{}) {
	message := PoloniexWebsocketTrollboxMessage{}
	message.MessageNumber, _ = args[1].(float64)
	message.Username = args[2].(string)
	message.Message = args[3].(string)
	message.Reputation = args[4].(float64)
}

func PoloniexOnDepthOrTrade(args []interface{}, kwargs map[string]interface{}) {
	for x := range args {
		data := args[x].(map[string]interface{})
		msgData := data["data"].(map[string]interface{})
		msgType := data["type"].(string)

		switch msgType {
		case "orderBookModify":
			{
				type PoloniexWebsocketOrderbookModify struct {
					Type   string
					Rate   float64
					Amount float64
				}

				orderModify := PoloniexWebsocketOrderbookModify{}
				orderModify.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderModify.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				orderModify.Amount, _ = strconv.ParseFloat(amountStr, 64)
			}
		case "orderBookRemove":
			{
				type PoloniexWebsocketOrderbookRemove struct {
					Type string
					Rate float64
				}

				orderRemoval := PoloniexWebsocketOrderbookRemove{}
				orderRemoval.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderRemoval.Rate, _ = strconv.ParseFloat(rateStr, 64)
			}
		case "newTrade":
			{
				type PoloniexWebsocketNewTrade struct {
					Type    string
					TradeID int64
					Rate    float64
					Amount  float64
					Date    string
					Total   float64
				}

				trade := PoloniexWebsocketNewTrade{}
				trade.Type = msgData["type"].(string)

				tradeIDstr := msgData["tradeID"].(string)
				trade.TradeID, _ = strconv.ParseInt(tradeIDstr, 10, 64)

				rateStr := msgData["rate"].(string)
				trade.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				trade.Amount, _ = strconv.ParseFloat(amountStr, 64)

				totalStr := msgData["total"].(string)
				trade.Rate, _ = strconv.ParseFloat(totalStr, 64)

				trade.Date = msgData["date"].(string)
			}
		}
	}
}

func (p *Poloniex) WebsocketClient() {
	for p.Enabled && p.Websocket {
		c, err := turnpike.NewWebsocketClient(turnpike.JSON, POLONIEX_WEBSOCKET_ADDRESS, nil)
		if err != nil {
			log.Printf("%s Unable to connect to Websocket. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Connected to Websocket.\n", p.GetName())
		}

		_, err = c.JoinRealm(POLONIEX_WEBSOCKET_REALM, nil)
		if err != nil {
			log.Printf("%s Unable to join realm. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Joined Websocket realm.\n", p.GetName())
		}

		c.ReceiveDone = make(chan bool)

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TICKER, PoloniexOnTicker); err != nil {
			log.Printf("%s Error subscribing to ticker channel: %s\n", p.GetName(), err)
		}

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TROLLBOX, PoloniexOnTrollbox); err != nil {
			log.Printf("%s Error subscribing to trollbox channel: %s\n", p.GetName(), err)
		}

		for x := range p.EnabledPairs {
			currency := p.EnabledPairs[x]
			if err := c.Subscribe(currency, PoloniexOnDepthOrTrade); err != nil {
				log.Printf("%s Error subscribing to %s channel: %s\n", p.GetName(), currency, err)
			}
		}

		if p.Verbose {
			log.Printf("%s Subscribed to websocket channels.\n", p.GetName())
		}

		<-c.ReceiveDone
		log.Printf("%s Websocket client disconnected.\n", p.GetName())
	}
}
<commit_msg>Fix Poloniex Trollbox response<commit_after>package main

import (
	"log"
	"strconv"

	"github.com/beatgammit/turnpike"
)

const (
	POLONIEX_WEBSOCKET_ADDRESS  = "wss://api.poloniex.com"
	POLONIEX_WEBSOCKET_REALM    = "realm1"
	POLONIEX_WEBSOCKET_TICKER   = "ticker"
	POLONIEX_WEBSOCKET_TROLLBOX = "trollbox"
)

type PoloniexWebsocketTicker struct {
	CurrencyPair  string
	Last          float64
	LowestAsk     float64
	HighestBid    float64
	PercentChange float64
	BaseVolume    float64
	QuoteVolume   float64
	IsFrozen      bool
	High          float64
	Low           float64
}

func PoloniexOnTicker(args []interface{}, kwargs map[string]interface{}) {
	ticker := PoloniexWebsocketTicker{}
	ticker.CurrencyPair = args[0].(string)
	ticker.Last, _ = strconv.ParseFloat(args[1].(string), 64)
	ticker.LowestAsk, _ = strconv.ParseFloat(args[2].(string), 64)
	ticker.HighestBid, _ = strconv.ParseFloat(args[3].(string), 64)
	ticker.PercentChange, _ = strconv.ParseFloat(args[4].(string), 64)
	ticker.BaseVolume, _ = strconv.ParseFloat(args[5].(string), 64)
	ticker.QuoteVolume, _ = strconv.ParseFloat(args[6].(string), 64)

	if args[7].(float64) != 0 {
		ticker.IsFrozen = true
	} else {
		ticker.IsFrozen = false
	}

	ticker.High, _ = strconv.ParseFloat(args[8].(string), 64)
	ticker.Low, _ = strconv.ParseFloat(args[9].(string), 64)
}

type PoloniexWebsocketTrollboxMessage struct {
	MessageNumber float64
	Username      string
	Message       string
	Reputation    float64
}

func PoloniexOnTrollbox(args []interface{}, kwargs map[string]interface{}) {
	message := PoloniexWebsocketTrollboxMessage{}
	message.MessageNumber, _ = args[1].(float64)
	message.Username = args[2].(string)
	message.Message = args[3].(string)
	if len(args) == 5 {
		message.Reputation = args[4].(float64)
	}
}

func PoloniexOnDepthOrTrade(args []interface{}, kwargs map[string]interface{}) {
	for x := range args {
		data := args[x].(map[string]interface{})
		msgData := data["data"].(map[string]interface{})
		msgType := data["type"].(string)

		switch msgType {
		case "orderBookModify":
			{
				type PoloniexWebsocketOrderbookModify struct {
					Type   string
					Rate   float64
					Amount float64
				}

				orderModify := PoloniexWebsocketOrderbookModify{}
				orderModify.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderModify.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				orderModify.Amount, _ = strconv.ParseFloat(amountStr, 64)
			}
		case "orderBookRemove":
			{
				type PoloniexWebsocketOrderbookRemove struct {
					Type string
					Rate float64
				}

				orderRemoval := PoloniexWebsocketOrderbookRemove{}
				orderRemoval.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderRemoval.Rate, _ = strconv.ParseFloat(rateStr, 64)
			}
		case "newTrade":
			{
				type PoloniexWebsocketNewTrade struct {
					Type    string
					TradeID int64
					Rate    float64
					Amount  float64
					Date    string
					Total   float64
				}

				trade := PoloniexWebsocketNewTrade{}
				trade.Type = msgData["type"].(string)

				tradeIDstr := msgData["tradeID"].(string)
				trade.TradeID, _ = strconv.ParseInt(tradeIDstr, 10, 64)

				rateStr := msgData["rate"].(string)
				trade.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				trade.Amount, _ = strconv.ParseFloat(amountStr, 64)

				totalStr := msgData["total"].(string)
				trade.Rate, _ = strconv.ParseFloat(totalStr, 64)

				trade.Date = msgData["date"].(string)
			}
		}
	}
}

func (p *Poloniex) WebsocketClient() {
	for p.Enabled && p.Websocket {
		c, err := turnpike.NewWebsocketClient(turnpike.JSON, POLONIEX_WEBSOCKET_ADDRESS, nil)
		if err != nil {
			log.Printf("%s Unable to connect to Websocket. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Connected to Websocket.\n", p.GetName())
		}

		_, err = c.JoinRealm(POLONIEX_WEBSOCKET_REALM, nil)
		if err != nil {
			log.Printf("%s Unable to join realm. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Joined Websocket realm.\n", p.GetName())
		}

		c.ReceiveDone = make(chan bool)

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TICKER, PoloniexOnTicker); err != nil {
			log.Printf("%s Error subscribing to ticker channel: %s\n", p.GetName(), err)
		}

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TROLLBOX, PoloniexOnTrollbox); err != nil {
			log.Printf("%s Error subscribing to trollbox channel: %s\n", p.GetName(), err)
		}

		for x := range p.EnabledPairs {
			currency := p.EnabledPairs[x]
			if err := c.Subscribe(currency, PoloniexOnDepthOrTrade); err != nil {
				log.Printf("%s Error subscribing to %s channel: %s\n", p.GetName(), currency, err)
			}
		}

		if p.Verbose {
			log.Printf("%s Subscribed to websocket channels.\n", p.GetName())
		}

		<-c.ReceiveDone
		log.Printf("%s Websocket client disconnected.\n", p.GetName())
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015, RadiantBlue Technologies, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package handlers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"time"

	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/session"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
	"github.com/venicegeo/pdal-microservice/objects"
)

// var validPath = regexp.MustCompile("^/(info|pipeline)/([a-zA-Z0-9]+)$")
var validPath = regexp.MustCompile("^/(pdal)$")

// UpdateJobManager handles PDAL status updates.
func UpdateJobManager(w http.ResponseWriter, t objects.StatusType) {
	log.Println("Setting job status as a", t.String())
	var res objects.JobManagerUpdate
	res.Status = t.String()
	// update the JobManager
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(res); err != nil {
		log.Fatal(err)
	}
}

// PdalHandler handles PDAL jobs.
func PdalHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	log.Println("Received request")
	var res objects.JobOutput
	res.StartedAt = time.Now()

	// Check that we have a valid path. Is this the correct place to do this?
	log.Println("Checking to see if", r.URL.Path, "is a valid endpoint")
	m := validPath.FindStringSubmatch(r.URL.Path)
	if m == nil {
		http.NotFound(w, r)
		return
	}

	log.Println("Attempt to read the JSON body")
	// Parse the incoming JSON body, and unmarshal as events.NewData struct.
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		UpdateJobManager(w, objects.Error)
		log.Fatal(err)
	}

	log.Println("Attempt to unmarshal the JSON")
	var msg objects.JobInput
	if err := json.Unmarshal(b, &msg); err != nil {
		UpdateJobManager(w, objects.Fail)
		log.Fatal(err)
	}
	if msg.Function == nil {
		UpdateJobManager(w, objects.Fail)
		log.Println("Must provide a function")
		return
	}

	res.Input = msg
	res.Status = objects.Running.String()
	// we have successfully parsed the input JSON, update JobManager that we are now running

	file, err := os.Create("download_file.laz")
	if err != nil {
		// errors here should also be JSON-encoded as below
		http.Error(w, err.Error(), http.StatusInternalServerError)
		res.Status = objects.Error.String()
		// update the JobManager
		return
	}
	defer file.Close()

	downloader := s3manager.NewDownloader(session.New(&aws.Config{Region: aws.String("us-east-1")}))
	numBytes, err := downloader.Download(file,
		&s3.GetObjectInput{
			Bucket: aws.String(msg.Source.Bucket),
			Key:    aws.String(msg.Source.Key),
		})
	if err != nil {
		// errors here should also be JSON-encoded as below
		if awsErr, ok := err.(awserr.Error); ok {
			log.Println("Error:", awsErr.Code(), awsErr.Message())
		} else {
			fmt.Println(err.Error())
		}
		return
	}
	log.Println("Downloaded", numBytes, "bytes")

	out, _ := exec.Command("pdal", *msg.Function, file.Name()).CombinedOutput()

	// Trim whitespace
	buffer := new(bytes.Buffer)
	if err := json.Compact(buffer, out); err != nil {
		fmt.Println(err)
	}

	if err = json.Unmarshal(buffer.Bytes(), &res.Response); err != nil {
		log.Fatal(err)
	}
	res.Status = objects.Success.String()
	res.FinishedAt = time.Now()

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(res); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Any change of status should be reported to the job manager<commit_after>/*
Copyright 2015, RadiantBlue Technologies, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package handlers

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"time"

	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/aws/session"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/s3/s3manager"
	"github.com/venicegeo/pdal-microservice/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
	"github.com/venicegeo/pdal-microservice/objects"
)

// var validPath = regexp.MustCompile("^/(info|pipeline)/([a-zA-Z0-9]+)$")
var validPath = regexp.MustCompile("^/(pdal)$")

// UpdateJobManager handles PDAL status updates.
func UpdateJobManager(w http.ResponseWriter, t objects.StatusType) {
	log.Println("Setting job status as a", t.String())
	var res objects.JobManagerUpdate
	res.Status = t.String()
	// update the JobManager
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(res); err != nil {
		log.Fatal(err)
	}
}

// PdalHandler handles PDAL jobs.
func PdalHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	log.Println("Received request")
	var res objects.JobOutput
	res.StartedAt = time.Now()

	// Check that we have a valid path. Is this the correct place to do this?
	log.Println("Checking to see if", r.URL.Path, "is a valid endpoint")
	m := validPath.FindStringSubmatch(r.URL.Path)
	if m == nil {
		http.NotFound(w, r)
		return
	}

	log.Println("Attempt to read the JSON body")
	// Parse the incoming JSON body, and unmarshal as events.NewData struct.
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		UpdateJobManager(w, objects.Error)
		log.Fatal(err)
	}

	log.Println("Attempt to unmarshal the JSON")
	var msg objects.JobInput
	if err := json.Unmarshal(b, &msg); err != nil {
		UpdateJobManager(w, objects.Fail)
		log.Fatal(err)
	}
	if msg.Function == nil {
		UpdateJobManager(w, objects.Fail)
		log.Println("Must provide a function")
		return
	}

	res.Input = msg
	UpdateJobManager(w, objects.Running)
	// we have successfully parsed the input JSON, update JobManager that we are now running

	file, err := os.Create("download_file.laz")
	if err != nil {
		// errors here should also be JSON-encoded as below
		http.Error(w, err.Error(), http.StatusInternalServerError)
		res.Status = objects.Error.String()
		// update the JobManager
		return
	}
	defer file.Close()

	downloader := s3manager.NewDownloader(session.New(&aws.Config{Region: aws.String("us-east-1")}))
	numBytes, err := downloader.Download(file,
		&s3.GetObjectInput{
			Bucket: aws.String(msg.Source.Bucket),
			Key:    aws.String(msg.Source.Key),
		})
	if err != nil {
		// errors here should also be JSON-encoded as below
		if awsErr, ok := err.(awserr.Error); ok {
			log.Println("Error:", awsErr.Code(), awsErr.Message())
		} else {
			fmt.Println(err.Error())
		}
		return
	}
	log.Println("Downloaded", numBytes, "bytes")

	out, _ := exec.Command("pdal", *msg.Function, file.Name()).CombinedOutput()

	// Trim whitespace
	buffer := new(bytes.Buffer)
	if err := json.Compact(buffer, out); err != nil {
		fmt.Println(err)
	}

	if err = json.Unmarshal(buffer.Bytes(), &res.Response); err != nil {
		log.Fatal(err)
	}
	res.Status = objects.Success.String()
	res.FinishedAt = time.Now()

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(res); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package handlers

import (
    "encoding/json"
    "jimmify-server/db"
    "net/http"
    "log"
)

//Question : get question by query id
func Question(w http.ResponseWriter, r *http.Request) {
    var q db.Query
    response :=make(map[string]interface{})

    //read json
    err := json.NewDecoder(r.Body).Decode(&q)
    if err != nil {
        ReturnStatusBadRequest(w, "Failed to decode query json")
        return
    }

    //validate data
    err = validateCheck(q)
    if err != nil {
        ReturnStatusBadRequest(w, err.Error())
        return
    }
    log.Println(q.Key)
    //get question
    a, err := db.GetQuestion(q.Key)
    log.Println(a)
    log.Println(err)
    if err != nil {
        //return status false
        w.WriteHeader(http.StatusOK)
        response["status"] = "false"
        json.NewEncoder(w).Encode(response)
        return
    }

    w.WriteHeader(http.StatusOK)
    response["key"] = a.Key
    response["text"] = a.Text
    response["type"] = a.Type
    response["status"] = "true"
    json.NewEncoder(w).Encode(response)
}
<commit_msg>Removing log statements<commit_after>package handlers

import (
    "encoding/json"
    "jimmify-server/db"
    "net/http"
    "log"
)

//Question : get question by query id
func Question(w http.ResponseWriter, r *http.Request) {
    var q db.Query
    response :=make(map[string]interface{})

    //read json
    err := json.NewDecoder(r.Body).Decode(&q)
    if err != nil {
        ReturnStatusBadRequest(w, "Failed to decode query json")
        return
    }

    //validate data
    err = validateCheck(q)
    if err != nil {
        ReturnStatusBadRequest(w, err.Error())
        return
    }
    log.Println(q.Key)
    //get question
    a, err := db.GetQuestion(q.Key)
    if err != nil {
        //return status false
        w.WriteHeader(http.StatusOK)
        response["status"] = "false"
        json.NewEncoder(w).Encode(response)
        return
    }

    w.WriteHeader(http.StatusOK)
    response["key"] = a.Key
    response["text"] = a.Text
    response["type"] = a.Type
    response["status"] = "true"
    json.NewEncoder(w).Encode(response)
}
<|endoftext|>


<commit_before>package httpfile

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"

	"github.com/anacrolix/missinggo"
)

type File struct {
	off    int64
	r      io.ReadCloser
	rOff   int64
	length int64
	url    string
	flags  int
}

func OpenSectionReader(url string, off, n int64) (ret io.ReadCloser, err error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}
	req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+n-1))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode == http.StatusNotFound {
		err = ErrNotFound
		resp.Body.Close()
		return
	}
	if resp.StatusCode != http.StatusPartialContent {
		err = fmt.Errorf("bad response status: %s", resp.Status)
		resp.Body.Close()
		return
	}
	ret = resp.Body
	return
}

func Open(url string, flags int) (ret *File, err error) {
	ret = &File{
		url:   url,
		flags: flags,
	}
	if flags&os.O_CREATE == 0 {
		err = ret.prepareReader()
	}
	return
}

func (me *File) prepareReader() (err error) {
	if me.r != nil && me.off != me.rOff {
		me.r.Close()
		me.r = nil
	}
	if me.r != nil {
		return nil
	}
	if me.flags&missinggo.O_ACCMODE == os.O_WRONLY {
		err = errors.New("read flags missing")
		return
	}
	req, err := http.NewRequest("GET", me.url, nil)
	if err != nil {
		return
	}
	if me.off != 0 {
		req.Header.Set("Range", fmt.Sprintf("bytes=%d-", me.off))
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	switch resp.StatusCode {
	case http.StatusPartialContent:
		cr, ok := missinggo.ParseHTTPBytesContentRange(resp.Header.Get("Content-Range"))
		if !ok || cr.First != me.off {
			err = errors.New("bad response")
			resp.Body.Close()
			return
		}
		me.length = cr.Length
	case http.StatusOK:
		if me.off != 0 {
			err = errors.New("bad response")
			resp.Body.Close()
			return
		}
		if h := resp.Header.Get("Content-Length"); h != "" {
			var cl uint64
			cl, err = strconv.ParseUint(h, 10, 64)
			if err != nil {
				resp.Body.Close()
				return
			}
			me.length = int64(cl)
		}
	case http.StatusNotFound:
		err = ErrNotFound
		resp.Body.Close()
		return
	default:
		err = errors.New(resp.Status)
		resp.Body.Close()
		return
	}
	me.r = resp.Body
	me.rOff = me.off
	return
}

func (me *File) Read(b []byte) (n int, err error) {
	err = me.prepareReader()
	if err != nil {
		return
	}
	n, err = me.r.Read(b)
	me.off += int64(n)
	me.rOff += int64(n)
	return
}

func instanceLength(r *http.Response) (int64, error) {
	switch r.StatusCode {
	case http.StatusOK:
		if h := r.Header.Get("Content-Length"); h != "" {
			return strconv.ParseInt(h, 10, 64)
		} else {
			return -1, nil
		}
	case http.StatusPartialContent:
		cr, ok := missinggo.ParseHTTPBytesContentRange(r.Header.Get("Content-Range"))
		if !ok {
			return -1, errors.New("bad 206 response")
		}
		return cr.Length, nil
	default:
		return -1, errors.New(r.Status)
	}
}

func (me *File) Seek(offset int64, whence int) (ret int64, err error) {
	switch whence {
	case os.SEEK_SET:
		ret = offset
	case os.SEEK_CUR:
		ret = me.off + offset
	case os.SEEK_END:
		if me.length < 0 {
			err = errors.New("length unknown")
			return
		}
		ret = me.length + offset
	default:
		err = fmt.Errorf("unhandled whence: %d", whence)
		return
	}
	me.off = ret
	return
}

func (me *File) Write(b []byte) (n int, err error) {
	if me.flags&(os.O_WRONLY|os.O_RDWR) == 0 || me.flags&os.O_CREATE == 0 {
		err = errors.New("cannot write without write and create flags")
		return
	}
	req, err := http.NewRequest("PATCH", me.url, bytes.NewReader(b))
	if err != nil {
		return
	}
	req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-", me.off))
	req.ContentLength = int64(len(b))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusPartialContent {
		err = errors.New(resp.Status)
		return
	}
	n = len(b)
	me.off += int64(n)
	return
}

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

// Returns the length of the resource in bytes.
func GetLength(url string) (ret int64, err error) {
	resp, err := http.Head(url)
	if err != nil {
		return
	}
	resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		err = ErrNotFound
		return
	}
	return instanceLength(resp)
}

func (me *File) Close() error {
	me.url = ""
	if me.r != nil {
		me.r.Close()
		me.r = nil
	}
	return nil
}

func Delete(urlStr string) (err error) {
	req, err := http.NewRequest("DELETE", urlStr, nil)
	if err != nil {
		return
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		err = ErrNotFound
		return
	}
	if resp.StatusCode != 200 {
		err = fmt.Errorf("response: %s", resp.Status)
	}
	return
}
<commit_msg>httpfile: ErrNotFound now aliases os.ErrNotExist<commit_after>package httpfile

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"

	"github.com/anacrolix/missinggo"
)

type File struct {
	off    int64
	r      io.ReadCloser
	rOff   int64
	length int64
	url    string
	flags  int
}

func OpenSectionReader(url string, off, n int64) (ret io.ReadCloser, err error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}
	req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+n-1))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	if resp.StatusCode == http.StatusNotFound {
		err = ErrNotFound
		resp.Body.Close()
		return
	}
	if resp.StatusCode != http.StatusPartialContent {
		err = fmt.Errorf("bad response status: %s", resp.Status)
		resp.Body.Close()
		return
	}
	ret = resp.Body
	return
}

func Open(url string, flags int) (ret *File, err error) {
	ret = &File{
		url:   url,
		flags: flags,
	}
	if flags&os.O_CREATE == 0 {
		err = ret.prepareReader()
	}
	return
}

func (me *File) prepareReader() (err error) {
	if me.r != nil && me.off != me.rOff {
		me.r.Close()
		me.r = nil
	}
	if me.r != nil {
		return nil
	}
	if me.flags&missinggo.O_ACCMODE == os.O_WRONLY {
		err = errors.New("read flags missing")
		return
	}
	req, err := http.NewRequest("GET", me.url, nil)
	if err != nil {
		return
	}
	if me.off != 0 {
		req.Header.Set("Range", fmt.Sprintf("bytes=%d-", me.off))
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	switch resp.StatusCode {
	case http.StatusPartialContent:
		cr, ok := missinggo.ParseHTTPBytesContentRange(resp.Header.Get("Content-Range"))
		if !ok || cr.First != me.off {
			err = errors.New("bad response")
			resp.Body.Close()
			return
		}
		me.length = cr.Length
	case http.StatusOK:
		if me.off != 0 {
			err = errors.New("bad response")
			resp.Body.Close()
			return
		}
		if h := resp.Header.Get("Content-Length"); h != "" {
			var cl uint64
			cl, err = strconv.ParseUint(h, 10, 64)
			if err != nil {
				resp.Body.Close()
				return
			}
			me.length = int64(cl)
		}
	case http.StatusNotFound:
		err = ErrNotFound
		resp.Body.Close()
		return
	default:
		err = errors.New(resp.Status)
		resp.Body.Close()
		return
	}
	me.r = resp.Body
	me.rOff = me.off
	return
}

func (me *File) Read(b []byte) (n int, err error) {
	err = me.prepareReader()
	if err != nil {
		return
	}
	n, err = me.r.Read(b)
	me.off += int64(n)
	me.rOff += int64(n)
	return
}

func instanceLength(r *http.Response) (int64, error) {
	switch r.StatusCode {
	case http.StatusOK:
		if h := r.Header.Get("Content-Length"); h != "" {
			return strconv.ParseInt(h, 10, 64)
		} else {
			return -1, nil
		}
	case http.StatusPartialContent:
		cr, ok := missinggo.ParseHTTPBytesContentRange(r.Header.Get("Content-Range"))
		if !ok {
			return -1, errors.New("bad 206 response")
		}
		return cr.Length, nil
	default:
		return -1, errors.New(r.Status)
	}
}

func (me *File) Seek(offset int64, whence int) (ret int64, err error) {
	switch whence {
	case os.SEEK_SET:
		ret = offset
	case os.SEEK_CUR:
		ret = me.off + offset
	case os.SEEK_END:
		if me.length < 0 {
			err = errors.New("length unknown")
			return
		}
		ret = me.length + offset
	default:
		err = fmt.Errorf("unhandled whence: %d", whence)
		return
	}
	me.off = ret
	return
}

func (me *File) Write(b []byte) (n int, err error) {
	if me.flags&(os.O_WRONLY|os.O_RDWR) == 0 || me.flags&os.O_CREATE == 0 {
		err = errors.New("cannot write without write and create flags")
		return
	}
	req, err := http.NewRequest("PATCH", me.url, bytes.NewReader(b))
	if err != nil {
		return
	}
	req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-", me.off))
	req.ContentLength = int64(len(b))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	resp.Body.Close()
	if resp.StatusCode != http.StatusPartialContent {
		err = errors.New(resp.Status)
		return
	}
	n = len(b)
	me.off += int64(n)
	return
}

var (
	ErrNotFound = os.ErrNotExist
)

// Returns the length of the resource in bytes.
func GetLength(url string) (ret int64, err error) {
	resp, err := http.Head(url)
	if err != nil {
		return
	}
	resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		err = ErrNotFound
		return
	}
	return instanceLength(resp)
}

func (me *File) Close() error {
	me.url = ""
	if me.r != nil {
		me.r.Close()
		me.r = nil
	}
	return nil
}

func Delete(urlStr string) (err error) {
	req, err := http.NewRequest("DELETE", urlStr, nil)
	if err != nil {
		return
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return
	}
	resp.Body.Close()
	if resp.StatusCode == http.StatusNotFound {
		err = ErrNotFound
		return
	}
	if resp.StatusCode != 200 {
		err = fmt.Errorf("response: %s", resp.Status)
	}
	return
}
<|endoftext|>


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

package httptest

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
)

type Request http.Request
type Response http.Response

// NewRequest wraps http.Request
func NewRequest(method string, uri string, body interface{}, params url.Values) (*Request, error) {
	method = strings.ToUpper(method)

	if body != nil && (method != "POST" && method != "PUT") {
		return nil, fmt.Errorf("%s method does not accept body", method)
	}

	var buf io.Reader

	if body != nil {
		b, ok := body.([]byte)
		if ok {
			buf = bytes.NewBuffer(b)
		} else {
			body, err := toURL(body)

			if err != nil {
				return nil, err
			}

			buf = strings.NewReader(body.Encode())
		}
	}

	req, err := http.NewRequest(method, joinURL(uri, params), buf)

	if method == "POST" || method == "PUT" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}

	rr := Request(*req)
	return &rr, err
}

func (req *Request) Do() (*Response, error) {
	rr, err := http.DefaultClient.Do((*http.Request)(req))

	if err != nil {
		return nil, err
	}

	return (*Response)(rr), nil
}

func (res *Response) ToJSON(i interface{}) error {
	defer res.Body.Close()

	if c := res.Header.Get("Content-Type"); !strings.Contains(c, "application/json") {
		return fmt.Errorf("Unexpected Content-Type, got %s", c)
	}

	reader := bufio.NewReader(res.Body)
	buf, _ := ioutil.ReadAll(reader)
	err := json.Unmarshal(buf, i)
	//fmt.Printf("%s\n", buf)
	//err := json.NewDecoder(res.Body).Decode(v)
	return err
}

type DataErrResponse struct {
	Error map[string]string
}

func (res *Response) ToErr() (*DataErrResponse, error) {
	v := &DataErrResponse{}
	err := res.ToJSON(v)
	return v, err
}

func toURL(query interface{}) (url.Values, error) {
	switch vv := query.(type) {
	case url.Values:
		return query.(url.Values), nil
	case map[string]string:
		val := make(url.Values, len(vv))
		for k, v := range vv {
			val.Add(k, v)
		}
		return val, nil
	default:
		s := reflect.ValueOf(query)
		t := reflect.TypeOf(query)
		val := make(url.Values, s.NumField())

		for i := 0; i < s.NumField(); i++ {
			val.Add(strings.ToLower(t.Field(i).Name), fmt.Sprintf("%v", s.Field(i).Interface()))
		}
		return val, nil
	}
}

func joinURL(endpoint string, args url.Values) string {
	var params string

	if args != nil && len(args) > 0 {
		params = "?" + args.Encode()
	}

	return endpoint + params
}
<commit_msg>correct pkg name<commit_after>// Copyright 2014 Simon Zimmermann. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package httputil

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"reflect"
	"strings"
)

type Request http.Request
type Response http.Response

// NewRequest wraps http.Request
func NewRequest(method string, uri string, body interface{}, params url.Values) (*Request, error) {
	method = strings.ToUpper(method)

	if body != nil && (method != "POST" && method != "PUT") {
		return nil, fmt.Errorf("%s method does not accept body", method)
	}

	var buf io.Reader

	if body != nil {
		b, ok := body.([]byte)
		if ok {
			buf = bytes.NewBuffer(b)
		} else {
			body, err := toURL(body)

			if err != nil {
				return nil, err
			}

			buf = strings.NewReader(body.Encode())
		}
	}

	req, err := http.NewRequest(method, joinURL(uri, params), buf)

	if method == "POST" || method == "PUT" {
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	}

	rr := Request(*req)
	return &rr, err
}

func (req *Request) Do() (*Response, error) {
	rr, err := http.DefaultClient.Do((*http.Request)(req))

	if err != nil {
		return nil, err
	}

	return (*Response)(rr), nil
}

func (res *Response) ToJSON(i interface{}) error {
	defer res.Body.Close()

	if c := res.Header.Get("Content-Type"); !strings.Contains(c, "application/json") {
		return fmt.Errorf("Unexpected Content-Type, got %s", c)
	}

	reader := bufio.NewReader(res.Body)
	buf, _ := ioutil.ReadAll(reader)
	err := json.Unmarshal(buf, i)
	//fmt.Printf("%s\n", buf)
	//err := json.NewDecoder(res.Body).Decode(v)
	return err
}

type DataErrResponse struct {
	Error map[string]string
}

func (res *Response) ToErr() (*DataErrResponse, error) {
	v := &DataErrResponse{}
	err := res.ToJSON(v)
	return v, err
}

func toURL(query interface{}) (url.Values, error) {
	switch vv := query.(type) {
	case url.Values:
		return query.(url.Values), nil
	case map[string]string:
		val := make(url.Values, len(vv))
		for k, v := range vv {
			val.Add(k, v)
		}
		return val, nil
	default:
		s := reflect.ValueOf(query)
		t := reflect.TypeOf(query)
		val := make(url.Values, s.NumField())

		for i := 0; i < s.NumField(); i++ {
			val.Add(strings.ToLower(t.Field(i).Name), fmt.Sprintf("%v", s.Field(i).Interface()))
		}
		return val, nil
	}
}

func joinURL(endpoint string, args url.Values) string {
	var params string

	if args != nil && len(args) > 0 {
		params = "?" + args.Encode()
	}

	return endpoint + params
}
<|endoftext|>


<commit_before>package main

import (
    "io/ioutil"
    "fmt"
    "flag"
    "math/rand"
    "time"
    "strings"
    "hash/fnv"
)

// Retrieves a list of words from a newline seperated file
// Returns an array of single words
func loadWordList(corpusFile string) []string {

  corpus, err := ioutil.ReadFile(corpusFile)
  if err != nil {
      panic(err)
  }
  words := strings.Split(string(corpus), "\n")

  return words
}

func randomWord(wordList []string, r *rand.Rand) string {

  q := wordList[r.Intn(len(wordList))]

  return q
}

// Uses magic to create a hash of a string
func hash(s string) int64 {

  h := fnv.New64a()
  h.Write([]byte(s))
  return int64(h.Sum64())
}

// Creates the randomization source
func randSource(s string) rand.Source {

  if (s != "") {
  // if there's a seed flag, hash it, then use it
    seed := hash(s)
    return rand.NewSource(seed)
  } else {
  // if there's no seed flag just use something generic
    return rand.NewSource(time.Now().Unix())
  }
}

func main() {

  separatorPtr := flag.String("separator", "-", "character(s) to place between words")
  pwdLengthPtr := flag.Int("pwdLength", 4, "number of words in password")
  corpusPtr := flag.String("corpus", "corpus/corpus.txt", "newline sepearted file of words to use")
  seedPtr := flag.String("seed", "", "seed for random generation, should allow repeat password generation")

  flag.Parse()

  var words []string
  wordList := loadWordList(*corpusPtr)

  var s rand.Source = randSource(*seedPtr)
  r := rand.New(s) // initialize local pseudorandom generator

  for i := 0; i < *pwdLengthPtr; i++ {
    words = append(words, randomWord(wordList, r))
  }

  password := strings.Join(words, *separatorPtr)
  fmt.Println(password)

}<commit_msg>Added capitialization option<commit_after>package main

import (
	"flag"
	"fmt"
	"hash/fnv"
	"io/ioutil"
	"math/rand"
	"strings"
	"time"
)

// Retrieves a list of words from a newline seperated file
// Returns an array of single words
func loadWordList(corpusFile string) []string {

	corpus, err := ioutil.ReadFile(corpusFile)
	if err != nil {
		panic(err)
	}
	words := strings.Split(string(corpus), "\n")

	return words
}

func randomWord(wordList []string, r *rand.Rand) string {

	q := wordList[r.Intn(len(wordList))]

	return q
}

// Uses magic to create a hash of a string
func hash(s string) int64 {

	h := fnv.New64a()
	h.Write([]byte(s))
	return int64(h.Sum64())
}

// Creates the randomization source
func randSource(s string) rand.Source {

	if s != "" {
		// if there's a seed flag, hash it, then use it
		seed := hash(s)
		return rand.NewSource(seed)
	} else {
		// if there's no seed flag just use something generic
		return rand.NewSource(time.Now().Unix())
	}
}

func capitialize(word string, mode string, position int) string {
	mode = strings.ToLower(mode)
	switch mode {
	case "none":
		return word
	case "camelcase":
		return strings.Title(word)
	case "alternating":
		if position%2 == 1 {
			return strings.ToUpper(word)
		} else {
			return word
		}
	default:
		return word
	}
}

func main() {

	separatorPtr := flag.String("separator", "-", "character(s) to place between words")
	pwdLengthPtr := flag.Int("pwdLength", 4, "number of words in password")
	corpusPtr := flag.String("corpus", "corpus/corpus.txt", "newline sepearted file of words to use")
	seedPtr := flag.String("seed", "", "seed for random generation, should allow repeat password generation")
	capitializationPtr := flag.String("capitalization", "none", "Capitialization pattern. Valid values are none, camelcase, and alternating. Anything else defaults to none")

	flag.Parse()

	var words []string
	wordList := loadWordList(*corpusPtr)

	var s rand.Source = randSource(*seedPtr)
	r := rand.New(s) // initialize local pseudorandom generator

	for i := 0; i < *pwdLengthPtr; i++ {
		var word string
		word = capitialize(randomWord(wordList, r), *capitializationPtr, i)

		words = append(words, word)
	}

	password := strings.Join(words, *separatorPtr)
	fmt.Println(password)

}
<|endoftext|>


<commit_before>package modules

import (
	"fmt"
	"github.com/davidscholberg/go-i3barjson"
	"net"
	"strings"
)

// Interface represents the configuration for the network interface block.
type Interface struct {
	BlockConfigBase `yaml:",inline"`
	IfaceName       string `yaml:"interface_name"`
	IPv4            string
	IPv4CIDR        string
	IPv6            string
	IPv6CIDR        string
}

// UpdateBlock updates the network interface block.
func (c Interface) UpdateBlock(b *i3barjson.Block) {
	b.Color = c.Color
	fullTextFmt := fmt.Sprintf("%s%%s", c.Label)

	iface, err := net.InterfaceByName(c.IfaceName)
	if err != nil {
		b.Urgent = true
		b.FullText = fmt.Sprintf(fullTextFmt, err.Error())
		return
	}

	if iface.Flags == net.FlagUp {
		b.Urgent = false
	} else {
		b.Urgent = true
	}

	addrs, err := iface.Addrs()
	if err != nil {
		b.Urgent = true
		b.FullText = fmt.Sprintf(fullTextFmt, err.Error())
		return
	}

	for _, addr := range addrs {
		ip, _, err := net.ParseCIDR(addr.String())
		if err != nil {
			b.Urgent = true
			b.FullText = fmt.Sprintf(fullTextFmt, err.Error())
			return
		}

		// Checking for address family
		if ip.To4() != nil {
			c.Label = strings.Replace(c.Label, "\u003cipv4\u003e", ip.String(), -1)
			c.Label = strings.Replace(c.Label, "\u003ccidr4\u003e", addr.String(), -1)
		} else {
			c.Label = strings.Replace(c.Label, "\u003cipv6\u003e", ip.String(), -1)
			c.Label = strings.Replace(c.Label, "\u003ccidr6\u003e", addr.String(), -1)
		}
	}

	b.FullText = fmt.Sprintf(fullTextFmt, c.Label)
}
<commit_msg>added status & local6 placeholder; some improvements<commit_after>package modules

import (
	"fmt"
	"github.com/davidscholberg/go-i3barjson"
	"net"
	"strings"
)

// Interface represents the configuration for the network interface block.
type Interface struct {
	BlockConfigBase `yaml:",inline"`
	IfaceName       string `yaml:"interface_name"`
	IPv4            string
	IPv4CIDR        string
	IPv6            string
	IPv6CIDR        string
	IPv6Local       string
}

// UpdateBlock updates the network interface block.
func (c Interface) UpdateBlock(b *i3barjson.Block) {
	var (
		status string
	)

	b.Color = c.Color
	fullTextFmt := fmt.Sprintf("%s%%s", c.Label)

	iface, err := net.InterfaceByName(c.IfaceName)
	if err != nil {
		b.Urgent = true
		b.FullText = fmt.Sprintf(fullTextFmt, err.Error())
		return
	}

	if iface.Flags == net.FlagUp {
		b.Urgent = false
		status = "up"
	} else {
		b.Urgent = true
		status = "down"
	}

	addrs, err := iface.Addrs()
	if err != nil {
		b.Urgent = true
		b.FullText = fmt.Sprintf(fullTextFmt, err.Error())
		return
	}

	for _, addr := range addrs {
		ip, _, err := net.ParseCIDR(addr.String())
		if err != nil {
			b.Urgent = true
			b.FullText = fmt.Sprintf(fullTextFmt, err.Error())
			return
		}

		// Checking for address family
		if ip.To4() != nil {
			fullTextFmt = strings.Replace(fullTextFmt, "\u003cipv4\u003e", ip.String(), -1)
			fullTextFmt = strings.Replace(fullTextFmt, "\u003ccidr4\u003e", addr.String(), -1)
		} else {

			if ip.String()[0:4] == "fe80" {
				//setting ipv6 link local
				fullTextFmt = strings.Replace(fullTextFmt, "\u003clocal6\u003e", ip.String(), -1)
			} else {
				fullTextFmt = strings.Replace(fullTextFmt, "\u003cipv6\u003e", ip.String()[0:3], -1)
				fullTextFmt = strings.Replace(fullTextFmt, "\u003ccidr6\u003e", addr.String(), -1)
			}
		}
	}

	// setting up/down flag
	fullTextFmt = strings.Replace(fullTextFmt, "\u003cstatus\u003e", status, -1)

	// clearing unset fields i.e. because of ipv6 single-stack
	fullTextFmt = strings.Replace(fullTextFmt, "\u003cipv4\u003e", "", -1)
	fullTextFmt = strings.Replace(fullTextFmt, "\u003ccidr4\u003e", "", -1)
	fullTextFmt = strings.Replace(fullTextFmt, "\u003cipv6\u003e", "", -1)
	fullTextFmt = strings.Replace(fullTextFmt, "\u003ccidr6\u003e", "", -1)
	fullTextFmt = strings.Replace(fullTextFmt, "\u003clocal6\u003e", "", -1)

	// removing the last %s placeholder from final string
	b.FullText = fmt.Sprintf(fullTextFmt, "")
}
<|endoftext|>


<commit_before>package bh1750

import (
	"github.com/explicite/i2c/driver"
	"time"
)

const (
	// ADDR ≦ 0.3VCC
	AddrL = 0x23

	// ADDR ≧ 0.7VCC
	AddrH = 0x5c

	// No active state.
	PowerDown = 0x00

	// Waiting for measurement command.
	PowerOn = 0x01

	// Reset Data register value. Reset command is not acceptable in Power Down mode.
	Reset = 0x07

	// Start measurement at 1lx resolution. Measurement Time is typically 120ms.
	ConHRes1lx = 0x10

	// Start measurement at 0.5lx resolution. Measurement Time is typically 120ms.
	ConHRes05lx = 0x11

	// Start measurement at 4lx resolution. Measurement Time is typically 16ms.
	ConLRes4lx = 0x13

	// Start measurement at 1lx resolution. Measurement Time is typically 120ms.
	// It is automatically set to Power Down mode after measurement.
	OtHRes1lx = 0x20

	// Start measurement at 0.5lx resolution. Measurement Time is typically 120ms.
	// It is automatically set to Power Down mode after measurement.
	OtHRes05lx = 0x21

	// Start measurement at 4lx resolution. Measurement Time is typically 16ms.
	// It is automatically set to Power Down mode after measurement.
	OtLRes4lx = 0x23

	// 20ms for safety time margine in measurement.
	Stm = 20 * time.Millisecond
)

// Map of timeouts for measurement type.
var timeout = map[byte]time.Duration{
	ConHRes1lx:  120*time.Millisecond + Stm,
	ConHRes05lx: 120*time.Millisecond + Stm,
	ConLRes4lx:  16*time.Millisecond + Stm,
	OtHRes1lx:   120*time.Millisecond + Stm,
	OtHRes05lx:  120*time.Millisecond + Stm,
	OtLRes4lx:   16*time.Millisecond + Stm,
}

type BH1750 struct{ driver.Driver }

func (b *BH1750) Init(addr byte, bus byte) error {
	return b.Load(addr, bus)
}

func (b *BH1750) Lux(mode byte) (float32, error) {
	b.Write(mode, 0x00)
	time.Sleep(timeout[mode])
	buf := make([]byte, 0x02)
	var err error
	buf, err = b.Read(mode, 0x02)

	if err != nil {
		return 0, err
	}

	return float32((int(buf[1]) + (int(buf[0] >> 8)))) / 1.2, nil
}

func (b *BH1750) Active() error {
	return b.On()
}

func (b *BH1750) Deactive() error {
	return b.Off()
}
<commit_msg>bh1750 type for go vet<commit_after>package bh1750

import (
	"github.com/explicite/i2c/driver"
	"time"
)

const (
	// ADDR ≦ 0.3VCC
	AddrL = 0x23

	// ADDR ≧ 0.7VCC
	AddrH = 0x5c

	// No active state.
	PowerDown = 0x00

	// Waiting for measurement command.
	PowerOn = 0x01

	// Reset Data register value. Reset command is not acceptable in Power Down mode.
	Reset = 0x07

	// Start measurement at 1lx resolution. Measurement Time is typically 120ms.
	ConHRes1lx = 0x10

	// Start measurement at 0.5lx resolution. Measurement Time is typically 120ms.
	ConHRes05lx = 0x11

	// Start measurement at 4lx resolution. Measurement Time is typically 16ms.
	ConLRes4lx = 0x13

	// Start measurement at 1lx resolution. Measurement Time is typically 120ms.
	// It is automatically set to Power Down mode after measurement.
	OtHRes1lx = 0x20

	// Start measurement at 0.5lx resolution. Measurement Time is typically 120ms.
	// It is automatically set to Power Down mode after measurement.
	OtHRes05lx = 0x21

	// Start measurement at 4lx resolution. Measurement Time is typically 16ms.
	// It is automatically set to Power Down mode after measurement.
	OtLRes4lx = 0x23

	// 20ms for safety time margine in measurement.
	Stm = 20 * time.Millisecond
)

// Map of timeouts for measurement type.
var timeout = map[byte]time.Duration{
	ConHRes1lx:  120*time.Millisecond + Stm,
	ConHRes05lx: 120*time.Millisecond + Stm,
	ConLRes4lx:  16*time.Millisecond + Stm,
	OtHRes1lx:   120*time.Millisecond + Stm,
	OtHRes05lx:  120*time.Millisecond + Stm,
	OtLRes4lx:   16*time.Millisecond + Stm,
}

type BH1750 struct{ driver.Driver }

func (b *BH1750) Init(addr byte, bus byte) error {
	return b.Load(addr, bus)
}

func (b *BH1750) Lux(mode byte) (float32, error) {
	b.Write(mode, 0x00)
	time.Sleep(timeout[mode])
	buf := make([]byte, 0x02)
	var err error
	buf, err = b.Read(mode, 0x02)

	if err != nil {
		return 0, err
	}

	return float32((int(buf[1]) + (int(buf[0]) >> 8))) / 1.2, nil
}

func (b *BH1750) Active() error {
	return b.On()
}

func (b *BH1750) Deactive() error {
	return b.Off()
}
<|endoftext|>