<commit_before>// Copyright 2015 Matthew Collins
//
// 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 ui provides methods to draw a user interface onto the
// the screen and manage resizing.
package ui

const (
	scaledWidth, scaledHeight = 854, 480
)

var (
	// DrawMode is the scaling mode used.
	DrawMode = Scaled
	// Scale controls the scaling manually when DrawModel is Unscaled
	Scale = 1.0

	drawables []drawRef
)

type drawRef struct {
	Drawable
	removeHook func(d Drawable)
}

// Region is an area for a Drawable to draw to
type Region struct {
	X, Y, W, H float64
}

// Drawable is a scalable element that can be drawn to an
// area.
type Drawable interface {
	Draw(r Region, delta float64)
	Size() (float64, float64)
	// Offset is the offset from the attachment point on
	// each axis
	Offset() (float64, float64)
	ShouldDraw() bool
	AttachedTo() Drawable
	Attachment() (vAttach, hAttach AttachPoint)

	isDirty() bool
	clearDirty()
}

type Interactable interface {
	Click(r Region, x, y float64)
	Hover(r Region, x, y float64, over bool)
}

// AddDrawable adds the drawable to the draw list.
func AddDrawable(d Drawable) {
	drawables = append(drawables, drawRef{Drawable: d})
}

// AddDrawableHook adds the drawable to the draw list.
// The passed function will be called when the drawable
// is removed.
func AddDrawableHook(d Drawable, hook func(d Drawable)) {
	drawables = append(drawables, drawRef{Drawable: d, removeHook: hook})
}

var screen = Region{W: scaledWidth, H: scaledHeight}

var (
	lastWidth, lastHeight int
	forceDirty            bool
)

// Draw draws all drawables in the draw list to the screen.
func Draw(width, height int, delta float64) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}

	for _, d := range drawables {
		if !d.ShouldDraw() {
			continue
		}
		r := getDrawRegion(d, sw, sh)
		if r.intersects(screen) {
			d.Draw(r, delta)
		}
	}

	for _, d := range drawables {
		// Handle parents that aren't drawing too
		for r := d.Drawable; r != nil; r = r.AttachedTo() {
			r.clearDirty()
		}
	}
	forceDirty = false
	if lastWidth != width || lastHeight != height {
		forceDirty = true
		lastWidth, lastHeight = width, height
	}
}

func (r Region) intersects(o Region) bool {
	return !(r.X+r.W < o.X ||
		r.X > o.X+o.W ||
		r.Y+r.H < o.Y ||
		r.Y > o.Y+o.H)
}

// Hover calls Hover on all interactables at the passed location.
func Hover(x, y float64, width, height int) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}
	x = (x / float64(width)) * scaledWidth
	y = (y / float64(height)) * scaledHeight
	for i := range drawables {
		d := drawables[len(drawables)-1-i]
		inter, ok := d.Drawable.(Interactable)
		if !ok {
			continue
		}
		r := getDrawRegion(d, sw, sh)
		if x >= r.X && x <= r.X+r.W && y >= r.Y && y <= r.Y+r.H {
			inter.Hover(r, x, y, true)
		} else {
			inter.Hover(r, x, y, false)
		}
	}
}

// Click calls Click on all interactables at the passed location.
func Click(x, y float64, width, height int) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}
	x = (x / float64(width)) * scaledWidth
	y = (y / float64(height)) * scaledHeight
	for i := range drawables {
		d := drawables[len(drawables)-1-i]
		inter, ok := d.Drawable.(Interactable)
		if !ok {
			continue
		}
		r := getDrawRegion(d, sw, sh)
		if x >= r.X && x <= r.X+r.W && y >= r.Y && y <= r.Y+r.H {
			inter.Click(r, x, y)
			break
		}
	}
}

// Intersects returns whether the point x,y intersects with the drawable
func Intersects(d Drawable, x, y float64, width, height int) (float64, float64, bool) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}
	x = (x / float64(width)) * scaledWidth
	y = (y / float64(height)) * scaledHeight
	r := getDrawRegion(d, sw, sh)
	if x >= r.X && x <= r.X+r.W && y >= r.Y && y <= r.Y+r.H {
		w, h := d.Size()
		ox := ((x - r.X) / r.W) * w
		oy := ((y - r.Y) / r.H) * h
		return ox, oy, true
	}
	return 0, 0, false
}

func getDrawRegion(d Drawable, sw, sh float64) Region {
	parent := d.AttachedTo()
	var superR Region
	if parent != nil {
		superR = getDrawRegion(parent, sw, sh)
	} else {
		superR = screen
	}
	r := Region{}
	w, h := d.Size()
	ox, oy := d.Offset()
	r.W = w * sw
	r.H = h * sh
	vAttach, hAttach := d.Attachment()
	switch hAttach {
	case Left:
		r.X = ox * sw
	case Middle:
		r.X = (superR.W / 2) - (r.W / 2) + ox*sw
	case Right:
		r.X = superR.W - ox*sw - r.W
	}
	switch vAttach {
	case Top:
		r.Y = oy * sh
	case Middle:
		r.Y = (superR.H / 2) - (r.H / 2) + oy*sh
	case Right:
		r.Y = superR.H - oy*sh - r.H
	}
	r.X += superR.X
	r.Y += superR.Y
	return r
}

// Remove removes the drawable from the screen.
func Remove(d Drawable) {
	for i, dd := range drawables {
		if dd.Drawable == d {
			if dd.removeHook != nil {
				dd.removeHook(d)
			}
			drawables = append(drawables[:i], drawables[i+1:]...)
			return
		}
	}
}

type baseElement struct {
	parent           Drawable
	visible          bool
	vAttach, hAttach AttachPoint

	dirty bool
	isNew bool
	data  []byte
}

// Attachment returns the sides where this element is attached too.
func (b *baseElement) Attachment() (vAttach, hAttach AttachPoint) {
	return b.vAttach, b.hAttach
}

// ShouldDraw returns whether this should be drawn at this time.
func (b *baseElement) ShouldDraw() bool {
	return b.visible
}

func (b *baseElement) SetDraw(shouldDraw bool) {
	if shouldDraw != b.visible {
		b.visible = shouldDraw
		b.dirty = true
	}
}

// AttachedTo returns the Drawable this is attached to or nil.
func (b *baseElement) AttachedTo() Drawable {
	return b.parent
}

func (b *baseElement) AttachTo(d Drawable) {
	if b.parent != d {
		b.parent = d
		b.dirty = true
	}
}

func (b *baseElement) isDirty() bool {
	return b.dirty || (b.parent != nil && b.parent.isDirty())
}

func (b *baseElement) clearDirty() {
	b.dirty = false
}
<commit_msg>ui: flag added elements as dirty<commit_after>// Copyright 2015 Matthew Collins
//
// 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 ui provides methods to draw a user interface onto the
// the screen and manage resizing.
package ui

const (
	scaledWidth, scaledHeight = 854, 480
)

var (
	// DrawMode is the scaling mode used.
	DrawMode = Scaled
	// Scale controls the scaling manually when DrawModel is Unscaled
	Scale = 1.0

	drawables []drawRef
)

type drawRef struct {
	Drawable
	removeHook func(d Drawable)
}

// Region is an area for a Drawable to draw to
type Region struct {
	X, Y, W, H float64
}

// Drawable is a scalable element that can be drawn to an
// area.
type Drawable interface {
	Draw(r Region, delta float64)
	Size() (float64, float64)
	// Offset is the offset from the attachment point on
	// each axis
	Offset() (float64, float64)
	ShouldDraw() bool
	AttachedTo() Drawable
	Attachment() (vAttach, hAttach AttachPoint)

	isDirty() bool
	flagDirty()
	clearDirty()
}

type Interactable interface {
	Click(r Region, x, y float64)
	Hover(r Region, x, y float64, over bool)
}

// AddDrawable adds the drawable to the draw list.
func AddDrawable(d Drawable) {
	d.flagDirty()
	drawables = append(drawables, drawRef{Drawable: d})
}

// AddDrawableHook adds the drawable to the draw list.
// The passed function will be called when the drawable
// is removed.
func AddDrawableHook(d Drawable, hook func(d Drawable)) {
	d.flagDirty()
	drawables = append(drawables, drawRef{Drawable: d, removeHook: hook})
}

var screen = Region{W: scaledWidth, H: scaledHeight}

var (
	lastWidth, lastHeight int
	forceDirty            bool
)

// Draw draws all drawables in the draw list to the screen.
func Draw(width, height int, delta float64) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}

	for _, d := range drawables {
		if !d.ShouldDraw() {
			continue
		}
		r := getDrawRegion(d, sw, sh)
		if r.intersects(screen) {
			d.Draw(r, delta)
		}
	}

	for _, d := range drawables {
		// Handle parents that aren't drawing too
		for r := d.Drawable; r != nil; r = r.AttachedTo() {
			r.clearDirty()
		}
	}
	forceDirty = false
	if lastWidth != width || lastHeight != height {
		forceDirty = true
		lastWidth, lastHeight = width, height
	}
}

func (r Region) intersects(o Region) bool {
	return !(r.X+r.W < o.X ||
		r.X > o.X+o.W ||
		r.Y+r.H < o.Y ||
		r.Y > o.Y+o.H)
}

// Hover calls Hover on all interactables at the passed location.
func Hover(x, y float64, width, height int) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}
	x = (x / float64(width)) * scaledWidth
	y = (y / float64(height)) * scaledHeight
	for i := range drawables {
		d := drawables[len(drawables)-1-i]
		inter, ok := d.Drawable.(Interactable)
		if !ok {
			continue
		}
		r := getDrawRegion(d, sw, sh)
		if x >= r.X && x <= r.X+r.W && y >= r.Y && y <= r.Y+r.H {
			inter.Hover(r, x, y, true)
		} else {
			inter.Hover(r, x, y, false)
		}
	}
}

// Click calls Click on all interactables at the passed location.
func Click(x, y float64, width, height int) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}
	x = (x / float64(width)) * scaledWidth
	y = (y / float64(height)) * scaledHeight
	for i := range drawables {
		d := drawables[len(drawables)-1-i]
		inter, ok := d.Drawable.(Interactable)
		if !ok {
			continue
		}
		r := getDrawRegion(d, sw, sh)
		if x >= r.X && x <= r.X+r.W && y >= r.Y && y <= r.Y+r.H {
			inter.Click(r, x, y)
			break
		}
	}
}

// Intersects returns whether the point x,y intersects with the drawable
func Intersects(d Drawable, x, y float64, width, height int) (float64, float64, bool) {
	sw := scaledWidth / float64(width)
	sh := scaledHeight / float64(height)
	if DrawMode == Unscaled {
		sw, sh = Scale, Scale
	}
	x = (x / float64(width)) * scaledWidth
	y = (y / float64(height)) * scaledHeight
	r := getDrawRegion(d, sw, sh)
	if x >= r.X && x <= r.X+r.W && y >= r.Y && y <= r.Y+r.H {
		w, h := d.Size()
		ox := ((x - r.X) / r.W) * w
		oy := ((y - r.Y) / r.H) * h
		return ox, oy, true
	}
	return 0, 0, false
}

func getDrawRegion(d Drawable, sw, sh float64) Region {
	parent := d.AttachedTo()
	var superR Region
	if parent != nil {
		superR = getDrawRegion(parent, sw, sh)
	} else {
		superR = screen
	}
	r := Region{}
	w, h := d.Size()
	ox, oy := d.Offset()
	r.W = w * sw
	r.H = h * sh
	vAttach, hAttach := d.Attachment()
	switch hAttach {
	case Left:
		r.X = ox * sw
	case Middle:
		r.X = (superR.W / 2) - (r.W / 2) + ox*sw
	case Right:
		r.X = superR.W - ox*sw - r.W
	}
	switch vAttach {
	case Top:
		r.Y = oy * sh
	case Middle:
		r.Y = (superR.H / 2) - (r.H / 2) + oy*sh
	case Right:
		r.Y = superR.H - oy*sh - r.H
	}
	r.X += superR.X
	r.Y += superR.Y
	return r
}

// Remove removes the drawable from the screen.
func Remove(d Drawable) {
	for i, dd := range drawables {
		if dd.Drawable == d {
			if dd.removeHook != nil {
				dd.removeHook(d)
			}
			drawables = append(drawables[:i], drawables[i+1:]...)
			return
		}
	}
}

type baseElement struct {
	parent           Drawable
	visible          bool
	vAttach, hAttach AttachPoint

	dirty bool
	isNew bool
	data  []byte
}

// Attachment returns the sides where this element is attached too.
func (b *baseElement) Attachment() (vAttach, hAttach AttachPoint) {
	return b.vAttach, b.hAttach
}

// ShouldDraw returns whether this should be drawn at this time.
func (b *baseElement) ShouldDraw() bool {
	return b.visible
}

func (b *baseElement) SetDraw(shouldDraw bool) {
	if shouldDraw != b.visible {
		b.visible = shouldDraw
		b.dirty = true
	}
}

// AttachedTo returns the Drawable this is attached to or nil.
func (b *baseElement) AttachedTo() Drawable {
	return b.parent
}

func (b *baseElement) AttachTo(d Drawable) {
	if b.parent != d {
		b.parent = d
		b.dirty = true
	}
}

func (b *baseElement) isDirty() bool {
	return b.dirty || (b.parent != nil && b.parent.isDirty())
}

func (b *baseElement) flagDirty() {
	b.dirty = true
}

func (b *baseElement) clearDirty() {
	b.dirty = false
}
<|endoftext|>


<commit_before>package main

import "net"
import "errors"

func externalIP() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}
			return ip.String(), nil
		}
	}
	return "", errors.New("are you connected to the network?")
}

func GetLocalIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	for _, address := range addrs {
		// check the address type and if it is not a loopback the display it
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String()
			}
		}
	}
	return ""
}
<commit_msg>Uses local ip address only<commit_after>package main

import "net"
import "errors"
import "strings"

func externalIP() (string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}
			return ip.String(), nil
		}
	}
	return "", errors.New("are you connected to the network?")
}

func GetLocalIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	for _, address := range addrs {
		// check the address type and if it is not a loopback the display it
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil && (strings.Contains(ipnet.IP.String(), "192.168.1") || strings.Contains(ipnet.IP.String(), "192.168.0")) {
				return ipnet.IP.String()
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package rotor

import (
	"bytes"
	"context"
	"encoding/json"
	"net/http"
	"net/url"
	"strings"

	"github.com/pkg/errors"
)

// GatewayRequest represents an Amazon API Gateway Proxy Event.
type GatewayRequest struct {
	HTTPMethod            string
	Headers               map[string]string
	Resource              string
	PathParameters        map[string]string
	Path                  string
	QueryStringParameters map[string]string
	Body                  string
	IsBase64Encoded       bool
	StageVariables        map[string]string
}

//GatewayResponse is returned to the API Gateway
type GatewayResponse struct {
	StatusCode int               `json:"statusCode"`
	Body       string            `json:"body"`
	Headers    map[string]string `json:"headers"`
}

//GatewayHandler implements the lambda handler while allowing normal http.Handlers to serve
type GatewayHandler struct {
	stripN int
	httpH  http.Handler
}

//NewGatewayHandler makes it easy to serve normal http
func NewGatewayHandler(stripBasePaths int, httpH http.Handler) *GatewayHandler {
	return &GatewayHandler{
		stripN: stripBasePaths,
		httpH:  httpH,
	}
}

//HandleEvent takes invocations from the API Gateway and turns them into http.Handler invocations
func (gwh *GatewayHandler) HandleEvent(ctx context.Context, msg json.RawMessage) (res interface{}, err error) {
	req := &GatewayRequest{}
	err = json.Unmarshal(msg, req)
	if err != nil {
		return nil, errors.Wrap(err, "failed to decode gateway request")
	}

	//parse path
	loc, err := url.Parse(req.Path)
	if err != nil {
		return nil, errors.Wrap(err, "failed to parse request path")
	}

	//strip path base
	if gwh.stripN > 0 {
		comps := strings.SplitN(
			strings.TrimLeft(loc.Path, "/"),
			"/", gwh.stripN+1)
		if len(comps) >= gwh.stripN {
			loc.Path = "/" + strings.Join(comps[gwh.stripN:], "/")
		} else {
			loc.Path = "/"
		}
	}

	q := loc.Query()
	for k, param := range req.QueryStringParameters {
		q.Set(k, param)
	}

	loc.RawQuery = q.Encode()
	r, err := http.NewRequest(req.HTTPMethod, loc.String(), bytes.NewBufferString(req.Body))
	if err != nil {
		return nil, errors.Wrap(err, "failed to create HTTP request")
	}

	for k, val := range req.Headers {
		for _, v := range strings.Split(val, ",") {
			r.Header.Add(k, strings.TrimSpace(v))
		}
	}

	w := &bufferedResponse{
		statusCode: http.StatusOK, //like standard lib, assume 200
		header:     http.Header{},
		Buffer:     bytes.NewBuffer(nil),
	}

	gwh.httpH.ServeHTTP(w, r.WithContext(ctx))

	resp := &GatewayResponse{
		StatusCode: w.statusCode,
		Body:       w.Buffer.String(),
		Headers:    map[string]string{},
	}

	for k, v := range w.header {
		resp.Headers[k] = strings.Join(v, ",")
	}

	return resp, nil
}

//bufferedResponse implements the response writer interface but buffers the body which is necessary for the creating a JSON formatted Lambda response anyway
type bufferedResponse struct {
	statusCode int
	header     http.Header
	*bytes.Buffer
}

func (br *bufferedResponse) Header() http.Header    { return br.header }
func (br *bufferedResponse) WriteHeader(status int) { br.statusCode = status }
<commit_msg>removed dependency on pkg/errors<commit_after>package rotor

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

// GatewayRequest represents an Amazon API Gateway Proxy Event.
type GatewayRequest struct {
	HTTPMethod            string
	Headers               map[string]string
	Resource              string
	PathParameters        map[string]string
	Path                  string
	QueryStringParameters map[string]string
	Body                  string
	IsBase64Encoded       bool
	StageVariables        map[string]string
}

//GatewayResponse is returned to the API Gateway
type GatewayResponse struct {
	StatusCode int               `json:"statusCode"`
	Body       string            `json:"body"`
	Headers    map[string]string `json:"headers"`
}

//GatewayHandler implements the lambda handler while allowing normal http.Handlers to serve
type GatewayHandler struct {
	stripN int
	httpH  http.Handler
}

//NewGatewayHandler makes it easy to serve normal http
func NewGatewayHandler(stripBasePaths int, httpH http.Handler) *GatewayHandler {
	return &GatewayHandler{
		stripN: stripBasePaths,
		httpH:  httpH,
	}
}

//HandleEvent takes invocations from the API Gateway and turns them into http.Handler invocations
func (gwh *GatewayHandler) HandleEvent(ctx context.Context, msg json.RawMessage) (res interface{}, err error) {
	req := &GatewayRequest{}
	err = json.Unmarshal(msg, req)
	if err != nil {
		return nil, fmt.Errorf("failed to decode gateway request: %v", err)
	}

	//parse path
	loc, err := url.Parse(req.Path)
	if err != nil {
		return nil, fmt.Errorf("failed to parse request path: %v", err)
	}

	//strip path base
	if gwh.stripN > 0 {
		comps := strings.SplitN(
			strings.TrimLeft(loc.Path, "/"),
			"/", gwh.stripN+1)
		if len(comps) >= gwh.stripN {
			loc.Path = "/" + strings.Join(comps[gwh.stripN:], "/")
		} else {
			loc.Path = "/"
		}
	}

	q := loc.Query()
	for k, param := range req.QueryStringParameters {
		q.Set(k, param)
	}

	loc.RawQuery = q.Encode()
	r, err := http.NewRequest(req.HTTPMethod, loc.String(), bytes.NewBufferString(req.Body))
	if err != nil {
		return nil, fmt.Errorf("failed to create HTTP request: %v", err)
		// return nil, errors.Wrap(err, "failed to create HTTP request")
	}

	for k, val := range req.Headers {
		for _, v := range strings.Split(val, ",") {
			r.Header.Add(k, strings.TrimSpace(v))
		}
	}

	w := &bufferedResponse{
		statusCode: http.StatusOK, //like standard lib, assume 200
		header:     http.Header{},
		Buffer:     bytes.NewBuffer(nil),
	}

	gwh.httpH.ServeHTTP(w, r.WithContext(ctx))

	resp := &GatewayResponse{
		StatusCode: w.statusCode,
		Body:       w.Buffer.String(),
		Headers:    map[string]string{},
	}

	for k, v := range w.header {
		resp.Headers[k] = strings.Join(v, ",")
	}

	return resp, nil
}

//bufferedResponse implements the response writer interface but buffers the body which is necessary for the creating a JSON formatted Lambda response anyway
type bufferedResponse struct {
	statusCode int
	header     http.Header
	*bytes.Buffer
}

func (br *bufferedResponse) Header() http.Header    { return br.header }
func (br *bufferedResponse) WriteHeader(status int) { br.statusCode = status }
<|endoftext|>


<commit_before>package ics

import (
	"errors"
	"strconv"
	"time"

	strparse "github.com/MJKWoolnough/parser"
)

func escape(s string) []byte {
	p := make([]byte, 0, len(s))
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '\\':
			p = append(p, '\\', '\\')
		case ';':
			p = append(p, '\\', ';')
		case ',':
			p = append(p, '\\', ',')
		case '\n':
			p = append(p, '\\', 'n')
		default:
			p = append(p, s[i])
		}
	}
	return p
}

func unescape(p string) []byte {
	u := make([]byte, 0, len(p))
	for i := 0; i < len(p); i++ {
		if p[i] == '\\' && i+1 < len(p) {
			i++
			switch p[i] {
			case '\\', ';', ',':
				u = append(u, p[i])
			case 'N', 'n':
				u = append(u, '\n')
			default:
				u = append(u, '\\', p[i])
			}
		} else {
			u = append(u, p[i])
		}
	}
	return u
}

func escape6868(s string) []byte {
	p := make([]byte, 0, len(s))
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '\n':
			p = append(p, '^', 'n')
		case '^':
			p = append(p, '^', '^')
		case '"':
			p = append(p, '^', '\'')
		default:
			p = append(p, s[i])
		}
	}
	return p
}

func unescape6868(p string) []byte {
	u := make([]byte, 0, len(p))
	for i := 0; i < len(p); i++ {
		if p[i] == '^' && i+1 < len(p) {
			i++
			switch p[i] {
			case 'n':
				u = append(u, '\n') //crlf on windows?
			case '^':
				u = append(u, '^')
			case '\'':
				u = append(u, '"')
			default:
				u = append(u, '^', p[i])
			}
		} else {
			u = append(u, p[i])
		}
	}
	return u
}

func textSplit(s string, delim byte) []string {
	toRet := make([]string, 0, 1)
	lastPos := 0
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '\\':
			i++
		case delim:
			toRet = append(toRet, string(unescape(s[lastPos:i])))
			lastPos = i + 1
		}
	}
	if lastPos <= len(s) {
		toRet = append(toRet, string(unescape(s[lastPos:])))
	}
	return toRet
}

type dateTime struct {
	justDate bool
	time.Time
}

func (dt dateTime) Add(d time.Duration) dateTime {
	if d%24*time.Hour != 0 {
		dt.justDate = false
	}
	dt.Time = dt.Time.Add(d)
	return dt
}

func (dt dateTime) AddDate(years, months, days int) dateTime {
	dt.Time = dt.Time.AddDate(years, months, days)
	return dt
}

func (dt dateTime) In(loc *time.Location) dateTime {
	dt.Time.In(loc)
	return dt
}

func (dt dateTime) String() string {
	if dt.justDate {
		return dt.Format("20060102")
	}
	switch dt.Location() {
	case nil, time.UTC:
		return dt.Format("20060102T150405Z")
	default:
		return dt.Format("20060102T150405")
	}
}

func parseDate(s string) (dateTime, error) {
	t, err := time.Parse("20060102", s)
	return dateTime{true, t}, err
}

func parseDateTime(s string, l *time.Location) (dateTime, error) {
	var (
		t   time.Time
		err error
	)
	if l == nil {
		if s[len(s)-1] == 'Z' {
			t, err = time.Parse("20060102T150405Z", s)
		} else {
			t, err = time.ParseInLocation("20060102T150405", s, time.Local)
		}
	} else {
		t, err = time.ParseInLocation("20060102T150405", s, l)
	}
	return dateTime{Time: t}, err
}

func parseTime(s string, l *time.Location) (time.Time, error) {
	if l == nil {
		if s[len(s)-1] == 'Z' {
			return time.Parse("150405Z", s)
		} else {
			return time.ParseInLocation("150405Z", s, time.Local)
		}
	}
	return time.ParseInLocation("150405", s, l)
}

const nums = "0123456789"

func parseDuration(s string) (time.Duration, error) {
	p := strparse.NewStringParser(s)
	var (
		dur time.Duration
		neg bool
	)
	if p.Accept("-") {
		neg = true
	} else {
		p.Accept("+")
	}
	if !p.Accept("P") {
		return 0, ErrInvalidDuration
	}
	p.Get()
	if !p.Accept("T") {
		p.AcceptRun(nums)
		num := p.Get()
		if len(num) == 0 {
			return 0, ErrInvalidDuration
		}
		n, _ := strconv.Atoi(num)
		p.Accept("DW")
		switch p.Get() {
		case "D":
			dur = time.Duration(n) * time.Hour * 24
		case "W":
			return time.Duration(n) * time.Hour * 24 * 7, nil
		default:
			return 0, ErrInvalidDuration
		}
		p.Except("")
		switch p.Get() {
		case "":
			if neg {
				return -dur, nil
			}
			return dur, nil
		case "T":
		default:
			return 0, ErrInvalidDuration
		}
	} else {
		p.Get()
	}
	toRead := "HMS"
	var readTime bool
	for len(toRead) > 0 {
		p.AcceptRun(nums)
		num := p.Get()
		if len(num) == 0 {
			if !readTime {
				return 0, ErrInvalidDuration
			}
			break
		}
		n, _ := strconv.Atoi(num)
		p.Accept(toRead)
		switch p.Get() {
		case "H":
			dur += time.Duration(n) * time.Hour
			toRead = "MS"
		case "M":
			dur += time.Duration(n) * time.Minute
			toRead = "S"
		case "S":
			dur += time.Duration(n) * time.Second
			toRead = ""
		default:
			return 0, ErrInvalidDuration
		}
		readTime = true
	}
	if neg {
		return -dur, nil
	}
	return dur, nil
}

func durationString(d time.Duration) string {
	toRet := make([]byte, 0, 16)
	if d < 0 {
		toRet = append(toRet, '-')
	}
	toRet = append(toRet, 'P')
	if d%(time.Hour*24*7) == 0 {
		toRet = append(toRet, strconv.FormatInt(int64(d/(time.Hour*24*7)), 10)...)
		toRet = append(toRet, 'W')
	} else {
		if d >= time.Hour*24 {
			toRet = append(toRet, strconv.FormatInt(int64(d/(time.Hour*24)), 10)...)
			toRet = append(toRet, 'D')
			d = d % (time.Hour * 24)
		}
		if d > 0 {
			toRet = append(toRet, 'T')
			if d >= time.Hour {
				toRet = append(toRet, strconv.FormatInt(int64(d/time.Hour), 10)...)
				toRet = append(toRet, 'H')
				d = d % time.Hour
			}
			if d >= time.Minute {
				toRet = append(toRet, strconv.FormatInt(int64(d/time.Minute), 10)...)
				toRet = append(toRet, 'M')
				d = d % time.Minute
			}
			if d >= time.Second {
				toRet = append(toRet, strconv.FormatInt(int64(d/time.Second), 10)...)
				toRet = append(toRet, 'S')
			}
		}
	}
	return string(toRet)
}

func parseOffset(s string) (int, error) {
	if len(s) != 5 && len(s) != 7 {
		return 0, ErrInvalidOffset
	}
	var neg bool
	if s[0] == '-' {
		neg = true
	} else if s[0] != '+' {
		return 0, ErrInvalidOffset
	}
	hours, err := strconv.Atoi(s[1:3])
	if err != nil {
		return 0, ErrInvalidOffset
	}
	minutes, err := strconv.Atoi(s[3:5])
	if err != nil {
		return 0, ErrInvalidOffset
	}
	var seconds int
	if len(s) == 7 {
		seconds, err = strconv.Atoi(s[5:7])
		if err != nil {
			return 0, ErrInvalidOffset
		}
	}
	val := hours*3600 + minutes*60 + seconds
	if neg {
		return -val, nil
	}
	return val, nil
}

func offsetString(o int) string {
	toRet := make([]byte, 1, 7)
	if o < 0 {
		toRet[0] = '-'
		o = -o
	} else {
		toRet[0] = '+'
	}
	toRet = append(toRet, strconv.Itoa(o/3600)...)
	toRet = append(toRet, strconv.Itoa((o%3600)/60)...)
	seconds := o % 60
	if seconds > 0 {
		toRet = append(toRet, strconv.Itoa(seconds)...)
	}
	return string(toRet)
}

func dquote(p []byte) []byte {
	q := make([]byte, 0, len(p)+2)
	q = append(q, '"')
	q = append(q, p...)
	q = append(q, '"')
	return q
}

func dquoteIfNeeded(p []byte) []byte {
	for _, c := range p {
		switch c {
		case ';', ':', ',':
			return dquote(p)
		}
	}
	return p
}

// Errors

var (
	ErrInvalidDuration = errors.New("invalid duration string")
	ErrInvalidOffset   = errors.New("invalid offset string")
)
<commit_msg>corrected encoding of negative durations<commit_after>package ics

import (
	"errors"
	"strconv"
	"time"

	strparse "github.com/MJKWoolnough/parser"
)

func escape(s string) []byte {
	p := make([]byte, 0, len(s))
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '\\':
			p = append(p, '\\', '\\')
		case ';':
			p = append(p, '\\', ';')
		case ',':
			p = append(p, '\\', ',')
		case '\n':
			p = append(p, '\\', 'n')
		default:
			p = append(p, s[i])
		}
	}
	return p
}

func unescape(p string) []byte {
	u := make([]byte, 0, len(p))
	for i := 0; i < len(p); i++ {
		if p[i] == '\\' && i+1 < len(p) {
			i++
			switch p[i] {
			case '\\', ';', ',':
				u = append(u, p[i])
			case 'N', 'n':
				u = append(u, '\n')
			default:
				u = append(u, '\\', p[i])
			}
		} else {
			u = append(u, p[i])
		}
	}
	return u
}

func escape6868(s string) []byte {
	p := make([]byte, 0, len(s))
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '\n':
			p = append(p, '^', 'n')
		case '^':
			p = append(p, '^', '^')
		case '"':
			p = append(p, '^', '\'')
		default:
			p = append(p, s[i])
		}
	}
	return p
}

func unescape6868(p string) []byte {
	u := make([]byte, 0, len(p))
	for i := 0; i < len(p); i++ {
		if p[i] == '^' && i+1 < len(p) {
			i++
			switch p[i] {
			case 'n':
				u = append(u, '\n') //crlf on windows?
			case '^':
				u = append(u, '^')
			case '\'':
				u = append(u, '"')
			default:
				u = append(u, '^', p[i])
			}
		} else {
			u = append(u, p[i])
		}
	}
	return u
}

func textSplit(s string, delim byte) []string {
	toRet := make([]string, 0, 1)
	lastPos := 0
	for i := 0; i < len(s); i++ {
		switch s[i] {
		case '\\':
			i++
		case delim:
			toRet = append(toRet, string(unescape(s[lastPos:i])))
			lastPos = i + 1
		}
	}
	if lastPos <= len(s) {
		toRet = append(toRet, string(unescape(s[lastPos:])))
	}
	return toRet
}

type dateTime struct {
	justDate bool
	time.Time
}

func (dt dateTime) Add(d time.Duration) dateTime {
	if d%24*time.Hour != 0 {
		dt.justDate = false
	}
	dt.Time = dt.Time.Add(d)
	return dt
}

func (dt dateTime) AddDate(years, months, days int) dateTime {
	dt.Time = dt.Time.AddDate(years, months, days)
	return dt
}

func (dt dateTime) In(loc *time.Location) dateTime {
	dt.Time.In(loc)
	return dt
}

func (dt dateTime) String() string {
	if dt.justDate {
		return dt.Format("20060102")
	}
	switch dt.Location() {
	case nil, time.UTC:
		return dt.Format("20060102T150405Z")
	default:
		return dt.Format("20060102T150405")
	}
}

func parseDate(s string) (dateTime, error) {
	t, err := time.Parse("20060102", s)
	return dateTime{true, t}, err
}

func parseDateTime(s string, l *time.Location) (dateTime, error) {
	var (
		t   time.Time
		err error
	)
	if l == nil {
		if s[len(s)-1] == 'Z' {
			t, err = time.Parse("20060102T150405Z", s)
		} else {
			t, err = time.ParseInLocation("20060102T150405", s, time.Local)
		}
	} else {
		t, err = time.ParseInLocation("20060102T150405", s, l)
	}
	return dateTime{Time: t}, err
}

func parseTime(s string, l *time.Location) (time.Time, error) {
	if l == nil {
		if s[len(s)-1] == 'Z' {
			return time.Parse("150405Z", s)
		} else {
			return time.ParseInLocation("150405Z", s, time.Local)
		}
	}
	return time.ParseInLocation("150405", s, l)
}

const nums = "0123456789"

func parseDuration(s string) (time.Duration, error) {
	p := strparse.NewStringParser(s)
	var (
		dur time.Duration
		neg bool
	)
	if p.Accept("-") {
		neg = true
	} else {
		p.Accept("+")
	}
	if !p.Accept("P") {
		return 0, ErrInvalidDuration
	}
	p.Get()
	if !p.Accept("T") {
		p.AcceptRun(nums)
		num := p.Get()
		if len(num) == 0 {
			return 0, ErrInvalidDuration
		}
		n, _ := strconv.Atoi(num)
		p.Accept("DW")
		switch p.Get() {
		case "D":
			dur = time.Duration(n) * time.Hour * 24
		case "W":
			return time.Duration(n) * time.Hour * 24 * 7, nil
		default:
			return 0, ErrInvalidDuration
		}
		p.Except("")
		switch p.Get() {
		case "":
			if neg {
				return -dur, nil
			}
			return dur, nil
		case "T":
		default:
			return 0, ErrInvalidDuration
		}
	} else {
		p.Get()
	}
	toRead := "HMS"
	var readTime bool
	for len(toRead) > 0 {
		p.AcceptRun(nums)
		num := p.Get()
		if len(num) == 0 {
			if !readTime {
				return 0, ErrInvalidDuration
			}
			break
		}
		n, _ := strconv.Atoi(num)
		p.Accept(toRead)
		switch p.Get() {
		case "H":
			dur += time.Duration(n) * time.Hour
			toRead = "MS"
		case "M":
			dur += time.Duration(n) * time.Minute
			toRead = "S"
		case "S":
			dur += time.Duration(n) * time.Second
			toRead = ""
		default:
			return 0, ErrInvalidDuration
		}
		readTime = true
	}
	if neg {
		return -dur, nil
	}
	return dur, nil
}

func durationString(d time.Duration) string {
	toRet := make([]byte, 0, 16)
	if d < 0 {
		toRet = append(toRet, '-')
		d = -d
	}
	toRet = append(toRet, 'P')
	if d%(time.Hour*24*7) == 0 {
		toRet = append(toRet, strconv.FormatInt(int64(d/(time.Hour*24*7)), 10)...)
		toRet = append(toRet, 'W')
	} else {
		if d >= time.Hour*24 {
			toRet = append(toRet, strconv.FormatInt(int64(d/(time.Hour*24)), 10)...)
			toRet = append(toRet, 'D')
			d = d % (time.Hour * 24)
		}
		if d > 0 {
			toRet = append(toRet, 'T')
			if d >= time.Hour {
				toRet = append(toRet, strconv.FormatInt(int64(d/time.Hour), 10)...)
				toRet = append(toRet, 'H')
				d = d % time.Hour
			}
			if d >= time.Minute {
				toRet = append(toRet, strconv.FormatInt(int64(d/time.Minute), 10)...)
				toRet = append(toRet, 'M')
				d = d % time.Minute
			}
			if d >= time.Second {
				toRet = append(toRet, strconv.FormatInt(int64(d/time.Second), 10)...)
				toRet = append(toRet, 'S')
			}
		}
	}
	return string(toRet)
}

func parseOffset(s string) (int, error) {
	if len(s) != 5 && len(s) != 7 {
		return 0, ErrInvalidOffset
	}
	var neg bool
	if s[0] == '-' {
		neg = true
	} else if s[0] != '+' {
		return 0, ErrInvalidOffset
	}
	hours, err := strconv.Atoi(s[1:3])
	if err != nil {
		return 0, ErrInvalidOffset
	}
	minutes, err := strconv.Atoi(s[3:5])
	if err != nil {
		return 0, ErrInvalidOffset
	}
	var seconds int
	if len(s) == 7 {
		seconds, err = strconv.Atoi(s[5:7])
		if err != nil {
			return 0, ErrInvalidOffset
		}
	}
	val := hours*3600 + minutes*60 + seconds
	if neg {
		return -val, nil
	}
	return val, nil
}

func offsetString(o int) string {
	toRet := make([]byte, 1, 7)
	if o < 0 {
		toRet[0] = '-'
		o = -o
	} else {
		toRet[0] = '+'
	}
	toRet = append(toRet, strconv.Itoa(o/3600)...)
	toRet = append(toRet, strconv.Itoa((o%3600)/60)...)
	seconds := o % 60
	if seconds > 0 {
		toRet = append(toRet, strconv.Itoa(seconds)...)
	}
	return string(toRet)
}

func dquote(p []byte) []byte {
	q := make([]byte, 0, len(p)+2)
	q = append(q, '"')
	q = append(q, p...)
	q = append(q, '"')
	return q
}

func dquoteIfNeeded(p []byte) []byte {
	for _, c := range p {
		switch c {
		case ';', ':', ',':
			return dquote(p)
		}
	}
	return p
}

// Errors

var (
	ErrInvalidDuration = errors.New("invalid duration string")
	ErrInvalidOffset   = errors.New("invalid offset string")
)
<|endoftext|>


<commit_before>package goriak

import (
	"encoding/json"
	"errors"
	"reflect"

	riak "github.com/basho/riak-go-client"
)

// SetJSON saves value as key in the bucket bucket/bucketType
// Values can automatically be added to indexes with the struct tag goriakindex
func (c *Client) SetJSON(bucket, bucketType, key string, value interface{}) error {
	by, err := json.Marshal(value)

	if err != nil {
		return err
	}

	object := riak.Object{
		Value: by,
	}

	refType := reflect.TypeOf(value)
	refValue := reflect.ValueOf(value)

	// Set indexes
	for i := 0; i < refType.NumField(); i++ {

		indexName := refType.Field(i).Tag.Get("goriakindex")

		if len(indexName) == 0 {
			continue
		}

		// String
		if refValue.Field(i).Type().Kind() == reflect.String {
			object.AddToIndex(indexName, refValue.Field(i).String())
			continue
		}

		// Slice
		if refValue.Field(i).Type().Kind() == reflect.Slice {

			sliceType := refValue.Field(i).Type().Elem()
			sliceValue := refValue.Field(i)

			// Slice: String
			if sliceType.Kind() == reflect.String {
				for sli := 0; sli < sliceValue.Len(); sli++ {
					object.AddToIndex(indexName, sliceValue.Index(sli).String())
				}

				continue
			}
		}

		return errors.New("Did not know how to set index: " + refType.Field(i).Name)
	}

	cmd, err := riak.NewStoreValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		WithContent(&object).
		Build()

	if err != nil {
		return err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return err
	}

	res, ok := cmd.(*riak.StoreValueCommand)

	if !ok {
		return errors.New("Unable to parse response from Riak")
	}

	if !res.Success() {
		return errors.New("Riak command was not successful")
	}

	return nil
}

// SetRaw saves the data in Riak directly without any modifications
func (c *Client) SetRaw(bucket, bucketType, key string, data []byte) error {
	object := riak.Object{
		Value: data,
	}

	cmd, err := riak.NewStoreValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		WithContent(&object).
		Build()

	if err != nil {
		return err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return err
	}

	res, ok := cmd.(*riak.StoreValueCommand)

	if !ok {
		return errors.New("Unable to parse response from Riak")
	}

	if !res.Success() {
		return errors.New("Riak command was not successful")
	}

	return nil
}

// GetJSON is the same as GetRaw, but with automatic JSON unmarshalling
func (c *Client) GetJSON(bucket, bucketType, key string, value interface{}) (err error, isNotFound bool) {
	raw, err, isNotFound := c.GetRaw(bucket, bucketType, key)

	if err != nil {
		return err, isNotFound
	}

	err = json.Unmarshal(raw, value)

	if err != nil {
		return err, false
	}

	return nil, false
}

// GetRaw retuns the raw []byte array that is stored in Riak without any modifications
func (c *Client) GetRaw(bucket, bucketType, key string) (raw []byte, err error, isNotFound bool) {
	cmd, err := riak.NewFetchValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		Build()

	if err != nil {
		return raw, err, false
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return raw, err, false
	}

	res, ok := cmd.(*riak.FetchValueCommand)

	if !ok {
		return raw, errors.New("Unable to parse response from Riak"), false
	}

	if !res.Success() {
		return raw, errors.New("Riak command was not successful"), false
	}

	if res.Response.IsNotFound {
		return raw, errors.New("Not Found"), true
	}

	if len(res.Response.Values) != 1 {
		return raw, errors.New("Not Found"), false
	}

	return res.Response.Values[0].Value, nil, false
}

func (c *Client) Delete(bucket, bucketType, key string) error {
	cmd, err := riak.NewDeleteValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		Build()

	if err != nil {
		return err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return err
	}

	res, ok := cmd.(*riak.DeleteValueCommand)

	if !ok {
		return errors.New("Could not convert")
	}

	if !res.Success() {
		return errors.New("Command was not successful")
	}

	return nil
}

func (c *Client) AllKeys(bucket, bucketType string) ([]string, error) {
	cmd, err := riak.NewListKeysCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		Build()

	if err != nil {
		return []string{}, err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return []string{}, err
	}

	res, ok := cmd.(*riak.ListKeysCommand)

	if !ok {
		return []string{}, errors.New("Could not convert")
	}

	return res.Response.Keys, nil
}
<commit_msg>Value: Added optional value type to SetRaw() which enables setting indexes<commit_after>package goriak

import (
	"encoding/json"
	"errors"
	"reflect"

	riak "github.com/basho/riak-go-client"
)

// SetJSON saves value as key in the bucket bucket/bucketType
// Values can automatically be added to indexes with the struct tag goriakindex
func (c *Client) SetJSON(bucket, bucketType, key string, value interface{}) error {
	by, err := json.Marshal(value)

	if err != nil {
		return err
	}

	object := riak.Object{
		Value: by,
	}

	refType := reflect.TypeOf(value)
	refValue := reflect.ValueOf(value)

	if refType.Kind() == reflect.Struct {

		// Set indexes
		for i := 0; i < refType.NumField(); i++ {

			indexName := refType.Field(i).Tag.Get("goriakindex")

			if len(indexName) == 0 {
				continue
			}

			// String
			if refValue.Field(i).Type().Kind() == reflect.String {
				object.AddToIndex(indexName, refValue.Field(i).String())
				continue
			}

			// Slice
			if refValue.Field(i).Type().Kind() == reflect.Slice {

				sliceType := refValue.Field(i).Type().Elem()
				sliceValue := refValue.Field(i)

				// Slice: String
				if sliceType.Kind() == reflect.String {
					for sli := 0; sli < sliceValue.Len(); sli++ {
						object.AddToIndex(indexName, sliceValue.Index(sli).String())
					}

					continue
				}
			}

			return errors.New("Did not know how to set index: " + refType.Field(i).Name)
		}

	}

	cmd, err := riak.NewStoreValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		WithContent(&object).
		Build()

	if err != nil {
		return err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return err
	}

	res, ok := cmd.(*riak.StoreValueCommand)

	if !ok {
		return errors.New("Unable to parse response from Riak")
	}

	if !res.Success() {
		return errors.New("Riak command was not successful")
	}

	return nil
}

type Options struct {
	indexes map[string][]string
}

func (o *Options) AddToIndex(key, value string) *Options {

	// Create map if needed
	if o.indexes == nil {
		o.indexes = make(map[string][]string)
	}

	// Add to existing slice
	if _, ok := o.indexes[key]; ok {
		o.indexes[key] = append(o.indexes[key], value)
	}

	// Create new slice
	o.indexes[key] = []string{value}

	return o
}

// SetRaw saves the data in Riak directly without any modifications
func (c *Client) SetRaw(bucket, bucketType, key string, data []byte, opt *Options) error {
	object := riak.Object{
		Value: data,
	}

	// Add to indexes
	if opt != nil {
		for name, values := range opt.indexes {
			for _, val := range values {
				object.AddToIndex(name, val)
			}
		}
	}

	cmd, err := riak.NewStoreValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		WithContent(&object).
		Build()

	if err != nil {
		return err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return err
	}

	res, ok := cmd.(*riak.StoreValueCommand)

	if !ok {
		return errors.New("Unable to parse response from Riak")
	}

	if !res.Success() {
		return errors.New("Riak command was not successful")
	}

	return nil
}

// GetJSON is the same as GetRaw, but with automatic JSON unmarshalling
func (c *Client) GetJSON(bucket, bucketType, key string, value interface{}) (err error, isNotFound bool) {
	raw, err, isNotFound := c.GetRaw(bucket, bucketType, key)

	if err != nil {
		return err, isNotFound
	}

	err = json.Unmarshal(raw, value)

	if err != nil {
		return err, false
	}

	return nil, false
}

// GetRaw retuns the raw []byte array that is stored in Riak without any modifications
func (c *Client) GetRaw(bucket, bucketType, key string) (raw []byte, err error, isNotFound bool) {
	cmd, err := riak.NewFetchValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		Build()

	if err != nil {
		return raw, err, false
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return raw, err, false
	}

	res, ok := cmd.(*riak.FetchValueCommand)

	if !ok {
		return raw, errors.New("Unable to parse response from Riak"), false
	}

	if !res.Success() {
		return raw, errors.New("Riak command was not successful"), false
	}

	if res.Response.IsNotFound {
		return raw, errors.New("Not Found"), true
	}

	if len(res.Response.Values) != 1 {
		return raw, errors.New("Not Found"), false
	}

	return res.Response.Values[0].Value, nil, false
}

func (c *Client) Delete(bucket, bucketType, key string) error {
	cmd, err := riak.NewDeleteValueCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		WithKey(key).
		Build()

	if err != nil {
		return err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return err
	}

	res, ok := cmd.(*riak.DeleteValueCommand)

	if !ok {
		return errors.New("Could not convert")
	}

	if !res.Success() {
		return errors.New("Command was not successful")
	}

	return nil
}

func (c *Client) AllKeys(bucket, bucketType string) ([]string, error) {
	cmd, err := riak.NewListKeysCommandBuilder().
		WithBucket(bucket).
		WithBucketType(bucketType).
		Build()

	if err != nil {
		return []string{}, err
	}

	err = c.riak.Execute(cmd)

	if err != nil {
		return []string{}, err
	}

	res, ok := cmd.(*riak.ListKeysCommand)

	if !ok {
		return []string{}, errors.New("Could not convert")
	}

	return res.Response.Keys, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package vm

import (
	"errors"
	"fmt"
	"regexp"
	"time"
)

// Instance represents a Linux VM or a remote physical machine.
type Instance interface {
	// Copy copies a hostSrc file into vm and returns file name in vm.
	Copy(hostSrc string) (string, error)

	// Forward setups forwarding from within VM to host port port
	// and returns address to use in VM.
	Forward(port int) (string, error)

	// Run runs cmd inside of the VM (think of ssh cmd).
	// outc receives combined cmd and kernel console output.
	// errc receives either command Wait return error or vm.TimeoutErr.
	Run(timeout time.Duration, command string) (outc <-chan []byte, errc <-chan error, err error)

	// Close stops and destroys the VM.
	Close()
}

type Config struct {
	Name       string
	Index      int
	Workdir    string
	Bin        string
	Kernel     string
	Cmdline    string
	Image      string
	Sshkey     string
	ConsoleDev string
	Cpu        int
	Mem        int
	Debug      bool
}

type ctorFunc func(cfg *Config) (Instance, error)

var ctors = make(map[string]ctorFunc)

func Register(typ string, ctor ctorFunc) {
	ctors[typ] = ctor
}

// Create creates and boots a new VM instance.
func Create(typ string, cfg *Config) (Instance, error) {
	ctor := ctors[typ]
	if ctor == nil {
		return nil, fmt.Errorf("unknown instance type '%v'", typ)
	}
	return ctor(cfg)
}

var (
	CrashRe    = regexp.MustCompile("Kernel panic[^\r\n]*|BUG:[^\r\n]*|kernel BUG[^\r\n]*|WARNING:[^\r\n]*|" +
		"INFO:[^\r\n]*|unable to handle|Unable to handle kernel[^\r\n]*|general protection fault|UBSAN:[^\r\n]*|" +
		"unreferenced object[^\r\n]*")
	TimeoutErr = errors.New("timeout")
)
<commit_msg>vm: reformat<commit_after>// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package vm

import (
	"errors"
	"fmt"
	"regexp"
	"time"
)

// Instance represents a Linux VM or a remote physical machine.
type Instance interface {
	// Copy copies a hostSrc file into vm and returns file name in vm.
	Copy(hostSrc string) (string, error)

	// Forward setups forwarding from within VM to host port port
	// and returns address to use in VM.
	Forward(port int) (string, error)

	// Run runs cmd inside of the VM (think of ssh cmd).
	// outc receives combined cmd and kernel console output.
	// errc receives either command Wait return error or vm.TimeoutErr.
	Run(timeout time.Duration, command string) (outc <-chan []byte, errc <-chan error, err error)

	// Close stops and destroys the VM.
	Close()
}

type Config struct {
	Name       string
	Index      int
	Workdir    string
	Bin        string
	Kernel     string
	Cmdline    string
	Image      string
	Sshkey     string
	ConsoleDev string
	Cpu        int
	Mem        int
	Debug      bool
}

type ctorFunc func(cfg *Config) (Instance, error)

var ctors = make(map[string]ctorFunc)

func Register(typ string, ctor ctorFunc) {
	ctors[typ] = ctor
}

// Create creates and boots a new VM instance.
func Create(typ string, cfg *Config) (Instance, error) {
	ctor := ctors[typ]
	if ctor == nil {
		return nil, fmt.Errorf("unknown instance type '%v'", typ)
	}
	return ctor(cfg)
}

var (
	CrashRe = regexp.MustCompile("Kernel panic[^\r\n]*|BUG:[^\r\n]*|kernel BUG[^\r\n]*|WARNING:[^\r\n]*|" +
		"INFO:[^\r\n]*|unable to handle|Unable to handle kernel[^\r\n]*|general protection fault|UBSAN:[^\r\n]*|" +
		"unreferenced object[^\r\n]*")
	TimeoutErr = errors.New("timeout")
)
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"reflect"
	"runtime"
	"sync"
	"text/template"
	"time"

	"github.com/armon/consul-api"
)

const (
	// failSleep controls how long to sleep on a failure
	failSleep = 5 * time.Second

	// maxFailures controls the maximum number of failures
	// before we limit the sleep value
	maxFailures = 3

	// waitTime is used to control how long we do a blocking
	// query for
	waitTime = 60 * time.Second
)

type backendData struct {
	sync.Mutex

	// Client is a shared Consul client
	Client *consulapi.Client

	// Servers maps each watch path to a list of entries
	Servers map[*WatchPath][]*consulapi.ServiceEntry

	// Backends maps a backend to a list of watch paths used
	// to build up the server list
	Backends map[string][]*WatchPath

	// ChangeCh is used to inform of an update
	ChangeCh chan struct{}

	// StopCh is used to trigger a stop
	StopCh chan struct{}
}

// watch is used to start a long running watcher to handle updates.
// Returns a stopCh, and a finishCh.
func watch(conf *Config) (chan struct{}, chan struct{}) {
	stopCh := make(chan struct{})
	finishCh := make(chan struct{})
	go runWatch(conf, stopCh, finishCh)
	return stopCh, finishCh
}

// runWatch is a long running routine that watches with a
// given configuration
func runWatch(conf *Config, stopCh, doneCh chan struct{}) {
	defer close(doneCh)

	// Create the consul client
	consulConf := consulapi.DefaultConfig()
	if conf.Address != "" {
		consulConf.Address = conf.Address
	}

	// Attempt to contact the agent
	client, err := consulapi.NewClient(consulConf)
	if err != nil {
		log.Printf("[ERR] Failed to initialize consul client: %v", err)
		return
	}
	if _, err := client.Agent().NodeName(); err != nil {
		log.Printf("[ERR] Failed to contact consul agent: %v", err)
		return
	}

	// Create a backend store
	data := &backendData{
		Client:   client,
		Servers:  make(map[*WatchPath][]*consulapi.ServiceEntry),
		Backends: make(map[string][]*WatchPath),
		ChangeCh: make(chan struct{}, 1),
		StopCh:   stopCh,
	}

	// Start the watches
	data.Lock()
	for _, watch := range conf.watches {
		data.Backends[watch.Backend] = append(data.Backends[watch.Backend], watch)
		go runSingleWatch(conf, data, watch)
	}
	data.Unlock()

	// Monitor for changes or stop
	for {
		select {
		case <-data.ChangeCh:
			if maybeRefresh(conf, data) {
				return
			}

		case <-stopCh:
			return
		}
	}
}

// maybeRefresh is used to handle a potential config update
func maybeRefresh(conf *Config, data *backendData) (exit bool) {
	// Ignore initial updates until all the data is ready
	data.Lock()
	num := len(data.Servers)
	data.Unlock()
	if num < len(conf.watches) {
		return
	}

	// Merge the data for each backend
	backendServers := make(map[string][]*consulapi.ServiceEntry)
	data.Lock()
	for backend, watches := range data.Backends {
		var all []*consulapi.ServiceEntry
		for _, watch := range watches {
			entries := data.Servers[watch]
			all = append(all, entries...)
		}
		backendServers[backend] = all
	}
	data.Unlock()

	// Format the output
	outVars := formatOutput(backendServers)

	// Read the template
	raw, err := ioutil.ReadFile(conf.Template)
	if err != nil {
		log.Printf("[ERR] Failed to read template: %v", err)
		return true
	}

	// Create the template
	templ, err := template.New("output").Parse(string(raw))
	if err != nil {
		log.Printf("[ERR] Failed to parse the template: %v", err)
		return true
	}

	// Generate the output
	var output bytes.Buffer
	if err := templ.Execute(&output, outVars); err != nil {
		log.Printf("[ERR] Failed to generate the template: %v", err)
		return true
	}

	// Check for a dry run
	if conf.DryRun {
		fmt.Printf("%s\n", output.Bytes())
		return true
	}

	// Write out the configuration
	if err := ioutil.WriteFile(conf.Path, output.Bytes(), 0660); err != nil {
		log.Printf("[ERR] Failed to write config file: %v", err)
		return true
	}
	log.Printf("[INFO] Updated configuration file at %s", conf.Path)

	// Invoke the reload hook
	if err := reload(conf); err != nil {
		log.Printf("[ERR] Failed to reload: %v", err)
	} else {
		log.Printf("[INFO] Completed reload")
	}
	return
}

// runSingleWatch is used to query a single watch path for changes
func runSingleWatch(conf *Config, data *backendData, watch *WatchPath) {
	health := data.Client.Health()
	opts := &consulapi.QueryOptions{
		WaitTime: waitTime,
	}
	if watch.Datacenter != "" {
		opts.Datacenter = watch.Datacenter
	}

	failures := 0
	for {
		if shouldStop(data.StopCh) {
			return
		}
		entries, qm, err := health.Service(watch.Service, watch.Tag, true, opts)
		if err != nil {
			log.Printf("[ERR] Failed to fetch service nodes: %v", err)
		}

		// Fixup the ports if necessary
		if watch.Port != 0 {
			for _, entry := range entries {
				if entry.Service.Port == 0 {
					entry.Service.Port = watch.Port
				}
			}
		}

		// Update the entries. If this is the first read, do it on error
		data.Lock()
		old, ok := data.Servers[watch]
		if !ok || (err == nil && !reflect.DeepEqual(old, entries)) {
			data.Servers[watch] = entries
			asyncNotify(data.ChangeCh)
			if !conf.DryRun {
				log.Printf("[DEBUG] Updated nodes for %v", watch.Spec)
			}
		}
		data.Unlock()

		// Stop immediately on a dry run
		if conf.DryRun {
			return
		}

		// Check for an error
		if err != nil {
			failures = min(failures+1, maxFailures)
			time.Sleep(backoff(failSleep, failures))
		} else {
			failures = 0
			opts.WaitIndex = qm.LastIndex
		}
	}
}

// reload is used to invoke the reload command
func reload(conf *Config) error {
	// Determine the shell invocation based on OS
	var shell, flag string
	if runtime.GOOS == "windows" {
		shell = "cmd"
		flag = "/C"
	} else {
		shell = "/bin/sh"
		flag = "-c"
	}

	// Create and invoke the command
	cmd := exec.Command(shell, flag, conf.ReloadCommand)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// shouldStop checks for a closed control channel
func shouldStop(ch chan struct{}) bool {
	select {
	case <-ch:
		return true
	default:
		return false
	}
}

// asyncNotify is used to notify a channel
func asyncNotify(ch chan struct{}) {
	select {
	case ch <- struct{}{}:
	default:
	}
}

// min returns the min of two ints
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// backoff is used to compute an exponential backoff
func backoff(interval time.Duration, times int) time.Duration {
	base := interval
	for ; times > 1; times-- {
		base *= interval
	}
	return interval
}

// formatOutput converts the service entries into a format
// suitable for templating into the HAProxy file
func formatOutput(inp map[string][]*consulapi.ServiceEntry) map[string][]string {
	out := make(map[string][]string)
	for backend, entries := range inp {
		servers := make([]string, len(entries))
		for idx, entry := range entries {
			// TODO: Avoid multi-DC name conflict
			name := fmt.Sprintf("%s_%s", entry.Node.Node, entry.Service.ID)
			ip := net.ParseIP(entry.Node.Address)
			addr := &net.TCPAddr{IP: ip, Port: entry.Service.Port}
			servers[idx] = fmt.Sprintf("server %s %s", name, addr)
		}
		out[backend] = servers
	}
	return out
}
<commit_msg>Fix potential name collisions<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"os"
	"os/exec"
	"reflect"
	"runtime"
	"sync"
	"text/template"
	"time"

	"github.com/armon/consul-api"
)

const (
	// failSleep controls how long to sleep on a failure
	failSleep = 5 * time.Second

	// maxFailures controls the maximum number of failures
	// before we limit the sleep value
	maxFailures = 3

	// waitTime is used to control how long we do a blocking
	// query for
	waitTime = 60 * time.Second
)

type backendData struct {
	sync.Mutex

	// Client is a shared Consul client
	Client *consulapi.Client

	// Servers maps each watch path to a list of entries
	Servers map[*WatchPath][]*consulapi.ServiceEntry

	// Backends maps a backend to a list of watch paths used
	// to build up the server list
	Backends map[string][]*WatchPath

	// ChangeCh is used to inform of an update
	ChangeCh chan struct{}

	// StopCh is used to trigger a stop
	StopCh chan struct{}
}

// watch is used to start a long running watcher to handle updates.
// Returns a stopCh, and a finishCh.
func watch(conf *Config) (chan struct{}, chan struct{}) {
	stopCh := make(chan struct{})
	finishCh := make(chan struct{})
	go runWatch(conf, stopCh, finishCh)
	return stopCh, finishCh
}

// runWatch is a long running routine that watches with a
// given configuration
func runWatch(conf *Config, stopCh, doneCh chan struct{}) {
	defer close(doneCh)

	// Create the consul client
	consulConf := consulapi.DefaultConfig()
	if conf.Address != "" {
		consulConf.Address = conf.Address
	}

	// Attempt to contact the agent
	client, err := consulapi.NewClient(consulConf)
	if err != nil {
		log.Printf("[ERR] Failed to initialize consul client: %v", err)
		return
	}
	if _, err := client.Agent().NodeName(); err != nil {
		log.Printf("[ERR] Failed to contact consul agent: %v", err)
		return
	}

	// Create a backend store
	data := &backendData{
		Client:   client,
		Servers:  make(map[*WatchPath][]*consulapi.ServiceEntry),
		Backends: make(map[string][]*WatchPath),
		ChangeCh: make(chan struct{}, 1),
		StopCh:   stopCh,
	}

	// Start the watches
	data.Lock()
	for idx, watch := range conf.watches {
		data.Backends[watch.Backend] = append(data.Backends[watch.Backend], watch)
		go runSingleWatch(conf, data, idx, watch)
	}
	data.Unlock()

	// Monitor for changes or stop
	for {
		select {
		case <-data.ChangeCh:
			if maybeRefresh(conf, data) {
				return
			}

		case <-stopCh:
			return
		}
	}
}

// maybeRefresh is used to handle a potential config update
func maybeRefresh(conf *Config, data *backendData) (exit bool) {
	// Ignore initial updates until all the data is ready
	data.Lock()
	num := len(data.Servers)
	data.Unlock()
	if num < len(conf.watches) {
		return
	}

	// Merge the data for each backend
	backendServers := make(map[string][]*consulapi.ServiceEntry)
	data.Lock()
	for backend, watches := range data.Backends {
		var all []*consulapi.ServiceEntry
		for _, watch := range watches {
			entries := data.Servers[watch]
			all = append(all, entries...)
		}
		backendServers[backend] = all
	}
	data.Unlock()

	// Format the output
	outVars := formatOutput(backendServers)

	// Read the template
	raw, err := ioutil.ReadFile(conf.Template)
	if err != nil {
		log.Printf("[ERR] Failed to read template: %v", err)
		return true
	}

	// Create the template
	templ, err := template.New("output").Parse(string(raw))
	if err != nil {
		log.Printf("[ERR] Failed to parse the template: %v", err)
		return true
	}

	// Generate the output
	var output bytes.Buffer
	if err := templ.Execute(&output, outVars); err != nil {
		log.Printf("[ERR] Failed to generate the template: %v", err)
		return true
	}

	// Check for a dry run
	if conf.DryRun {
		fmt.Printf("%s\n", output.Bytes())
		return true
	}

	// Write out the configuration
	if err := ioutil.WriteFile(conf.Path, output.Bytes(), 0660); err != nil {
		log.Printf("[ERR] Failed to write config file: %v", err)
		return true
	}
	log.Printf("[INFO] Updated configuration file at %s", conf.Path)

	// Invoke the reload hook
	if err := reload(conf); err != nil {
		log.Printf("[ERR] Failed to reload: %v", err)
	} else {
		log.Printf("[INFO] Completed reload")
	}
	return
}

// runSingleWatch is used to query a single watch path for changes
func runSingleWatch(conf *Config, data *backendData, idx int, watch *WatchPath) {
	health := data.Client.Health()
	opts := &consulapi.QueryOptions{
		WaitTime: waitTime,
	}
	if watch.Datacenter != "" {
		opts.Datacenter = watch.Datacenter
	}

	failures := 0
	for {
		if shouldStop(data.StopCh) {
			return
		}
		entries, qm, err := health.Service(watch.Service, watch.Tag, true, opts)
		if err != nil {
			log.Printf("[ERR] Failed to fetch service nodes: %v", err)
		}

		// Patch the entries as necessary
		for _, entry := range entries {
			// Modify the node name to prefix with the watch ID. This
			// prevents a name conflict on duplicate names
			entry.Node.Node = fmt.Sprintf("%d_%s", idx, entry.Node.Node)

			// Patch the port if provided and the service hasn't registered
			if watch.Port != 0 && entry.Service.Port == 0 {
				entry.Service.Port = watch.Port
			}
		}

		// Update the entries. If this is the first read, do it on error
		data.Lock()
		old, ok := data.Servers[watch]
		if !ok || (err == nil && !reflect.DeepEqual(old, entries)) {
			data.Servers[watch] = entries
			asyncNotify(data.ChangeCh)
			if !conf.DryRun {
				log.Printf("[DEBUG] Updated nodes for %v", watch.Spec)
			}
		}
		data.Unlock()

		// Stop immediately on a dry run
		if conf.DryRun {
			return
		}

		// Check for an error
		if err != nil {
			failures = min(failures+1, maxFailures)
			time.Sleep(backoff(failSleep, failures))
		} else {
			failures = 0
			opts.WaitIndex = qm.LastIndex
		}
	}
}

// reload is used to invoke the reload command
func reload(conf *Config) error {
	// Determine the shell invocation based on OS
	var shell, flag string
	if runtime.GOOS == "windows" {
		shell = "cmd"
		flag = "/C"
	} else {
		shell = "/bin/sh"
		flag = "-c"
	}

	// Create and invoke the command
	cmd := exec.Command(shell, flag, conf.ReloadCommand)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// shouldStop checks for a closed control channel
func shouldStop(ch chan struct{}) bool {
	select {
	case <-ch:
		return true
	default:
		return false
	}
}

// asyncNotify is used to notify a channel
func asyncNotify(ch chan struct{}) {
	select {
	case ch <- struct{}{}:
	default:
	}
}

// min returns the min of two ints
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

// backoff is used to compute an exponential backoff
func backoff(interval time.Duration, times int) time.Duration {
	base := interval
	for ; times > 1; times-- {
		base *= interval
	}
	return interval
}

// formatOutput converts the service entries into a format
// suitable for templating into the HAProxy file
func formatOutput(inp map[string][]*consulapi.ServiceEntry) map[string][]string {
	out := make(map[string][]string)
	for backend, entries := range inp {
		servers := make([]string, len(entries))
		for idx, entry := range entries {
			name := fmt.Sprintf("%s_%s", entry.Node.Node, entry.Service.ID)
			ip := net.ParseIP(entry.Node.Address)
			addr := &net.TCPAddr{IP: ip, Port: entry.Service.Port}
			servers[idx] = fmt.Sprintf("server %s %s", name, addr)
		}
		out[backend] = servers
	}
	return out
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/codegangsta/cli"
	mp "github.com/mackerelio/go-mackerel-plugin"
)

// metric value structure
var graphdef map[string](mp.Graphs) = map[string](mp.Graphs){
	"php-apc.purges": mp.Graphs{
		Label: "PHP APC Purge Count",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cache_full_count", Label: "File Cache", Diff: true, Stacked: false},
			mp.Metrics{Name: "user_cache_full_count", Label: "User Cache", Diff: true, Stacked: false},
		},
	},
	"php-apc.stats": mp.Graphs{
		Label: "PHP APC File Cache Statistics",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cache_hits", Label: "Hits", Diff: true, Stacked: false},
			mp.Metrics{Name: "cache_misses", Label: "Misses", Diff: true, Stacked: false},
		},
	},
	"php-apc.cache_size": mp.Graphs{
		Label: "PHP APC Cache Size",
		Unit:  "float",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cached_files_size", Label: "File Cache", Diff: false, Stacked: true},
			mp.Metrics{Name: "user_cache_vars_size", Label: "User Cache", Diff: false, Stacked: true},
			mp.Metrics{Name: "total_memory", Label: "Total", Diff: false, Stacked: false},
		},
	},
	"php-apc.user_stats": mp.Graphs{
		Label: "PHP APC User Cache Statistics",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "user_cache_hits", Label: "Hits", Diff: true, Stacked: false},
			mp.Metrics{Name: "user_cache_misses", Label: "Misses", Diff: true, Stacked: false},
		},
	},
}

// for fetching metrics
type PhpApcPlugin struct {
	Host     string
	Port     uint16
	Path     string
	Tempfile string
}

// Graph definition
func (c PhpApcPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

// main function
func doMain(c *cli.Context) {

	var phpapc PhpApcPlugin

	phpapc.Host = c.String("http_host")
	phpapc.Port = uint16(c.Int("http_port"))
	phpapc.Path = c.String("status_page")

	helper := mp.NewMackerelPlugin(phpapc)
	helper.Tempfile = c.String("tempfile")

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}

// fetch metrics
func (c PhpApcPlugin) FetchMetrics() (map[string]float64, error) {
	data, err := getPhpApcMetrics(c.Host, c.Port, c.Path)
	if err != nil {
		return nil, err
	}

	stat := make(map[string]float64)
	err_stat := parsePhpApcStatus(data, &stat)
	if err_stat != nil {
		return nil, err_stat
	}

	return stat, nil
}

// parsing metrics from server-status?auto
func parsePhpApcStatus(str string, p *map[string]float64) error {
	for _, line := range strings.Split(str, "\n") {
		record := strings.Split(line, ":")
		if len(record) != 2 {
			continue
		}
		var err_parse error
		(*p)[record[0]], err_parse = strconv.ParseFloat(strings.Trim(record[1], " "), 64)
		if err_parse != nil {
			return err_parse
		}
	}

	if len(*p) == 0 {
		return errors.New("Status data not found.")
	}

	return nil
}

// Getting php-apc status from server-status module data.
func getPhpApcMetrics(host string, port uint16, path string) (string, error) {
	uri := "http://" + host + ":" + strconv.FormatUint(uint64(port), 10) + path
	resp, err := http.Get(uri)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != http.StatusOK {
		return "", errors.New(fmt.Sprintf("HTTP status error: %d", resp.StatusCode))
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return "", err
	}
	return string(body[:]), nil
}

// main
func main() {
	app := cli.NewApp()
	app.Name = "php-apc_metrics"
	app.Version = Version
	app.Usage = "Get metrics from php-apc."
	app.Author = "Yuichiro Saito"
	app.Email = "saito@heartbeats.jp"
	app.Flags = Flags
	app.Action = doMain

	app.Run(os.Args)
}
<commit_msg>Change unit.<commit_after>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"

	"github.com/codegangsta/cli"
	mp "github.com/mackerelio/go-mackerel-plugin"
)

// metric value structure
var graphdef map[string](mp.Graphs) = map[string](mp.Graphs){
	"php-apc.purges": mp.Graphs{
		Label: "PHP APC Purge Count",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cache_full_count", Label: "File Cache", Diff: true, Stacked: false},
			mp.Metrics{Name: "user_cache_full_count", Label: "User Cache", Diff: true, Stacked: false},
		},
	},
	"php-apc.stats": mp.Graphs{
		Label: "PHP APC File Cache Statistics",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cache_hits", Label: "Hits", Diff: true, Stacked: false},
			mp.Metrics{Name: "cache_misses", Label: "Misses", Diff: true, Stacked: false},
		},
	},
	"php-apc.cache_size": mp.Graphs{
		Label: "PHP APC Cache Size",
		Unit:  "bytes",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "cached_files_size", Label: "File Cache", Diff: false, Stacked: true},
			mp.Metrics{Name: "user_cache_vars_size", Label: "User Cache", Diff: false, Stacked: true},
			mp.Metrics{Name: "total_memory", Label: "Total", Diff: false, Stacked: false},
		},
	},
	"php-apc.user_stats": mp.Graphs{
		Label: "PHP APC User Cache Statistics",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "user_cache_hits", Label: "Hits", Diff: true, Stacked: false},
			mp.Metrics{Name: "user_cache_misses", Label: "Misses", Diff: true, Stacked: false},
		},
	},
}

// for fetching metrics
type PhpApcPlugin struct {
	Host     string
	Port     uint16
	Path     string
	Tempfile string
}

// Graph definition
func (c PhpApcPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

// main function
func doMain(c *cli.Context) {

	var phpapc PhpApcPlugin

	phpapc.Host = c.String("http_host")
	phpapc.Port = uint16(c.Int("http_port"))
	phpapc.Path = c.String("status_page")

	helper := mp.NewMackerelPlugin(phpapc)
	helper.Tempfile = c.String("tempfile")

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}

// fetch metrics
func (c PhpApcPlugin) FetchMetrics() (map[string]float64, error) {
	data, err := getPhpApcMetrics(c.Host, c.Port, c.Path)
	if err != nil {
		return nil, err
	}

	stat := make(map[string]float64)
	err_stat := parsePhpApcStatus(data, &stat)
	if err_stat != nil {
		return nil, err_stat
	}

	return stat, nil
}

// parsing metrics from server-status?auto
func parsePhpApcStatus(str string, p *map[string]float64) error {
	for _, line := range strings.Split(str, "\n") {
		record := strings.Split(line, ":")
		if len(record) != 2 {
			continue
		}
		var err_parse error
		(*p)[record[0]], err_parse = strconv.ParseFloat(strings.Trim(record[1], " "), 64)
		if err_parse != nil {
			return err_parse
		}
	}

	if len(*p) == 0 {
		return errors.New("Status data not found.")
	}

	return nil
}

// Getting php-apc status from server-status module data.
func getPhpApcMetrics(host string, port uint16, path string) (string, error) {
	uri := "http://" + host + ":" + strconv.FormatUint(uint64(port), 10) + path
	resp, err := http.Get(uri)
	if err != nil {
		return "", err
	}
	if resp.StatusCode != http.StatusOK {
		return "", errors.New(fmt.Sprintf("HTTP status error: %d", resp.StatusCode))
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return "", err
	}
	return string(body[:]), nil
}

// main
func main() {
	app := cli.NewApp()
	app.Name = "php-apc_metrics"
	app.Version = Version
	app.Usage = "Get metrics from php-apc."
	app.Author = "Yuichiro Saito"
	app.Email = "saito@heartbeats.jp"
	app.Flags = Flags
	app.Action = doMain

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"

	"os"

	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

var graphdef = map[string](mp.Graphs){
	"unicorn.memory": mp.Graphs{
		Label: "Unicorn Memory",
		Unit:  "bytes",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "memory_workers", Label: "Workers", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_master", Label: "Master", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_workeravg", Label: "Worker Average", Diff: false, Stacked: false},
		},
	},
	"unicorn.workers": mp.Graphs{
		Label: "Unicorn Workers",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "worker_total", Label: "Worker Total", Diff: false, Stacked: false},
			mp.Metrics{Name: "worker_idles", Label: "Worker Idles", Diff: false, Stacked: false},
		},
	},
}

// UnicornPlugin mackerel plugin for Unicorn
type UnicornPlugin struct {
	MasterPid  string
	WorkerPids []string
	Tempfile   string
}

// FetchMetrics interface for mackerelplugin
func (u UnicornPlugin) FetchMetrics() (map[string]interface{}, error) {
	stat := make(map[string]interface{})

	workers := len(u.WorkerPids)
	stat["worker_total"] = fmt.Sprint(workers)

	idles, err := idleWorkerCount(u.WorkerPids)
	if err != nil {
		return stat, err
	}
	stat["worker_idles"] = fmt.Sprint(idles)

	workersM, err := workersMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_workers"] = workersM

	masterM, err := masterMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_master"] = masterM

	averageM, err := workersMemoryAvg()
	if err != nil {
		return stat, err
	}
	stat["memory_workeravg"] = averageM

	return stat, nil
}

// GraphDefinition interface for mackerelplugin
func (n UnicornPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

func main() {
	optPidFile := flag.String("pidfile", "", "Pid file name")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()
	var unicorn UnicornPlugin

	command = RealCommand{}
	pipedCommands = RealPipedCommands{}

	if *optPidFile == "" {
		fmt.Errorf("Required unicorn pidfile.")
		os.Exit(1)
	} else {
		pid, err := ioutil.ReadFile(*optPidFile)
		if err != nil {
			fmt.Errorf("Failed to load unicorn pid file. %s", err)
			os.Exit(1)
		}
		unicorn.MasterPid = strings.Replace(string(pid), "\n", "", 1)
	}

	workerPids, err := fetchUnicornWorkerPids(unicorn.MasterPid)
	if err != nil {
		fmt.Errorf("Failed to fetch unicorn worker pids. %s", err)
		os.Exit(1)
	}
	unicorn.WorkerPids = workerPids

	helper := mp.NewMackerelPlugin(unicorn)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-unicorn")
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<commit_msg>use mackerel-agent/logging<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"

	"os"

	"strings"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/mackerelio/mackerel-agent/logging"
)

var logger = logging.GetLogger("metrics.plugin.unicorn")

var graphdef = map[string](mp.Graphs){
	"unicorn.memory": mp.Graphs{
		Label: "Unicorn Memory",
		Unit:  "bytes",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "memory_workers", Label: "Workers", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_master", Label: "Master", Diff: false, Stacked: true},
			mp.Metrics{Name: "memory_workeravg", Label: "Worker Average", Diff: false, Stacked: false},
		},
	},
	"unicorn.workers": mp.Graphs{
		Label: "Unicorn Workers",
		Unit:  "integer",
		Metrics: [](mp.Metrics){
			mp.Metrics{Name: "worker_total", Label: "Worker Total", Diff: false, Stacked: false},
			mp.Metrics{Name: "worker_idles", Label: "Worker Idles", Diff: false, Stacked: false},
		},
	},
}

// UnicornPlugin mackerel plugin for Unicorn
type UnicornPlugin struct {
	MasterPid  string
	WorkerPids []string
	Tempfile   string
}

// FetchMetrics interface for mackerelplugin
func (u UnicornPlugin) FetchMetrics() (map[string]interface{}, error) {
	stat := make(map[string]interface{})

	workers := len(u.WorkerPids)
	stat["worker_total"] = fmt.Sprint(workers)

	idles, err := idleWorkerCount(u.WorkerPids)
	if err != nil {
		return stat, err
	}
	stat["worker_idles"] = fmt.Sprint(idles)

	workersM, err := workersMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_workers"] = workersM

	masterM, err := masterMemory()
	if err != nil {
		return stat, err
	}
	stat["memory_master"] = masterM

	averageM, err := workersMemoryAvg()
	if err != nil {
		return stat, err
	}
	stat["memory_workeravg"] = averageM

	return stat, nil
}

// GraphDefinition interface for mackerelplugin
func (n UnicornPlugin) GraphDefinition() map[string](mp.Graphs) {
	return graphdef
}

func main() {
	optPidFile := flag.String("pidfile", "", "Pid file name")
	optTempfile := flag.String("tempfile", "", "Temp file name")
	flag.Parse()
	var unicorn UnicornPlugin

	command = RealCommand{}
	pipedCommands = RealPipedCommands{}

	if *optPidFile == "" {
		logger.Errorf("Required unicorn pidfile.")
		os.Exit(1)
	} else {
		pid, err := ioutil.ReadFile(*optPidFile)
		if err != nil {
			logger.Errorf("Failed to load unicorn pid file. %s", err)
			os.Exit(1)
		}
		unicorn.MasterPid = strings.Replace(string(pid), "\n", "", 1)
	}

	workerPids, err := fetchUnicornWorkerPids(unicorn.MasterPid)
	if err != nil {
		logger.Errorf("Failed to fetch unicorn worker pids. %s", err)
		os.Exit(1)
	}
	unicorn.WorkerPids = workerPids

	helper := mp.NewMackerelPlugin(unicorn)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-unicorn")
	}

	if os.Getenv("MACKEREL_AGENT_PLUGIN_META") != "" {
		helper.OutputDefinitions()
	} else {
		helper.OutputValues()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
	"github.com/robfig/cron"
	"github.com/zlisthq/zlistutil"
	"html/template"
	"log"
	"net/http"
	"os"
	"time"
)

const (
	Num         int = 10
	CacheExpire int = 60 * 30
)

var (
	conn, err = redis.Dial("tcp", os.Getenv("REDIS_PORT_6379_TCP_ADDR")+":"+os.Getenv("REDIS_PORT_6379_TCP_PORT"))
)

func perror(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
func ServeStatic(router *mux.Router, staticDirectory string) {
	staticPaths := map[string]string{
		"css":    staticDirectory + "/css/",
		"js":     staticDirectory + "/js/",
		"images": staticDirectory + "/images/"}

	for pathName, pathValue := range staticPaths {
		pathPrefix := "/" + pathName + "/"
		router.PathPrefix(pathPrefix).Handler(http.StripPrefix(pathPrefix, http.FileServer(http.Dir(pathValue))))
	}
}

func getJSONStringCached(site string, url string, num int) string {
	if conn == nil {
		return getJSONString(site, url, num)
	}
	jsonString, err := redis.String(conn.Do("GET", url))
	if err != nil {
		jsonString = getJSONString(site, url, num)
		conn.Do("SETEX", url, "300", jsonString)
		log.Println("Cache: set " + url)
	}
	return jsonString
}

func Index(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/index.html")
	perror(err)
	err = t.Execute(w, nil)
	perror(err)
}

func getJSONString(site string, url string, num int) string {
	var items []zlistutil.Item
	items = zlistutil.GetItem(site, url, num)
	json_items, err := json.Marshal(&items)
	perror(err)
	return string(json_items)
}

func V2ex(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	listName := vars["list_name"]
	var url string
	if listName == "hot" || listName == "latest" {
		url = zlistutil.V2EX_BASE_URL + listName + ".json"
	} else {
		http.NotFound(w, r)
		return
	}
	str := getJSONStringCached(zlistutil.SITE_V2EX, url, Num)
	fmt.Fprint(w, str)
	return
}
func ZhihuDaily(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_ZHIHUDAILY, zlistutil.DAILY_FETCH_NOW, Num)
	fmt.Fprint(w, str)
	return
}
func Next(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_NEXT, zlistutil.NEXT, Num)
	fmt.Fprint(w, str)
	return
}
func ProductHunt(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_PRODUCTHUNT, zlistutil.PRODUCTHUNT_TODAY, Num)
	fmt.Fprint(w, str)
	return
}
func HackerNews(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	listName := vars["list_name"]
	var url string
	if listName == "topstories" || listName == "newstories" || listName == "askstories" || listName == "showstories" {
		url = zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/" + listName + ".json"
	} else {
		http.NotFound(w, r)
		return
	}
	str := getJSONStringCached(zlistutil.SITE_HACKERNEWS, url, Num)
	fmt.Fprint(w, str)
	return
}
func Jianshu(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	listName := vars["list_name"]
	var url string
	if listName == "now" || listName == "weekly" || listName == "monthly" {
		url = zlistutil.JIANSHU_BASE_URL + "/trending/" + listName
	} else {
		http.NotFound(w, r)
		return
	}
	str := getJSONStringCached(zlistutil.SITE_JIANSHU, url, Num)
	fmt.Fprint(w, str)
	return
}
func Wanqu(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_WANQU, zlistutil.WANQU, Num)
	fmt.Fprint(w, str)
	return
}
func PingWestNews(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_PINGWEST, zlistutil.PINGWEST_NEWS, Num)
	fmt.Fprint(w, str)
	return
}
func Solidot(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_SOLIDOT, zlistutil.SOLIDOT, Num)
	fmt.Fprint(w, str)
	return
}
func Github(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_GITHUB, zlistutil.GITHUB, Num)
	fmt.Fprint(w, str)
	return
}
func DoubanMoment(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_DOUBANMOMENT, zlistutil.DOUBAN_MOMENT, Num)
	fmt.Fprint(w, str)
	return
}
func IfanrSurvey(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_IFANR, zlistutil.IFANR, Num)
	fmt.Fprint(w, str)
	return
}
func MindStore(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_MINDSTORE, zlistutil.MINDSTORE, Num)
	fmt.Fprint(w, str)
	return
}
func Kickstarter(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_KICKSTARTER, zlistutil.KICKSTARTER, Num)
	fmt.Fprint(w, str)
	return
}
func Refresh(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	refreshCache(true)
	str := "{'code':'OK'}"
	fmt.Fprint(w, str)
	return
}
func refreshCache(flag bool) {
	urlSite := map[string]string{
		zlistutil.V2EX_BASE_URL + "hot.json":                        zlistutil.SITE_V2EX,
		zlistutil.V2EX_BASE_URL + "latest.json":                     zlistutil.SITE_V2EX,
		zlistutil.DAILY_FETCH_NOW:                                   zlistutil.SITE_ZHIHUDAILY,
		zlistutil.NEXT:                                              zlistutil.SITE_NEXT,
		zlistutil.PRODUCTHUNT_TODAY:                                 zlistutil.SITE_PRODUCTHUNT,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/topstories.json":  zlistutil.SITE_HACKERNEWS,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/newstories.json":  zlistutil.SITE_HACKERNEWS,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/askstories.json":  zlistutil.SITE_HACKERNEWS,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/showstories.json": zlistutil.SITE_HACKERNEWS,
		zlistutil.JIANSHU_BASE_URL + "/trending/now":                zlistutil.SITE_JIANSHU,
		zlistutil.JIANSHU_BASE_URL + "/trending/weekly":             zlistutil.SITE_JIANSHU,
		zlistutil.JIANSHU_BASE_URL + "/trending/monthly":            zlistutil.SITE_JIANSHU,
		zlistutil.WANQU:                                             zlistutil.SITE_WANQU,
		zlistutil.PINGWEST_NEWS:                                     zlistutil.SITE_PINGWEST,
		zlistutil.SOLIDOT:                                           zlistutil.SITE_SOLIDOT,
		zlistutil.GITHUB:                                            zlistutil.SITE_GITHUB,
		zlistutil.DOUBAN_MOMENT:                                     zlistutil.SITE_DOUBANMOMENT,
		zlistutil.IFANR:                                             zlistutil.SITE_IFANR,
		zlistutil.MINDSTORE:                                         zlistutil.SITE_MINDSTORE,
		zlistutil.KICKSTARTER:                                       zlistutil.SITE_KICKSTARTER,
	}
	log.Println("start refresh...")
	log.Println(time.Now())
	log.Printf("Clean exist cache ? %t",flag)
	for url, site := range urlSite {
		if flag==true && conn!= nil{
			conn.Do("DEL", url)
		}
		getJSONStringCached(site, url, Num)
	}
	log.Println("stop refresh...")
}
func jobRefreshCache() {
	refreshCache(false)
}
func main() {
	c := cron.New()
	c.AddFunc("0 */15 * * * ?", jobRefreshCache)
	c.Start()
	log.Println("REDIS HOST:" + os.Getenv("REDIS_PORT_6379_TCP_ADDR"))
	log.Println("REDIS PORT:" + os.Getenv("REDIS_PORT_6379_TCP_PORT"))
	router := mux.NewRouter().StrictSlash(true)
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
	router.HandleFunc("/", Index)
	router.HandleFunc("/refresh", Refresh)
	router.HandleFunc("/producthunt/top", ProductHunt)
	router.HandleFunc("/jianshu/{list_name}", Jianshu)
	router.HandleFunc("/36kr/next", Next)
	router.HandleFunc("/hackernews/{list_name}", HackerNews)
	router.HandleFunc("/v2ex/{list_name}", V2ex)
	router.HandleFunc("/zhihudaily/latest", ZhihuDaily)
	router.HandleFunc("/wanqu/top", Wanqu)
	router.HandleFunc("/pingwest/news", PingWestNews)
	router.HandleFunc("/solidot/top", Solidot)
	router.HandleFunc("/github/top", Github)
	router.HandleFunc("/douban/moment", DoubanMoment)
	router.HandleFunc("/ifanr/survey", IfanrSurvey)
	router.HandleFunc("/mindstore/top", MindStore)
	router.HandleFunc("/kickstarter/latest", Kickstarter)
	log.Println(http.ListenAndServe(":8080", router))
}
<commit_msg>Fix bug<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
	"github.com/robfig/cron"
	"github.com/zlisthq/zlistutil"
	"html/template"
	"log"
	"net/http"
	"os"
	"time"
)

const (
	Num         int    = 10
	CacheExpire string = "1800"
)

var (
	conn, err = redis.Dial("tcp", os.Getenv("REDIS_PORT_6379_TCP_ADDR")+":"+os.Getenv("REDIS_PORT_6379_TCP_PORT"))
)

func perror(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
func ServeStatic(router *mux.Router, staticDirectory string) {
	staticPaths := map[string]string{
		"css":    staticDirectory + "/css/",
		"js":     staticDirectory + "/js/",
		"images": staticDirectory + "/images/"}

	for pathName, pathValue := range staticPaths {
		pathPrefix := "/" + pathName + "/"
		router.PathPrefix(pathPrefix).Handler(http.StripPrefix(pathPrefix, http.FileServer(http.Dir(pathValue))))
	}
}

func getJSONStringCached(site string, url string, num int) string {
	if conn == nil {
		return getJSONString(site, url, num)
	}
	jsonString, err := redis.String(conn.Do("GET", url))
	if err != nil {
		jsonString = getJSONString(site, url, num)
		conn.Do("SETEX", url, CacheExpire, jsonString)
		log.Println("Cache: set " + url)
	}
	return jsonString
}

func Index(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/index.html")
	perror(err)
	err = t.Execute(w, nil)
	perror(err)
}

func getJSONString(site string, url string, num int) string {
	var items []zlistutil.Item
	items = zlistutil.GetItem(site, url, num)
	json_items, err := json.Marshal(&items)
	perror(err)
	return string(json_items)
}

func V2ex(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	listName := vars["list_name"]
	var url string
	if listName == "hot" || listName == "latest" {
		url = zlistutil.V2EX_BASE_URL + listName + ".json"
	} else {
		http.NotFound(w, r)
		return
	}
	str := getJSONStringCached(zlistutil.SITE_V2EX, url, Num)
	fmt.Fprint(w, str)
	return
}
func ZhihuDaily(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_ZHIHUDAILY, zlistutil.DAILY_FETCH_NOW, Num)
	fmt.Fprint(w, str)
	return
}
func Next(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_NEXT, zlistutil.NEXT, Num)
	fmt.Fprint(w, str)
	return
}
func ProductHunt(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_PRODUCTHUNT, zlistutil.PRODUCTHUNT_TODAY, Num)
	fmt.Fprint(w, str)
	return
}
func HackerNews(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	listName := vars["list_name"]
	var url string
	if listName == "topstories" || listName == "newstories" || listName == "askstories" || listName == "showstories" {
		url = zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/" + listName + ".json"
	} else {
		http.NotFound(w, r)
		return
	}
	str := getJSONStringCached(zlistutil.SITE_HACKERNEWS, url, Num)
	fmt.Fprint(w, str)
	return
}
func Jianshu(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	vars := mux.Vars(r)
	listName := vars["list_name"]
	var url string
	if listName == "now" || listName == "weekly" || listName == "monthly" {
		url = zlistutil.JIANSHU_BASE_URL + "/trending/" + listName
	} else {
		http.NotFound(w, r)
		return
	}
	str := getJSONStringCached(zlistutil.SITE_JIANSHU, url, Num)
	fmt.Fprint(w, str)
	return
}
func Wanqu(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_WANQU, zlistutil.WANQU, Num)
	fmt.Fprint(w, str)
	return
}
func PingWestNews(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_PINGWEST, zlistutil.PINGWEST_NEWS, Num)
	fmt.Fprint(w, str)
	return
}
func Solidot(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_SOLIDOT, zlistutil.SOLIDOT, Num)
	fmt.Fprint(w, str)
	return
}
func Github(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_GITHUB, zlistutil.GITHUB, Num)
	fmt.Fprint(w, str)
	return
}
func DoubanMoment(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_DOUBANMOMENT, zlistutil.DOUBAN_MOMENT, Num)
	fmt.Fprint(w, str)
	return
}
func IfanrSurvey(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_IFANR, zlistutil.IFANR, Num)
	fmt.Fprint(w, str)
	return
}
func MindStore(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_MINDSTORE, zlistutil.MINDSTORE, Num)
	fmt.Fprint(w, str)
	return
}
func Kickstarter(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	str := getJSONStringCached(zlistutil.SITE_KICKSTARTER, zlistutil.KICKSTARTER, Num)
	fmt.Fprint(w, str)
	return
}
func Refresh(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	refreshCache(true)
	str := "{'code':'OK'}"
	fmt.Fprint(w, str)
	return
}
func refreshCache(flag bool) {
	urlSite := map[string]string{
		zlistutil.V2EX_BASE_URL + "hot.json":                        zlistutil.SITE_V2EX,
		zlistutil.V2EX_BASE_URL + "latest.json":                     zlistutil.SITE_V2EX,
		zlistutil.DAILY_FETCH_NOW:                                   zlistutil.SITE_ZHIHUDAILY,
		zlistutil.NEXT:                                              zlistutil.SITE_NEXT,
		zlistutil.PRODUCTHUNT_TODAY:                                 zlistutil.SITE_PRODUCTHUNT,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/topstories.json":  zlistutil.SITE_HACKERNEWS,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/newstories.json":  zlistutil.SITE_HACKERNEWS,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/askstories.json":  zlistutil.SITE_HACKERNEWS,
		zlistutil.HACKER_NEWS_BASE_API_URL + "/v0/showstories.json": zlistutil.SITE_HACKERNEWS,
		zlistutil.JIANSHU_BASE_URL + "/trending/now":                zlistutil.SITE_JIANSHU,
		zlistutil.JIANSHU_BASE_URL + "/trending/weekly":             zlistutil.SITE_JIANSHU,
		zlistutil.JIANSHU_BASE_URL + "/trending/monthly":            zlistutil.SITE_JIANSHU,
		zlistutil.WANQU:                                             zlistutil.SITE_WANQU,
		zlistutil.PINGWEST_NEWS:                                     zlistutil.SITE_PINGWEST,
		zlistutil.SOLIDOT:                                           zlistutil.SITE_SOLIDOT,
		zlistutil.GITHUB:                                            zlistutil.SITE_GITHUB,
		zlistutil.DOUBAN_MOMENT:                                     zlistutil.SITE_DOUBANMOMENT,
		zlistutil.IFANR:                                             zlistutil.SITE_IFANR,
		zlistutil.MINDSTORE:                                         zlistutil.SITE_MINDSTORE,
		zlistutil.KICKSTARTER:                                       zlistutil.SITE_KICKSTARTER,
	}
	log.Println("start refresh...")
	log.Println(time.Now())
	log.Printf("Clean exist cache ? %t", flag)
	for url, site := range urlSite {
		if flag == true && conn != nil {
			conn.Do("DEL", url)
		}
		getJSONStringCached(site, url, Num)
	}
	log.Println("stop refresh...")
}
func jobRefreshCache() {
	refreshCache(false)
}
func main() {
	c := cron.New()
	c.AddFunc("0 */15 * * * ?", jobRefreshCache)
	c.Start()
	log.Println("REDIS HOST:" + os.Getenv("REDIS_PORT_6379_TCP_ADDR"))
	log.Println("REDIS PORT:" + os.Getenv("REDIS_PORT_6379_TCP_PORT"))
	router := mux.NewRouter().StrictSlash(true)
	router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))
	router.HandleFunc("/", Index)
	router.HandleFunc("/refresh", Refresh)
	router.HandleFunc("/producthunt/top", ProductHunt)
	router.HandleFunc("/jianshu/{list_name}", Jianshu)
	router.HandleFunc("/36kr/next", Next)
	router.HandleFunc("/hackernews/{list_name}", HackerNews)
	router.HandleFunc("/v2ex/{list_name}", V2ex)
	router.HandleFunc("/zhihudaily/latest", ZhihuDaily)
	router.HandleFunc("/wanqu/top", Wanqu)
	router.HandleFunc("/pingwest/news", PingWestNews)
	router.HandleFunc("/solidot/top", Solidot)
	router.HandleFunc("/github/top", Github)
	router.HandleFunc("/douban/moment", DoubanMoment)
	router.HandleFunc("/ifanr/survey", IfanrSurvey)
	router.HandleFunc("/mindstore/top", MindStore)
	router.HandleFunc("/kickstarter/latest", Kickstarter)
	log.Println(http.ListenAndServe(":8080", router))
}
<|endoftext|>


<commit_before>package mgopw

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type Mongo struct {
	session    *mgo.Session
	db         string
	collection string
}

func New(session *mgo.Session, db, collection string) *Mongo {
	m := Mongo{
		session:    session,
		db:         db,
		collection: collection,
	}
	return &m
}

func (m Mongo) Add(s string) error {
	_, err := m.session.DB(m.db).C(m.collection).UpsertId(s, bson.M{})
	return err
}

func (m Mongo) Has(s string) (bool, error) {
	n, err := m.session.DB(m.db).C(m.collection).FindId(s).Count()
	if err != nil {
		return false, err
	}
	return n > 0, nil
}
<commit_msg>Explicitly set _id<commit_after>package mgopw

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type Mongo struct {
	session    *mgo.Session
	db         string
	collection string
}

func New(session *mgo.Session, db, collection string) *Mongo {
	m := Mongo{
		session:    session,
		db:         db,
		collection: collection,
	}
	return &m
}

func (m Mongo) Add(s string) error {
	_, err := m.session.DB(m.db).C(m.collection).UpsertId(s, bson.M{"_id": s})
	return err
}

func (m Mongo) Has(s string) (bool, error) {
	n, err := m.session.DB(m.db).C(m.collection).FindId(s).Count()
	if err != nil {
		return false, err
	}
	return n > 0, nil
}
<|endoftext|>


<commit_before>package gogs

type Branch struct {
	Name      string         `json:"name"`
	Commit    *PayloadCommit `json:"commit"`
}

func (c *Client) ListRepoBranches(user, repo string) ([]*Branch, error) {
	branches := make([]*Branch, 0, 10)
	return branches, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches", user, repo), nil, nil, &branches)
}

func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, error) {
	b := new(Branch)
	return b, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b)
}
<commit_msg>Fix import<commit_after>package gogs

import (
	"fmt"
)

type Branch struct {
	Name      string         `json:"name"`
	Commit    *PayloadCommit `json:"commit"`
}

func (c *Client) ListRepoBranches(user, repo string) ([]*Branch, error) {
	branches := make([]*Branch, 0, 10)
	return branches, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches", user, repo), nil, nil, &branches)
}

func (c *Client) GetRepoBranch(user, repo, branch string) (*Branch, error) {
	b := new(Branch)
	return b, c.getParsedResponse("GET", fmt.Sprintf("/repos/%s/%s/branches/%s", user, repo, branch), nil, nil, &b)
}
<|endoftext|>