<commit_before>package gost

import (
	"fmt"
	"net"

	"github.com/docker/libcontainer/netlink"
	"github.com/go-log/log"
	"github.com/milosgajdos/tenus"
	"github.com/songgao/water"
)

func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
	ip, ipNet, err := net.ParseCIDR(cfg.Addr)
	if err != nil {
		return
	}

	ifce, err := water.New(water.Config{
		DeviceType: water.TUN,
		PlatformSpecificParams: water.PlatformSpecificParams{
			Name: cfg.Name,
		},
	})
	if err != nil {
		return
	}

	link, err := tenus.NewLinkFrom(ifce.Name())
	if err != nil {
		return
	}

	mtu := cfg.MTU
	if mtu <= 0 {
		mtu = DefaultMTU
	}

	cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
	log.Log("[tun]", cmd)
	if er := link.SetLinkMTU(mtu); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
	log.Log("[tun]", cmd)
	if er := link.SetLinkIp(ip, ipNet); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
	log.Log("[tun]", cmd)
	if er := link.SetLinkUp(); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	if err = addTunRoutes(ifce.Name(), cfg.Routes...); err != nil {
		return
	}

	itf, err = net.InterfaceByName(ifce.Name())
	if err != nil {
		return
	}

	conn = &tunTapConn{
		ifce: ifce,
		addr: &net.IPAddr{IP: ip},
	}
	return
}

func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
	var ip net.IP
	var ipNet *net.IPNet
	if cfg.Addr != "" {
		ip, ipNet, err = net.ParseCIDR(cfg.Addr)
		if err != nil {
			return
		}
	}

	ifce, err := water.New(water.Config{
		DeviceType: water.TAP,
		PlatformSpecificParams: water.PlatformSpecificParams{
			Name: cfg.Name,
		},
	})
	if err != nil {
		return
	}

	link, err := tenus.NewLinkFrom(ifce.Name())
	if err != nil {
		return
	}

	mtu := cfg.MTU
	if mtu <= 0 {
		mtu = DefaultMTU
	}

	cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
	log.Log("[tap]", cmd)
	if er := link.SetLinkMTU(mtu); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	if cfg.Addr != "" {
		cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
		log.Log("[tap]", cmd)
		if er := link.SetLinkIp(ip, ipNet); er != nil {
			err = fmt.Errorf("%s: %v", cmd, er)
			return
		}
	}

	cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
	log.Log("[tap]", cmd)
	if er := link.SetLinkUp(); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	if err = addTapRoutes(ifce.Name(), cfg.Gateway, cfg.Routes...); err != nil {
		return
	}

	itf, err = net.InterfaceByName(ifce.Name())
	if err != nil {
		return
	}

	conn = &tunTapConn{
		ifce: ifce,
		addr: &net.IPAddr{IP: ip},
	}
	return
}

func addTunRoutes(ifName string, routes ...IPRoute) error {
	for _, route := range routes {
		if route.Dest == nil {
			continue
		}
		cmd := fmt.Sprintf("ip route add %s dev %s", route.Dest.String(), ifName)
		log.Logf("[tun] %s", cmd)
		if err := netlink.AddRoute(route.Dest.String(), "", "", ifName); err != nil {
			return fmt.Errorf("%s: %v", cmd, err)
		}
	}
	return nil
}

func addTapRoutes(ifName string, gw string, routes ...string) error {
	for _, route := range routes {
		if route == "" {
			continue
		}
		cmd := fmt.Sprintf("ip route add %s via %s dev %s", route, gw, ifName)
		log.Logf("[tap] %s", cmd)
		if err := netlink.AddRoute(route, "", gw, ifName); err != nil {
			return fmt.Errorf("%s: %v", cmd, err)
		}
	}
	return nil
}
<commit_msg>ignore linux error: File exists while add same route twice<commit_after>package gost

import (
	"errors"
	"fmt"
	"net"
	"syscall"

	"github.com/docker/libcontainer/netlink"
	"github.com/go-log/log"
	"github.com/milosgajdos/tenus"
	"github.com/songgao/water"
)

func createTun(cfg TunConfig) (conn net.Conn, itf *net.Interface, err error) {
	ip, ipNet, err := net.ParseCIDR(cfg.Addr)
	if err != nil {
		return
	}

	ifce, err := water.New(water.Config{
		DeviceType: water.TUN,
		PlatformSpecificParams: water.PlatformSpecificParams{
			Name: cfg.Name,
		},
	})
	if err != nil {
		return
	}

	link, err := tenus.NewLinkFrom(ifce.Name())
	if err != nil {
		return
	}

	mtu := cfg.MTU
	if mtu <= 0 {
		mtu = DefaultMTU
	}

	cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
	log.Log("[tun]", cmd)
	if er := link.SetLinkMTU(mtu); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
	log.Log("[tun]", cmd)
	if er := link.SetLinkIp(ip, ipNet); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
	log.Log("[tun]", cmd)
	if er := link.SetLinkUp(); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	if err = addTunRoutes(ifce.Name(), cfg.Routes...); err != nil {
		return
	}

	itf, err = net.InterfaceByName(ifce.Name())
	if err != nil {
		return
	}

	conn = &tunTapConn{
		ifce: ifce,
		addr: &net.IPAddr{IP: ip},
	}
	return
}

func createTap(cfg TapConfig) (conn net.Conn, itf *net.Interface, err error) {
	var ip net.IP
	var ipNet *net.IPNet
	if cfg.Addr != "" {
		ip, ipNet, err = net.ParseCIDR(cfg.Addr)
		if err != nil {
			return
		}
	}

	ifce, err := water.New(water.Config{
		DeviceType: water.TAP,
		PlatformSpecificParams: water.PlatformSpecificParams{
			Name: cfg.Name,
		},
	})
	if err != nil {
		return
	}

	link, err := tenus.NewLinkFrom(ifce.Name())
	if err != nil {
		return
	}

	mtu := cfg.MTU
	if mtu <= 0 {
		mtu = DefaultMTU
	}

	cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
	log.Log("[tap]", cmd)
	if er := link.SetLinkMTU(mtu); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	if cfg.Addr != "" {
		cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
		log.Log("[tap]", cmd)
		if er := link.SetLinkIp(ip, ipNet); er != nil {
			err = fmt.Errorf("%s: %v", cmd, er)
			return
		}
	}

	cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
	log.Log("[tap]", cmd)
	if er := link.SetLinkUp(); er != nil {
		err = fmt.Errorf("%s: %v", cmd, er)
		return
	}

	if err = addTapRoutes(ifce.Name(), cfg.Gateway, cfg.Routes...); err != nil {
		return
	}

	itf, err = net.InterfaceByName(ifce.Name())
	if err != nil {
		return
	}

	conn = &tunTapConn{
		ifce: ifce,
		addr: &net.IPAddr{IP: ip},
	}
	return
}

func addTunRoutes(ifName string, routes ...IPRoute) error {
	for _, route := range routes {
		if route.Dest == nil {
			continue
		}
		cmd := fmt.Sprintf("ip route add %s dev %s", route.Dest.String(), ifName)
		log.Logf("[tun] %s", cmd)
		if err := netlink.AddRoute(route.Dest.String(), "", "", ifName); err != nil && !errors.Is(err, syscall.EEXIST) {
			return fmt.Errorf("%s: %v", cmd, err)
		}
	}
	return nil
}

func addTapRoutes(ifName string, gw string, routes ...string) error {
	for _, route := range routes {
		if route == "" {
			continue
		}
		cmd := fmt.Sprintf("ip route add %s via %s dev %s", route, gw, ifName)
		log.Logf("[tap] %s", cmd)
		if err := netlink.AddRoute(route, "", gw, ifName); err != nil {
			return fmt.Errorf("%s: %v", cmd, err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package pay

import (
	"encoding/xml"
	"errors"
	"fmt"

	"github.com/silenceper/wechat/context"
	"github.com/silenceper/wechat/util"
)

var payGateway = "https://api.mch.weixin.qq.com/pay/unifiedorder"

// Pay struct extends context
type Pay struct {
	*context.Context
}

// Params was NEEDED when request unifiedorder
// 传入的参数，用于生成 prepay_id 的必需参数
type Params struct {
	TotalFee   string
	CreateIP   string
	Body       string
	OutTradeNo string
	OpenID     string
}

// Config 是传出用于 jsdk 用的参数
type Config struct {
	Timestamp int64
	NonceStr  string
	PrePayID  string
	SignType  string
	Sign      string
}

// payResult 是 unifie order 接口的返回
type payResult struct {
	ReturnCode string `xml:"return_code"`
	ReturnMsg  string `xml:"return_msg"`
	AppID      string `xml:"appid,omitempty"`
	MchID      string `xml:"mch_id,omitempty"`
	NonceStr   string `xml:"nonce_str,omitempty"`
	Sign       string `xml:"sign,omitempty"`
	ResultCode string `xml:"result_code,omitempty"`
	TradeType  string `xml:"trade_type,omitempty"`
	PrePayID   string `xml:"prepay_id,omitempty"`
	CodeURL    string `xml:"code_url,omitempty"`
	ErrCode    string `xml:"err_code,omitempty"`
	ErrCodeDes string `xml:"err_code_des,omitempty"`
}

//payRequest 接口请求参数
type payRequest struct {
	AppID          string `xml:"appid"`
	MchID          string `xml:"mch_id"`
	DeviceInfo     string `xml:"device_info,omitempty"`
	NonceStr       string `xml:"nonce_str"`
	Sign           string `xml:"sign"`
	SignType       string `xml:"sign_type,omitempty"`
	Body           string `xml:"body"`
	Detail         string `xml:"detail,omitempty"`
	Attach         string `xml:"attach,omitempty"`      //附加数据
	OutTradeNo     string `xml:"out_trade_no"`          //商户订单号
	FeeType        string `xml:"fee_type,omitempty"`    //标价币种
	TotalFee       string `xml:"total_fee"`             //标价金额
	SpbillCreateIP string `xml:"spbill_create_ip"`      //终端IP
	TimeStart      string `xml:"time_start,omitempty"`  //交易起始时间
	TimeExpire     string `xml:"time_expire,omitempty"` //交易结束时间
	GoodsTag       string `xml:"goods_tag,omitempty"`   //订单优惠标记
	NotifyURL      string `xml:"notify_url"`            //通知地址
	TradeType      string `xml:"trade_type"`            //交易类型
	ProductID      string `xml:"product_id,omitempty"`  //商品ID
	LimitPay       string `xml:"limit_pay,omitempty"`   //
	OpenID         string `xml:"openid,omitempty"`      //用户标识
	SceneInfo      string `xml:"scene_info,omitempty"`  //场景信息
}

// NewPay return an instance of Pay package
func NewPay(ctx *context.Context) *Pay {
	pay := Pay{Context: ctx}
	return &pay
}

// PrePayID will request wechat merchant api and request for a pre payment order id
func (pcf *Pay) PrePayID(p *Params) (prePayID string, err error) {
	nonceStr := util.RandomStr(32)
	tradeType := "JSAPI"
	template := "appid=%s&body=%s&mch_id=%s&nonce_str=%s&notify_url=%s&openid=%s&out_trade_no=%s&spbill_create_ip=%s&total_fee=%s&trade_type=%s&key=%s"
	str := fmt.Sprintf(template, pcf.AppID, p.Body, pcf.PayMchID, nonceStr, pcf.PayNotifyURL, p.OpenID, p.OutTradeNo, p.CreateIP, p.TotalFee, tradeType, pcf.PayKey)
	sign := util.MD5Sum(str)
	request := payRequest{
		AppID:          pcf.AppID,
		MchID:          pcf.PayMchID,
		NonceStr:       nonceStr,
		Sign:           sign,
		Body:           p.Body,
		OutTradeNo:     p.OutTradeNo,
		TotalFee:       p.TotalFee,
		SpbillCreateIP: p.CreateIP,
		NotifyURL:      pcf.PayNotifyURL,
		TradeType:      tradeType,
		OpenID:         p.OpenID,
	}
	rawRet, err := util.PostXML(payGateway, request)
	if err != nil {
		return "", errors.New(err.Error() + " parameters : " + str)
	}
	payRet := payResult{}
	err = xml.Unmarshal(rawRet, &payRet)
	if err != nil {
		return "", errors.New(err.Error())
	}
	if payRet.ReturnCode == "SUCCESS" {
		//pay success
		if payRet.ResultCode == "SUCCESS" {
			return payRet.PrePayID, nil
		}
		return "", errors.New(payRet.ErrCode + payRet.ErrCodeDes)
	}
	return "", errors.New("[msg : xmlUnmarshalError] [rawReturn : " + string(rawRet) + "] [params : " + str + "] [sign : " + sign + "]")
}
<commit_msg>修改统一下单接口的返回，提供全部返回，不仅仅是 prepay order<commit_after>package pay

import (
	"encoding/xml"
	"errors"
	"fmt"

	"github.com/silenceper/wechat/context"
	"github.com/silenceper/wechat/util"
)

var payGateway = "https://api.mch.weixin.qq.com/pay/unifiedorder"

// Pay struct extends context
type Pay struct {
	*context.Context
}

// Params was NEEDED when request unifiedorder
// 传入的参数，用于生成 prepay_id 的必需参数
type Params struct {
	TotalFee   string
	CreateIP   string
	Body       string
	OutTradeNo string
	OpenID     string
}

// Config 是传出用于 jsdk 用的参数
type Config struct {
	Timestamp int64
	NonceStr  string
	PrePayID  string
	SignType  string
	Sign      string
}

// PreOrder 是 unifie order 接口的返回
type PreOrder struct {
	ReturnCode string `xml:"return_code"`
	ReturnMsg  string `xml:"return_msg"`
	AppID      string `xml:"appid,omitempty"`
	MchID      string `xml:"mch_id,omitempty"`
	NonceStr   string `xml:"nonce_str,omitempty"`
	Sign       string `xml:"sign,omitempty"`
	ResultCode string `xml:"result_code,omitempty"`
	TradeType  string `xml:"trade_type,omitempty"`
	PrePayID   string `xml:"prepay_id,omitempty"`
	CodeURL    string `xml:"code_url,omitempty"`
	ErrCode    string `xml:"err_code,omitempty"`
	ErrCodeDes string `xml:"err_code_des,omitempty"`
}

//payRequest 接口请求参数
type payRequest struct {
	AppID          string `xml:"appid"`
	MchID          string `xml:"mch_id"`
	DeviceInfo     string `xml:"device_info,omitempty"`
	NonceStr       string `xml:"nonce_str"`
	Sign           string `xml:"sign"`
	SignType       string `xml:"sign_type,omitempty"`
	Body           string `xml:"body"`
	Detail         string `xml:"detail,omitempty"`
	Attach         string `xml:"attach,omitempty"`      //附加数据
	OutTradeNo     string `xml:"out_trade_no"`          //商户订单号
	FeeType        string `xml:"fee_type,omitempty"`    //标价币种
	TotalFee       string `xml:"total_fee"`             //标价金额
	SpbillCreateIP string `xml:"spbill_create_ip"`      //终端IP
	TimeStart      string `xml:"time_start,omitempty"`  //交易起始时间
	TimeExpire     string `xml:"time_expire,omitempty"` //交易结束时间
	GoodsTag       string `xml:"goods_tag,omitempty"`   //订单优惠标记
	NotifyURL      string `xml:"notify_url"`            //通知地址
	TradeType      string `xml:"trade_type"`            //交易类型
	ProductID      string `xml:"product_id,omitempty"`  //商品ID
	LimitPay       string `xml:"limit_pay,omitempty"`   //
	OpenID         string `xml:"openid,omitempty"`      //用户标识
	SceneInfo      string `xml:"scene_info,omitempty"`  //场景信息
}

// NewPay return an instance of Pay package
func NewPay(ctx *context.Context) *Pay {
	pay := Pay{Context: ctx}
	return &pay
}

// PrePayOrder return data for invoke wechat payment
func (pcf *Pay) PrePayOrder(p *Params) (payOrder PreOrder, err error) {
	nonceStr := util.RandomStr(32)
	tradeType := "JSAPI"
	template := "appid=%s&body=%s&mch_id=%s&nonce_str=%s&notify_url=%s&openid=%s&out_trade_no=%s&spbill_create_ip=%s&total_fee=%s&trade_type=%s&key=%s"
	str := fmt.Sprintf(template, pcf.AppID, p.Body, pcf.PayMchID, nonceStr, pcf.PayNotifyURL, p.OpenID, p.OutTradeNo, p.CreateIP, p.TotalFee, tradeType, pcf.PayKey)
	sign := util.MD5Sum(str)
	request := payRequest{
		AppID:          pcf.AppID,
		MchID:          pcf.PayMchID,
		NonceStr:       nonceStr,
		Sign:           sign,
		Body:           p.Body,
		OutTradeNo:     p.OutTradeNo,
		TotalFee:       p.TotalFee,
		SpbillCreateIP: p.CreateIP,
		NotifyURL:      pcf.PayNotifyURL,
		TradeType:      tradeType,
		OpenID:         p.OpenID,
	}
	rawRet, err := util.PostXML(payGateway, request)
	if err != nil {
		return
	}
	err = xml.Unmarshal(rawRet, &payOrder)
	if err != nil {
		return
	}
	if payOrder.ReturnCode == "SUCCESS" {
		//pay success
		if payOrder.ResultCode == "SUCCESS" {
			err = nil
			return
		}
		err = errors.New(payOrder.ErrCode + payOrder.ErrCodeDes)
		return
	}
	err = errors.New("[msg : xmlUnmarshalError] [rawReturn : " + string(rawRet) + "] [params : " + str + "] [sign : " + sign + "]")
	return
}

// PrePayID will request wechat merchant api and request for a pre payment order id
func (pcf *Pay) PrePayID(p *Params) (prePayID string, err error) {
	order, err := pcf.PrePayOrder(p)
	if err != nil {
		return
	}
	if order.PrePayID == "" {
		err = errors.New("empty prepayid")
	}
	prePayID = order.PrePayID
	return
}
<|endoftext|>


<commit_before>package killswitch_test

import (
	"strings"
	"testing"

	"github.com/vpn-kill-switch/killswitch"
)

func TestPf(t *testing.T) {
	tt := []struct {
		peerIp            string
		expectedVpnString string
	}{
		{
			peerIp:            "127.0.0.1",
			expectedVpnString: "vpn_ip = \"127.0.0.1\"",
		},
		{
			peerIp:            "1.2.3.4",
			expectedVpnString: "vpn_ip = \"1.2.3.4\"",
		},
		{
			peerIp:            "",
			expectedVpnString: "vpn_ip = \"0.0.0.0\"",
		},
	}

	for i, tst := range tt {
		t.Logf("\tTest %d: \t%s", i, tst.peerIp)
		network, _ := killswitch.New(tst.peerIp)
		network.CreatePF(false)

		configFileContents := network.PFRules.String()

		if !strings.Contains(configFileContents, tst.expectedVpnString) {
			t.Fatalf("\t%s\t Should contain vpn string:  exp[%s] got[%s] ", failed, tst.expectedVpnString, configFileContents)
		}
		t.Logf("\t%s\t Should contain vpn string ", succeeded)
	}

	// with option -leak
	for i, tst := range tt {
		t.Logf("\tTest %d: \t%s", i, tst.peerIp)
		network, _ := killswitch.New(tst.peerIp)
		network.CreatePF(true)

		configFileContents := network.PFRules.String()

		if !strings.Contains(configFileContents, tst.expectedVpnString) {
			t.Fatalf("\t%s\t Should contain vpn string:  exp[%s] got[%s] ", failed, tst.expectedVpnString, configFileContents)
		}
		t.Logf("\t%s\t Should contain vpn string ", succeeded)
	}
}
<commit_msg>vpn needs to be off to run tests<commit_after>package killswitch_test

import (
	"strings"
	"testing"

	"github.com/vpn-kill-switch/killswitch"
)

// VPN needs to be off for testing
func TestPf(t *testing.T) {
	tt := []struct {
		peerIp            string
		expectedVpnString string
	}{
		{
			peerIp:            "127.0.0.1",
			expectedVpnString: "vpn_ip = \"127.0.0.1\"",
		},
		{
			peerIp:            "1.2.3.4",
			expectedVpnString: "vpn_ip = \"1.2.3.4\"",
		},
		{
			peerIp:            "",
			expectedVpnString: "vpn_ip = \"0.0.0.0\"",
		},
	}

	for i, tst := range tt {
		t.Logf("\tTest %d: \t%s", i, tst.peerIp)
		network, _ := killswitch.New(tst.peerIp)
		network.CreatePF(false)

		configFileContents := network.PFRules.String()

		if !strings.Contains(configFileContents, tst.expectedVpnString) {
			t.Fatalf("\t%s\t Should contain vpn string:  exp[%s] got[%s] ", failed, tst.expectedVpnString, configFileContents)
		}
		t.Logf("\t%s\t Should contain vpn string ", succeeded)
	}

	// with option -leak
	for i, tst := range tt {
		t.Logf("\tTest %d: \t%s", i, tst.peerIp)
		network, _ := killswitch.New(tst.peerIp)
		network.CreatePF(true)

		configFileContents := network.PFRules.String()

		if !strings.Contains(configFileContents, tst.expectedVpnString) {
			t.Fatalf("\t%s\t Should contain vpn string:  exp[%s] got[%s] ", failed, tst.expectedVpnString, configFileContents)
		}
		t.Logf("\t%s\t Should contain vpn string ", succeeded)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/sylphon/builder-core"
	"github.com/sylphon/builder-core/unit-config"
)

var example = &unitconfig.UnitConfig{
	Version: 1,
	ContainerArr: []*unitconfig.ContainerSection{
		&unitconfig.ContainerSection{
			Name:       "app",
			Dockerfile: "Dockerfile",
			Registry:   "quay.io/rafecolton",
			Project:    "builder-core-test",
			Tags:       []string{"latest", "git:sha", "git:tag", "git:branch"},
			SkipPush:   true,
		},
	},
}

func main() {
	if err := runner.RunBuildSynchronously(example, os.Getenv("GOPATH")+"/src/github.com/rafecolton/docker-builder"); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Updating tag syntax for the unit config in _example<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/sylphon/builder-core"
	"github.com/sylphon/builder-core/unit-config"
)

var example = &unitconfig.UnitConfig{
	Version: 1,
	ContainerArr: []*unitconfig.ContainerSection{
		&unitconfig.ContainerSection{
			Name:       "app",
			Dockerfile: "Dockerfile",
			Registry:   "quay.io/rafecolton",
			Project:    "builder-core-test",
			Tags:       []string{"latest", "{{ sha }}", "{{ tag }}", "{{ branch }}"},
			SkipPush:   true,
		},
	},
}

func main() {
	if err := runner.RunBuildSynchronously(example, os.Getenv("GOPATH")+"/src/github.com/rafecolton/docker-builder"); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>
<commit_msg>Delete sys.go<commit_after><|endoftext|>


<commit_before>package geom

import (
	"testing"
)

func TestLinearRingArea(t *testing.T) {
	for _, tc := range []struct {
		lr   *LinearRing
		want float64
	}{
		{
			lr: NewLinearRing(XY).MustSetCoords([][]float64{
				{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0},
			}),
			want: 1,
		},
		{
			lr: NewLinearRing(XY).MustSetCoords([][]float64{
				{0, 0}, {1, 1}, {1, 0}, {0, 0},
			}),
			want: -0.5,
		},
		{
			lr: NewLinearRing(XY).MustSetCoords([][]float64{
				{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2},
			}),
			want: 60,
		},
	} {
		if got := tc.lr.Area(); got != tc.want {
			t.Errorf("%#v.Area() == %f, want %f", tc.lr, got, tc.want)
		}
	}
}

func TestPolygonArea(t *testing.T) {
	for _, tc := range []struct {
		p    *Polygon
		want float64
	}{
		{
			p: NewPolygon(XY).MustSetCoords([][][]float64{
				{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}},
			}),
			want: 1,
		},
		{
			p: NewPolygon(XY).MustSetCoords([][][]float64{
				{{0, 0}, {1, 1}, {1, 0}, {0, 0}},
			}),
			want: -0.5,
		},
		{
			p: NewPolygon(XY).MustSetCoords([][][]float64{
				{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
			}),
			want: 60,
		},
		{
			p: NewPolygon(XY).MustSetCoords([][][]float64{
				{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
				{{0, 6}, {2, 6}, {2, 8}, {0, 8}, {0, 6}},
			}),
			want: 56,
		},
	} {
		if got := tc.p.Area(); got != tc.want {
			t.Errorf("%#v.Area() == %f, want %f", tc.p, got, tc.want)
		}
	}
}

func TestMultiPolygonArea(t *testing.T) {
	for _, tc := range []struct {
		mp   *MultiPolygon
		want float64
	}{
		{
			mp: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}},
				},
			}),
			want: 1,
		},
		{
			mp: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{0, 0}, {1, 1}, {1, 0}, {0, 0}},
				},
			}),
			want: -0.5,
		},
		{
			mp: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
				},
			}),
			want: 60,
		},
		{
			mp: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
					{{0, 6}, {2, 6}, {2, 8}, {0, 8}, {0, 6}},
				},
			}),
			want: 56,
		},
		{
			mp: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}},
				},
				{
					{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
					{{0, 6}, {2, 6}, {2, 8}, {0, 8}, {0, 6}},
				},
			}),
			want: 57,
		},
	} {
		if got := tc.mp.Area(); got != tc.want {
			t.Errorf("%#v.Area() == %f, want %f", tc.mp, got, tc.want)
		}
	}
}
<commit_msg>Combine area tests using anonymous interface trick<commit_after>package geom

import (
	"testing"
)

func TestArea(t *testing.T) {
	for _, tc := range []struct {
		g interface {
			Area() float64
		}
		want float64
	}{
		{
			g: NewLinearRing(XY).MustSetCoords([][]float64{
				{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0},
			}),
			want: 1,
		},
		{
			g: NewLinearRing(XY).MustSetCoords([][]float64{
				{0, 0}, {1, 1}, {1, 0}, {0, 0},
			}),
			want: -0.5,
		},
		{
			g: NewLinearRing(XY).MustSetCoords([][]float64{
				{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2},
			}),
			want: 60,
		},
		{
			g: NewPolygon(XY).MustSetCoords([][][]float64{
				{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}},
			}),
			want: 1,
		},
		{
			g: NewPolygon(XY).MustSetCoords([][][]float64{
				{{0, 0}, {1, 1}, {1, 0}, {0, 0}},
			}),
			want: -0.5,
		},
		{
			g: NewPolygon(XY).MustSetCoords([][][]float64{
				{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
			}),
			want: 60,
		},
		{
			g: NewPolygon(XY).MustSetCoords([][][]float64{
				{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
				{{0, 6}, {2, 6}, {2, 8}, {0, 8}, {0, 6}},
			}),
			want: 56,
		},
		{
			g: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}},
				},
			}),
			want: 1,
		},
		{
			g: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{0, 0}, {1, 1}, {1, 0}, {0, 0}},
				},
			}),
			want: -0.5,
		},
		{
			g: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
				},
			}),
			want: 60,
		},
		{
			g: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
					{{0, 6}, {2, 6}, {2, 8}, {0, 8}, {0, 6}},
				},
			}),
			want: 56,
		},
		{
			g: NewMultiPolygon(XY).MustSetCoords([][][][]float64{
				{
					{{0, 0}, {1, 0}, {1, 1}, {0, 1}, {0, 0}},
				},
				{
					{{-3, -2}, {-1, 4}, {6, 1}, {3, 10}, {-4, 9}, {-3, -2}},
					{{0, 6}, {2, 6}, {2, 8}, {0, 8}, {0, 6}},
				},
			}),
			want: 57,
		},
	} {
		if got := tc.g.Area(); got != tc.want {
			t.Errorf("%#v.Area() == %f, want %f", tc.g, got, tc.want)
		}
	}
}
<|endoftext|>


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

//+build !amd64 noasm appengine

package asm

func DscalUnitary(alpha float64, x []float64) {
	for i := range x {
		x[i] *= alpha
	}
}

func DscalUnitaryTo(dst []float64, alpha float64, x []float64) {
	for i, v := range x {
		dst[i] = alpha * v
	}
}
<commit_msg>asm: add non-asm version of DscalInc and DscalIncTo<commit_after>// Copyright ©2016 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//+build !amd64 noasm appengine

package asm

func DscalUnitary(alpha float64, x []float64) {
	for i := range x {
		x[i] *= alpha
	}
}

func DscalUnitaryTo(dst []float64, alpha float64, x []float64) {
	for i, v := range x {
		dst[i] = alpha * v
	}
}

func DscalInc(alpha float64, x []float64, n, incX, ix uintptr) {
	for i := 0; i < int(n); i++ {
		x[ix] *= alpha
		ix += incX
	}
}

func DscalIncTo(dst []float64, incDst, idst uintptr, alpha float64, x []float64, n, incX, ix uintptr) {
	for i := 0; i < int(n); i++ {
		dst[idst] = alpha * x[ix]
		ix += incX
		idst += incDst
	}
}
<|endoftext|>


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

package audio

import (
	"errors"
	"io"
	"runtime"
	"sync"
)

type mux struct {
	ps map[*playerImpl]struct{}
	m  sync.RWMutex
}

const (
	channelNum     = 2
	bytesPerSample = 2 * channelNum

	// TODO: This assumes that bytesPerSample is a power of 2.
	mask = ^(bytesPerSample - 1)
)

func newMux() *mux {
	return &mux{
		ps: map[*playerImpl]struct{}{},
	}
}

func (m *mux) Read(b []byte) (int, error) {
	m.m.Lock()
	defer m.m.Unlock()

	// Check the source duplication
	srcs := map[io.ReadCloser]struct{}{}
	for p := range m.ps {
		if _, ok := srcs[p.src]; ok {
			return 0, errors.New("audio: a same source is used by multiple Player")
		}
		srcs[p.src] = struct{}{}
	}

	if len(m.ps) == 0 {
		l := len(b)
		l &= mask
		copy(b, make([]byte, l))
		return l, nil
	}

	l := len(b)
	l &= mask

	allSkipped := true

	// TODO: Now a player is not locked. Should we lock it?

	for p := range m.ps {
		if p.shouldSkip() {
			continue
		}
		allSkipped = false
		s := p.bufferSizeInBytes()
		if l > s {
			l = s
			l &= mask
		}
	}

	if allSkipped {
		l = 0
	}

	if l == 0 {
		// If l is 0, all the ps might reach EOF at the next update.
		// However, this Read might block forever and never causes context switch
		// on single-thread environment (e.g. browser).
		// Call Gosched to cause context switch on purpose.
		runtime.Gosched()
	}

	b16s := [][]int16{}
	for p := range m.ps {
		buf, err := p.bufferToInt16(l)
		if err != nil {
			return 0, err
		}
		b16s = append(b16s, buf)
	}

	for i := 0; i < l/2; i++ {
		x := 0
		for _, b16 := range b16s {
			x += int(b16[i])
		}
		if x > (1<<15)-1 {
			x = (1 << 15) - 1
		}
		if x < -(1 << 15) {
			x = -(1 << 15)
		}
		b[2*i] = byte(x)
		b[2*i+1] = byte(x >> 8)
	}

	closed := []*playerImpl{}
	for p := range m.ps {
		if p.eof() {
			closed = append(closed, p)
		}
	}
	for _, p := range closed {
		p.closeImpl()
		delete(m.ps, p)
	}

	return l, nil
}

func (m *mux) addPlayer(player *playerImpl) {
	m.m.Lock()
	m.ps[player] = struct{}{}
	m.m.Unlock()
}

func (m *mux) removePlayer(player *playerImpl) {
	m.m.Lock()
	delete(m.ps, player)
	m.m.Unlock()
}

func (m *mux) hasPlayer(player *playerImpl) bool {
	m.m.RLock()
	_, ok := m.ps[player]
	m.m.RUnlock()
	return ok
}
<commit_msg>audio: Bug fix: bufferToInt16 can return smaller result<commit_after>// Copyright 2019 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package audio

import (
	"errors"
	"io"
	"runtime"
	"sync"
)

type mux struct {
	ps map[*playerImpl]struct{}
	m  sync.RWMutex
}

const (
	channelNum     = 2
	bytesPerSample = 2 * channelNum

	// TODO: This assumes that bytesPerSample is a power of 2.
	mask = ^(bytesPerSample - 1)
)

func newMux() *mux {
	return &mux{
		ps: map[*playerImpl]struct{}{},
	}
}

func (m *mux) Read(b []byte) (int, error) {
	m.m.Lock()
	defer m.m.Unlock()

	// Check the source duplication
	srcs := map[io.ReadCloser]struct{}{}
	for p := range m.ps {
		if _, ok := srcs[p.src]; ok {
			return 0, errors.New("audio: a same source is used by multiple Player")
		}
		srcs[p.src] = struct{}{}
	}

	if len(m.ps) == 0 {
		l := len(b)
		l &= mask
		copy(b, make([]byte, l))
		return l, nil
	}

	l := len(b)
	l &= mask

	allSkipped := true

	// TODO: Now a player is not locked. Should we lock it?

	for p := range m.ps {
		if p.shouldSkip() {
			continue
		}
		allSkipped = false
		s := p.bufferSizeInBytes()
		if l > s {
			l = s
			l &= mask
		}
	}

	if allSkipped {
		l = 0
	}

	if l == 0 {
		// If l is 0, all the ps might reach EOF at the next update.
		// However, this Read might block forever and never causes context switch
		// on single-thread environment (e.g. browser).
		// Call Gosched to cause context switch on purpose.
		runtime.Gosched()
	}

	b16s := [][]int16{}
	for p := range m.ps {
		buf, err := p.bufferToInt16(l)
		if err != nil {
			return 0, err
		}
		if l > len(buf)*2 {
			l = len(buf) * 2
		}
		b16s = append(b16s, buf)
	}

	for i := 0; i < l/2; i++ {
		x := 0
		for _, b16 := range b16s {
			x += int(b16[i])
		}
		if x > (1<<15)-1 {
			x = (1 << 15) - 1
		}
		if x < -(1 << 15) {
			x = -(1 << 15)
		}
		b[2*i] = byte(x)
		b[2*i+1] = byte(x >> 8)
	}

	closed := []*playerImpl{}
	for p := range m.ps {
		if p.eof() {
			closed = append(closed, p)
		}
	}
	for _, p := range closed {
		p.closeImpl()
		delete(m.ps, p)
	}

	return l, nil
}

func (m *mux) addPlayer(player *playerImpl) {
	m.m.Lock()
	m.ps[player] = struct{}{}
	m.m.Unlock()
}

func (m *mux) removePlayer(player *playerImpl) {
	m.m.Lock()
	delete(m.ps, player)
	m.m.Unlock()
}

func (m *mux) hasPlayer(player *playerImpl) bool {
	m.m.RLock()
	_, ok := m.ps[player]
	m.m.RUnlock()
	return ok
}
<|endoftext|>


<commit_before>package revelswagger

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"path"
	"runtime"
	"text/template"

	"github.com/howeyc/fsnotify"
	"github.com/revel/revel"
)

var spec Specification

func init() {
	revel.OnAppStart(func() {
		fmt.Println("[SWAGGER]: Loading schema...")

		loadSpecFile()

		go watchSpecFile()
	})
}

func loadSpecFile() {
	spec = Specification{}

	content, err := ioutil.ReadFile(revel.BasePath + "\\conf\\spec.json")

	if err != nil {
		fmt.Println("[SWAGGER]: Couldn't load spec.json.", err)
		return
	}

	err = json.Unmarshal(content, &spec)

	if err != nil {
		fmt.Println("[SWAGGER]: Error parsing schema file.", err)
	}
}

func watchSpecFile() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	done := make(chan bool)

	// Process events
	go func() {
		for {
			select {
			case <-watcher.Event:
				loadSpecFile()
			case err := <-watcher.Error:
				fmt.Println("[SWAGGER]: Watcher error:", err)
			}
		}
	}()

	err = watcher.Watch(revel.BasePath + "\\conf\\spec.json")

	if err != nil {
		fmt.Println("[SWAGGER]: Error watching spec file:", err)
	} else {
		fmt.Println("[SWAGGER]: Spec watcher initialized")
	}

	<-done

	/* ... do stuff ... */
	watcher.Close()
}

func Filter(c *revel.Controller, fc []revel.Filter) {
	var route *revel.RouteMatch = revel.MainRouter.Route(c.Request.Request)

	if route == nil {
		c.Result = c.NotFound("No matching route found: " + c.Request.RequestURI)
		return
	}

	if len(route.Params) == 0 {
		c.Params.Route = map[string][]string{}
	} else {
		c.Params.Route = route.Params
	}

	// Add the fixed parameters mapped by name.
	// TODO: Pre-calculate this mapping.
	for i, value := range route.FixedParams {
		if c.Params.Fixed == nil {
			c.Params.Fixed = make(url.Values)
		}
		if i < len(c.MethodType.Args) {
			arg := c.MethodType.Args[i]
			c.Params.Fixed.Set(arg.Name, value)
		} else {
			fmt.Println("Too many parameters to", route.Action, "trying to add", value)
			break
		}
	}

	leaf, _ := revel.MainRouter.Tree.Find(treePath(c.Request.Method, c.Request.URL.Path))

	r := leaf.Value.(*revel.Route)

	method := spec.Paths[r.Path].Get

	if method == nil {
		_, filename, _, _ := runtime.Caller(0)

		t, err := template.ParseFiles(path.Dir(filename) + "/views/notfound.html")

		if err != nil {
			panic(err)
		}

		t.Execute(c.Response.Out, map[string]interface{}{
			"routes": spec.Paths,
			"path":   c.Request.RequestURI,
		})
		return
	}

	if err := c.SetAction(route.ControllerName, route.MethodName); err != nil {
		c.Result = c.NotFound(err.Error())
		return
	}

	// Action has been found & set, let's validate the parameters
	validateParameters(method.Parameters, c)

	if c.Validation.HasErrors() {
		var errors []string

		for _, e := range c.Validation.Errors {
			errors = append(errors, e.Message)
		}

		c.Result = c.RenderJson(map[string]interface{}{"errors": errors})
		return
	}

	// Move onto the next filter
	fc[0](c, fc[1:])
}

func treePath(method, path string) string {
	if method == "*" {
		method = ":METHOD"
	}
	return "/" + method + path
}
<commit_msg>Added ability to configure lazy matching of spec<commit_after>package revelswagger

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/url"
	"path"
	"runtime"
	"text/template"

	"github.com/howeyc/fsnotify"
	"github.com/revel/revel"
)

var spec Specification

func init() {
	revel.OnAppStart(func() {
		fmt.Println("[SWAGGER]: Loading schema...")

		loadSpecFile()

		go watchSpecFile()
	})
}

func loadSpecFile() {
	spec = Specification{}

	content, err := ioutil.ReadFile(revel.BasePath + "\\conf\\spec.json")

	if err != nil {
		fmt.Println("[SWAGGER]: Couldn't load spec.json.", err)
		return
	}

	err = json.Unmarshal(content, &spec)

	if err != nil {
		fmt.Println("[SWAGGER]: Error parsing schema file.", err)
	}
}

func watchSpecFile() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	done := make(chan bool)

	// Process events
	go func() {
		for {
			select {
			case <-watcher.Event:
				loadSpecFile()
			case err := <-watcher.Error:
				fmt.Println("[SWAGGER]: Watcher error:", err)
			}
		}
	}()

	err = watcher.Watch(revel.BasePath + "\\conf\\spec.json")

	if err != nil {
		fmt.Println("[SWAGGER]: Error watching spec file:", err)
	} else {
		fmt.Println("[SWAGGER]: Spec watcher initialized")
	}

	<-done

	/* ... do stuff ... */
	watcher.Close()
}

func Filter(c *revel.Controller, fc []revel.Filter) {
	var route *revel.RouteMatch = revel.MainRouter.Route(c.Request.Request)

	if route == nil {
		c.Result = c.NotFound("No matching route found: " + c.Request.RequestURI)
		return
	}

	if len(route.Params) == 0 {
		c.Params.Route = map[string][]string{}
	} else {
		c.Params.Route = route.Params
	}

	if err := c.SetAction(route.ControllerName, route.MethodName); err != nil {
		c.Result = c.NotFound(err.Error())
		return
	}

	// Add the fixed parameters mapped by name.
	// TODO: Pre-calculate this mapping.
	for i, value := range route.FixedParams {
		if c.Params.Fixed == nil {
			c.Params.Fixed = make(url.Values)
		}
		if i < len(c.MethodType.Args) {
			arg := c.MethodType.Args[i]
			c.Params.Fixed.Set(arg.Name, value)
		} else {
			fmt.Println("Too many parameters to", route.Action, "trying to add", value)
			break
		}
	}

	leaf, _ := revel.MainRouter.Tree.Find(treePath(c.Request.Method, c.Request.URL.Path))

	r := leaf.Value.(*revel.Route)

	method := spec.Paths[r.Path].Get

	if method == nil {
		// Check if strict mode is enabled and throw an error, otherwise
		// just move onto the next filter like revel normally would
		if revel.Config.BoolDefault("swagger.strict", false) {
			_, filename, _, _ := runtime.Caller(0)

			t, err := template.ParseFiles(path.Dir(filename) + "/views/notfound.html")

			if err != nil {
				panic(err)
			}

			t.Execute(c.Response.Out, map[string]interface{}{
				"routes": spec.Paths,
				"path":   c.Request.RequestURI,
			})
			return
		} else {
			// Move onto the next filter
			fc[0](c, fc[1:])
			return
		}
	}

	// Action has been found & set, let's validate the parameters
	validateParameters(method.Parameters, c)

	if c.Validation.HasErrors() {
		var errors []string

		for _, e := range c.Validation.Errors {
			errors = append(errors, e.Message)
		}

		c.Result = c.RenderJson(map[string]interface{}{"errors": errors})
		return
	}

	// Move onto the next filter
	fc[0](c, fc[1:])
}

func treePath(method, path string) string {
	if method == "*" {
		method = ":METHOD"
	}
	return "/" + method + path
}
<|endoftext|>


<commit_before>package goal

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"

	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
)

// validateCols columns are valid
func validateCols(usernameCol string, passwordCol string, user interface{}) error {
	// validateCols column names
	scope := db.NewScope(user)
	cols := []string{usernameCol, passwordCol}
	for _, col := range cols {
		if !scope.HasColumn(col) {
			errorMsg := fmt.Sprintf("Column %s does not exist", col)
			return errors.New(errorMsg)
		}
	}

	return nil
}

// RegisterWithPassword checks if username exists and
// sets password with bcrypt algorithm
// Client can provides extra data to be saved into database for user
func RegisterWithPassword(
	w http.ResponseWriter, request *http.Request,
	usernameCol string, passwordCol string) (interface{}, error) {
	if request.Method != POST {
		return nil, http.ErrNotSupported
	}

	user, err := getUserResource()
	if err != nil {
		return nil, err
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	var values map[string]string
	err = decoder.Decode(&values)
	if err != nil {
		return nil, err
	}

	username := values["username"]
	password := values["password"]

	if username == "" || password == "" {
		return nil, errors.New("username or password is not found")
	}

	err = validateCols(usernameCol, passwordCol, user)

	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	// Search db, if a username is already defined, return error
	qry := fmt.Sprintf("%s = ?", usernameCol)
	err = db.Where(qry, username).First(user).Error
	if err != nil {
		if err != gorm.ErrRecordNotFound {
			return nil, err
		}
	}

	// Since user was populated with extra data, we need to
	// setup new scope
	scope := db.NewScope(user)

	// Save a new record to db
	scope.SetColumn(usernameCol, username)

	// Hashing the password with the default cost of 10
	hashedPw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}
	scope.SetColumn(passwordCol, hashedPw)
	err = scope.DB().New().Create(scope.Value).Error
	if err != nil {
		return nil, err
	}

	// Set current session
	SetUserSession(w, request, user)

	return user, nil
}

// LoginWithPassword checks if username and password correct
// and set user into session
func LoginWithPassword(
	w http.ResponseWriter, request *http.Request,
	usernameCol string, passwordCol string) (interface{}, error) {
	if request.Method != POST {
		return nil, http.ErrNotSupported
	}

	user, err := getUserResource()
	if err != nil {
		return nil, err
	}

	err = validateCols(usernameCol, passwordCol, user)
	if err != nil {
		return nil, err
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	var values map[string]string
	err = decoder.Decode(&values)
	if err != nil {
		return nil, err
	}

	username := values["username"]
	password := values["password"]

	if username == "" || password == "" {
		return nil, errors.New("username or password is not found")
	}

	// Search db, if a username is not found, return error
	qry := fmt.Sprintf("%s = ?", usernameCol)

	qryDB := db.Where(qry, username).First(user)
	err = qryDB.Error
	if err != nil {
		return nil, err
	}

	if user == nil {
		errorMsg := fmt.Sprintf("Username not found: %s", username)
		return nil, errors.New(errorMsg)
	}

	// Make sure the password is correct
	var hashs []string
	qryDB.Pluck(passwordCol, &hashs)

	if len(hashs) == 0 {
		errorMsg := fmt.Sprintf("Unable to get value from column: %s", passwordCol)
		return nil, errors.New(errorMsg)
	}

	hashed := hashs[0]

	// Comparing the password with the hash
	err = bcrypt.CompareHashAndPassword([]byte(hashed), []byte(password))
	if err != nil {
		return nil, err
	}

	// Set current session
	SetUserSession(w, request, user)

	return user, nil
}

// HandleLogout let user logout from the system
func HandleLogout(w http.ResponseWriter, request *http.Request) {
	ClearUserSession(w, request)
}
<commit_msg>Fix auth<commit_after>package goal

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"

	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
)

// validateCols columns are valid
func validateCols(usernameCol string, passwordCol string, user interface{}) error {
	// validateCols column names
	scope := db.NewScope(user)
	cols := []string{usernameCol, passwordCol}
	for _, col := range cols {
		if !scope.HasColumn(col) {
			errorMsg := fmt.Sprintf("Column %s does not exist", col)
			return errors.New(errorMsg)
		}
	}

	return nil
}

// RegisterWithPassword checks if username exists and
// sets password with bcrypt algorithm
// Client can provides extra data to be saved into database for user
func RegisterWithPassword(
	w http.ResponseWriter, request *http.Request,
	usernameCol string, passwordCol string) (interface{}, error) {
	if request.Method != POST {
		return nil, http.ErrNotSupported
	}

	user, err := getUserResource()
	if err != nil {
		return nil, err
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	var values map[string]string
	err = decoder.Decode(&values)
	if err != nil {
		return nil, err
	}

	username := values[usernameCol]
	password := values[passwordCol]

	if username == "" || password == "" {
		return nil, errors.New("username or password is not found")
	}

	err = validateCols(usernameCol, passwordCol, user)

	if err != nil {
		fmt.Println(err)
		return nil, err
	}

	// Search db, if a username is already defined, return error
	qryStr := fmt.Sprintf("%s = ?", usernameCol)
	var count int
	qry := db.Where(qryStr, username).First(user).Count(&count)
	err = qry.Error
	if err != nil {
		if err != gorm.ErrRecordNotFound {
			return nil, err
		}
	}

	if count > 0 {
		return nil, errors.New("account already exists")
	}

	// Since user was populated with extra data, we need to
	// setup new scope
	scope := db.NewScope(user)

	// Save a new record to db
	scope.SetColumn(usernameCol, username)

	// Hashing the password with the default cost of 10
	hashedPw, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}
	scope.SetColumn(passwordCol, hashedPw)
	err = scope.DB().New().Create(scope.Value).Error
	if err != nil {
		return nil, err
	}

	// Set current session
	SetUserSession(w, request, user)

	return user, nil
}

// LoginWithPassword checks if username and password correct
// and set user into session
func LoginWithPassword(
	w http.ResponseWriter, request *http.Request,
	usernameCol string, passwordCol string) (interface{}, error) {
	if request.Method != POST {
		return nil, http.ErrNotSupported
	}

	user, err := getUserResource()
	if err != nil {
		return nil, err
	}

	err = validateCols(usernameCol, passwordCol, user)
	if err != nil {
		return nil, err
	}

	// Parse request body into resource
	decoder := json.NewDecoder(request.Body)
	var values map[string]string
	err = decoder.Decode(&values)
	if err != nil {
		return nil, err
	}

	username := values[usernameCol]
	password := values[passwordCol]

	if username == "" || password == "" {
		return nil, errors.New("username or password is not found")
	}

	// Search db, if a username is not found, return error
	qry := fmt.Sprintf("%s = ?", usernameCol)

	qryDB := db.Where(qry, username).First(user)
	err = qryDB.Error
	if err != nil {
		return nil, err
	}

	if user == nil {
		errorMsg := fmt.Sprintf("Username not found: %s", username)
		return nil, errors.New(errorMsg)
	}

	// Make sure the password is correct
	var hashs []string
	qryDB.Pluck(passwordCol, &hashs)

	if len(hashs) == 0 {
		errorMsg := fmt.Sprintf("Unable to get value from column: %s", passwordCol)
		return nil, errors.New(errorMsg)
	}

	hashed := hashs[0]

	// Comparing the password with the hash
	err = bcrypt.CompareHashAndPassword([]byte(hashed), []byte(password))
	if err != nil {
		return nil, err
	}

	// Set current session
	SetUserSession(w, request, user)

	return user, nil
}

// HandleLogout let user logout from the system
func HandleLogout(w http.ResponseWriter, request *http.Request) {
	ClearUserSession(w, request)
}
<|endoftext|>


<commit_before>package tcp

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"sync"
	"time"
)

const (
	// DefaultTimeout is the default length of time to wait for first byte.
	DefaultTimeout = 30 * time.Second
)

// Layer represents the connection between nodes.
type Layer struct {
	ln     net.Listener
	header byte
	addr   net.Addr

	remoteEncrypted bool
	skipVerify      bool
}

// Addr returns the local address for the layer.
func (l *Layer) Addr() net.Addr {
	return l.addr
}

// Dial creates a new network connection.
func (l *Layer) Dial(addr string, timeout time.Duration) (net.Conn, error) {
	dialer := &net.Dialer{Timeout: timeout}

	var err error
	var conn net.Conn
	if l.remoteEncrypted {
		conf := &tls.Config{
			InsecureSkipVerify: l.skipVerify,
		}
		conn, err = tls.DialWithDialer(dialer, "tcp", addr, conf)
	} else {
		conn, err = dialer.Dial("tcp", addr)
	}
	if err != nil {
		return nil, err
	}

	// Write a marker byte to indicate message type.
	_, err = conn.Write([]byte{l.header})
	if err != nil {
		conn.Close()
		return nil, err
	}
	return conn, err
}

// Accept waits for the next connection.
func (l *Layer) Accept() (net.Conn, error) { return l.ln.Accept() }

// Close closes the layer.
func (l *Layer) Close() error { return l.ln.Close() }

// Mux multiplexes a network connection.
type Mux struct {
	ln   net.Listener
	addr net.Addr
	m    map[byte]*listener

	wg sync.WaitGroup

	remoteEncrypted bool

	// The amount of time to wait for the first header byte.
	Timeout time.Duration

	// Out-of-band error logger
	Logger *log.Logger

	// Path to X509 certificate
	nodeX509Cert string

	// Path to X509 key.
	nodeX509Key string

	// Whether to skip verification of other nodes' certificates.
	InsecureSkipVerify bool
}

// NewMux returns a new instance of Mux for ln. If adv is nil,
// then the addr of ln is used.
func NewMux(ln net.Listener, adv net.Addr) (*Mux, error) {
	addr := adv
	if addr == nil {
		addr = ln.Addr()
	}

	return &Mux{
		ln:      ln,
		addr:    addr,
		m:       make(map[byte]*listener),
		Timeout: DefaultTimeout,
		Logger:  log.New(os.Stderr, "[tcp] ", log.LstdFlags),
	}, nil
}

// NewTLSMux returns a new instance of Mux for ln, and encrypts all traffic
// using TLS. If adv is nil, then the addr of ln is used.
func NewTLSMux(ln net.Listener, adv net.Addr, cert, key string) (*Mux, error) {
	addr := adv
	if addr == nil {
		addr = ln.Addr()
	}

	var err error
	ln, err = newTLSListener(ln, cert, key)
	if err != nil {
		return nil, err
	}

	return &Mux{
		ln:              ln,
		addr:            addr,
		m:               make(map[byte]*listener),
		remoteEncrypted: true,
		Timeout:         DefaultTimeout,
		Logger:          log.New(os.Stderr, "[tcp] ", log.LstdFlags),
		nodeX509Cert:    cert,
		nodeX509Key:     key,
	}, nil
}

// Serve handles connections from ln and multiplexes then across registered listener.
func (mux *Mux) Serve() error {
	mux.Logger.Printf("mux serving on %s, advertising %s", mux.ln.Addr().String(), mux.addr)

	for {
		// Wait for the next connection.
		// If it returns a temporary error then simply retry.
		// If it returns any other error then exit immediately.
		conn, err := mux.ln.Accept()
		if err, ok := err.(interface {
			Temporary() bool
		}); ok && err.Temporary() {
			continue
		}
		if err != nil {
			// Wait for all connections to be demuxed
			mux.wg.Wait()
			for _, ln := range mux.m {
				close(ln.c)
			}
			return err
		}

		// Demux in a goroutine to
		mux.wg.Add(1)
		go mux.handleConn(conn)
	}
}

func (mux *Mux) handleConn(conn net.Conn) {
	defer mux.wg.Done()
	// Set a read deadline so connections with no data don't timeout.
	if err := conn.SetReadDeadline(time.Now().Add(mux.Timeout)); err != nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: cannot set read deadline: %s", err)
		return
	}

	// Read first byte from connection to determine handler.
	var typ [1]byte
	if _, err := io.ReadFull(conn, typ[:]); err != nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: cannot read header byte: %s", err)
		return
	}

	// Reset read deadline and let the listener handle that.
	if err := conn.SetReadDeadline(time.Time{}); err != nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: cannot reset set read deadline: %s", err)
		return
	}

	// Retrieve handler based on first byte.
	handler := mux.m[typ[0]]
	if handler == nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: handler not registered: %d", typ[0])
		return
	}

	// Send connection to handler.  The handler is responsible for closing the connection.
	handler.c <- conn
}

// Listen returns a listener identified by header.
// Any connection accepted by mux is multiplexed based on the initial header byte.
func (mux *Mux) Listen(header byte) *Layer {
	// Ensure two listeners are not created for the same header byte.
	if _, ok := mux.m[header]; ok {
		panic(fmt.Sprintf("listener already registered under header byte: %d", header))
	}

	// Create a new listener and assign it.
	ln := &listener{
		c: make(chan net.Conn),
	}
	mux.m[header] = ln

	layer := &Layer{
		ln:              ln,
		header:          header,
		addr:            mux.addr,
		remoteEncrypted: mux.remoteEncrypted,
		skipVerify:      mux.InsecureSkipVerify,
	}

	return layer
}

// listener is a receiver for connections received by Mux.
type listener struct {
	c chan net.Conn
}

// Accept waits for and returns the next connection to the listener.
func (ln *listener) Accept() (c net.Conn, err error) {
	conn, ok := <-ln.c
	if !ok {
		return nil, errors.New("network connection closed")
	}
	return conn, nil
}

// Close is a no-op. The mux's listener should be closed instead.
func (ln *listener) Close() error { return nil }

// Addr always returns nil
func (ln *listener) Addr() net.Addr { return nil }

// newTLSListener returns a net listener which encrypts the traffic using TLS.
func newTLSListener(ln net.Listener, certFile, keyFile string) (net.Listener, error) {
	config, err := createTLSConfig(certFile, keyFile)
	if err != nil {
		return nil, err
	}

	return tls.NewListener(ln, config), nil
}

// createTLSConfig returns a TLS config from the given cert and key.
func createTLSConfig(certFile, keyFile string) (*tls.Config, error) {
	var err error
	config := &tls.Config{}
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}
	return config, nil
}
<commit_msg>Simplify creation of TLS mux<commit_after>package tcp

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"sync"
	"time"
)

const (
	// DefaultTimeout is the default length of time to wait for first byte.
	DefaultTimeout = 30 * time.Second
)

// Layer represents the connection between nodes.
type Layer struct {
	ln     net.Listener
	header byte
	addr   net.Addr

	remoteEncrypted bool
	skipVerify      bool
}

// Addr returns the local address for the layer.
func (l *Layer) Addr() net.Addr {
	return l.addr
}

// Dial creates a new network connection.
func (l *Layer) Dial(addr string, timeout time.Duration) (net.Conn, error) {
	dialer := &net.Dialer{Timeout: timeout}

	var err error
	var conn net.Conn
	if l.remoteEncrypted {
		conf := &tls.Config{
			InsecureSkipVerify: l.skipVerify,
		}
		conn, err = tls.DialWithDialer(dialer, "tcp", addr, conf)
	} else {
		conn, err = dialer.Dial("tcp", addr)
	}
	if err != nil {
		return nil, err
	}

	// Write a marker byte to indicate message type.
	_, err = conn.Write([]byte{l.header})
	if err != nil {
		conn.Close()
		return nil, err
	}
	return conn, err
}

// Accept waits for the next connection.
func (l *Layer) Accept() (net.Conn, error) { return l.ln.Accept() }

// Close closes the layer.
func (l *Layer) Close() error { return l.ln.Close() }

// Mux multiplexes a network connection.
type Mux struct {
	ln   net.Listener
	addr net.Addr
	m    map[byte]*listener

	wg sync.WaitGroup

	remoteEncrypted bool

	// The amount of time to wait for the first header byte.
	Timeout time.Duration

	// Out-of-band error logger
	Logger *log.Logger

	// Path to X509 certificate
	nodeX509Cert string

	// Path to X509 key.
	nodeX509Key string

	// Whether to skip verification of other nodes' certificates.
	InsecureSkipVerify bool
}

// NewMux returns a new instance of Mux for ln. If adv is nil,
// then the addr of ln is used.
func NewMux(ln net.Listener, adv net.Addr) (*Mux, error) {
	addr := adv
	if addr == nil {
		addr = ln.Addr()
	}

	return &Mux{
		ln:      ln,
		addr:    addr,
		m:       make(map[byte]*listener),
		Timeout: DefaultTimeout,
		Logger:  log.New(os.Stderr, "[tcp] ", log.LstdFlags),
	}, nil
}

// NewTLSMux returns a new instance of Mux for ln, and encrypts all traffic
// using TLS. If adv is nil, then the addr of ln is used.
func NewTLSMux(ln net.Listener, adv net.Addr, cert, key string) (*Mux, error) {
	mux, err := NewMux(ln, adv)
	if err != nil {
		return nil, err
	}

	mux.ln, err = newTLSListener(mux.ln, cert, key)
	if err != nil {
		return nil, err
	}
	mux.remoteEncrypted = true
	mux.nodeX509Cert = cert
	mux.nodeX509Key = key

	return mux, nil
}

// Serve handles connections from ln and multiplexes then across registered listener.
func (mux *Mux) Serve() error {
	mux.Logger.Printf("mux serving on %s, advertising %s", mux.ln.Addr().String(), mux.addr)

	for {
		// Wait for the next connection.
		// If it returns a temporary error then simply retry.
		// If it returns any other error then exit immediately.
		conn, err := mux.ln.Accept()
		if err, ok := err.(interface {
			Temporary() bool
		}); ok && err.Temporary() {
			continue
		}
		if err != nil {
			// Wait for all connections to be demuxed
			mux.wg.Wait()
			for _, ln := range mux.m {
				close(ln.c)
			}
			return err
		}

		// Demux in a goroutine to
		mux.wg.Add(1)
		go mux.handleConn(conn)
	}
}

func (mux *Mux) handleConn(conn net.Conn) {
	defer mux.wg.Done()
	// Set a read deadline so connections with no data don't timeout.
	if err := conn.SetReadDeadline(time.Now().Add(mux.Timeout)); err != nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: cannot set read deadline: %s", err)
		return
	}

	// Read first byte from connection to determine handler.
	var typ [1]byte
	if _, err := io.ReadFull(conn, typ[:]); err != nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: cannot read header byte: %s", err)
		return
	}

	// Reset read deadline and let the listener handle that.
	if err := conn.SetReadDeadline(time.Time{}); err != nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: cannot reset set read deadline: %s", err)
		return
	}

	// Retrieve handler based on first byte.
	handler := mux.m[typ[0]]
	if handler == nil {
		conn.Close()
		mux.Logger.Printf("tcp.Mux: handler not registered: %d", typ[0])
		return
	}

	// Send connection to handler.  The handler is responsible for closing the connection.
	handler.c <- conn
}

// Listen returns a listener identified by header.
// Any connection accepted by mux is multiplexed based on the initial header byte.
func (mux *Mux) Listen(header byte) *Layer {
	// Ensure two listeners are not created for the same header byte.
	if _, ok := mux.m[header]; ok {
		panic(fmt.Sprintf("listener already registered under header byte: %d", header))
	}

	// Create a new listener and assign it.
	ln := &listener{
		c: make(chan net.Conn),
	}
	mux.m[header] = ln

	layer := &Layer{
		ln:              ln,
		header:          header,
		addr:            mux.addr,
		remoteEncrypted: mux.remoteEncrypted,
		skipVerify:      mux.InsecureSkipVerify,
	}

	return layer
}

// listener is a receiver for connections received by Mux.
type listener struct {
	c chan net.Conn
}

// Accept waits for and returns the next connection to the listener.
func (ln *listener) Accept() (c net.Conn, err error) {
	conn, ok := <-ln.c
	if !ok {
		return nil, errors.New("network connection closed")
	}
	return conn, nil
}

// Close is a no-op. The mux's listener should be closed instead.
func (ln *listener) Close() error { return nil }

// Addr always returns nil
func (ln *listener) Addr() net.Addr { return nil }

// newTLSListener returns a net listener which encrypts the traffic using TLS.
func newTLSListener(ln net.Listener, certFile, keyFile string) (net.Listener, error) {
	config, err := createTLSConfig(certFile, keyFile)
	if err != nil {
		return nil, err
	}

	return tls.NewListener(ln, config), nil
}

// createTLSConfig returns a TLS config from the given cert and key.
func createTLSConfig(certFile, keyFile string) (*tls.Config, error) {
	var err error
	config := &tls.Config{}
	config.Certificates = make([]tls.Certificate, 1)
	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
	if err != nil {
		return nil, err
	}
	return config, nil
}
<|endoftext|>


<commit_before>package admin_test

import (
	"fmt"
	"testing"

	"github.com/qor/qor"
	"github.com/qor/qor/admin"

	_ "github.com/mattn/go-sqlite3"
)

// Template helpers test

func TestLinkTo(t *testing.T) {
	context := &admin.Context{Admin: Admin}

	link := context.LinkTo("test link", "/link")

	if link != "test link" {
		t.Error("link not generated by LinkTo")
	}
}

func TestUrlForAdmin(t *testing.T) {
	context := &admin.Context{Admin: Admin}

	rootLink := context.UrlFor(Admin)

	if rootLink != "/admin" {
		t.Error("Admin link not generated by UrlFor")
	}
}

func TestUrlForResource(t *testing.T) {
	context := &admin.Context{Admin: Admin}
	user := Admin.GetResource("user")

	userLink := context.UrlFor(user)

	if userLink != "/admin/user" {
		t.Error("resource link not generated by UrlFor")
	}
}

func TestUrlForResourceName(t *testing.T) {
	user := &User{Name: "test"}
	db.Create(&user)

	context := &admin.Context{Admin: Admin, Context: &qor.Context{}}
	context.SetDB(db)

	userLink := context.UrlFor(user)

	if userLink != "/admin/user/"+fmt.Sprintf("%v", user.Id) {
		t.Error("resource link not generated by UrlFor")
	}
}

func TestPagination(t *testing.T) {
	context := &admin.Context{Admin: Admin}
	context.Searcher = &admin.Searcher{Context: context}

	// Test current page 1
	context.Searcher.Pagination.Pages = 10
	context.Searcher.Pagination.CurrentPage = 1

	pages := context.Pagination()

	if !pages[0].Current {
		t.Error("first page not set as current page")
	}

	// +1 for "Next page" link which is a "Page" too
	if len(pages) != admin.VISIBLE_PAGE_COUNT+1 {
		t.Error("visible pages in current context beyond the bound of VISIBLE_PAGE_COUNT")
	}

	// Test current page 8 => the length between start and end less than MAX_VISIBLE_PAGES
	context.Searcher.Pagination.CurrentPage = 8
	pages = context.Pagination()

	if !pages[6].Current {
		t.Error("visible previous pages count incorrect")
	}

	// 1 for "Prev"
	if len(pages) != admin.VISIBLE_PAGE_COUNT+1 {
		t.Error("visible pages in current context beyond the bound of VISIBLE_PAGE_COUNT")
	}

	// Test current page at last
	context.Searcher.Pagination.CurrentPage = 10
	pages = context.Pagination()

	if !pages[len(pages)-1].Current {
		t.Error("last page is not the current page")
	}

	if len(pages) != admin.VISIBLE_PAGE_COUNT+1 {
		t.Error("visible pages count is incorrect")
	}

	// Test current page at last but total page count less than VISIBLE_PAGE_COUNT
	context.Searcher.Pagination.Pages = 5
	context.Searcher.Pagination.CurrentPage = 5
	pages = context.Pagination()

	if len(pages) != 5 {
		t.Error("incorrect pages count")
	}
}
<commit_msg>No pagination if only has one page<commit_after>package admin_test

import (
	"fmt"
	"testing"

	"github.com/qor/qor"
	"github.com/qor/qor/admin"

	_ "github.com/mattn/go-sqlite3"
)

// Template helpers test

func TestLinkTo(t *testing.T) {
	context := &admin.Context{Admin: Admin}

	link := context.LinkTo("test link", "/link")

	if link != "test link" {
		t.Error("link not generated by LinkTo")
	}
}

func TestUrlForAdmin(t *testing.T) {
	context := &admin.Context{Admin: Admin}

	rootLink := context.UrlFor(Admin)

	if rootLink != "/admin" {
		t.Error("Admin link not generated by UrlFor")
	}
}

func TestUrlForResource(t *testing.T) {
	context := &admin.Context{Admin: Admin}
	user := Admin.GetResource("user")

	userLink := context.UrlFor(user)

	if userLink != "/admin/user" {
		t.Error("resource link not generated by UrlFor")
	}
}

func TestUrlForResourceName(t *testing.T) {
	user := &User{Name: "test"}
	db.Create(&user)

	context := &admin.Context{Admin: Admin, Context: &qor.Context{}}
	context.SetDB(db)

	userLink := context.UrlFor(user)

	if userLink != "/admin/user/"+fmt.Sprintf("%v", user.Id) {
		t.Error("resource link not generated by UrlFor")
	}
}

func TestPagination(t *testing.T) {
	context := &admin.Context{Admin: Admin}
	context.Searcher = &admin.Searcher{Context: context}

	// Test no pagination if only has one page
	context.Searcher.Pagination.Pages = 1
	context.Searcher.Pagination.CurrentPage = 1
	pages := *context.Pagination()
	if pages != nil {
		t.Error("Don't display pagination if only has one page")
	}

	// Test current page 1
	context.Searcher.Pagination.Pages = 10
	context.Searcher.Pagination.CurrentPage = 1

	pages = *context.Pagination()

	if !pages[0].Current {
		t.Error("first page not set as current page")
	}

	// +1 for "Next page" link which is a "Page" too
	if len(pages) != admin.VISIBLE_PAGE_COUNT+1 {
		t.Error("visible pages in current context beyond the bound of VISIBLE_PAGE_COUNT")
	}

	// Test current page 8 => the length between start and end less than MAX_VISIBLE_PAGES
	context.Searcher.Pagination.CurrentPage = 8
	pages = *context.Pagination()

	if !pages[6].Current {
		t.Error("visible previous pages count incorrect")
	}

	// 1 for "Prev"
	if len(pages) != admin.VISIBLE_PAGE_COUNT+1 {
		t.Error("visible pages in current context beyond the bound of VISIBLE_PAGE_COUNT")
	}

	// Test current page at last
	context.Searcher.Pagination.CurrentPage = 10
	pages = *context.Pagination()

	if !pages[len(pages)-1].Current {
		t.Error("last page is not the current page")
	}

	if len(pages) != admin.VISIBLE_PAGE_COUNT+1 {
		t.Error("visible pages count is incorrect")
	}

	// Test current page at last but total page count less than VISIBLE_PAGE_COUNT
	context.Searcher.Pagination.Pages = 5
	context.Searcher.Pagination.CurrentPage = 5
	pages = *context.Pagination()

	if len(pages) != 5 {
		t.Error("incorrect pages count")
	}
}
<|endoftext|>


<commit_before>package main

// A snapshot transcription of the hystrix.stream JSON object
// This is here for legacy support only. Only update if the fields change or
// In the event of an inevitable bug.
type HystrixStream struct {
	// Forgive my ridiculous formatting in this ridiculous object
	CurrentConcurrentExecutionCount int64  `json:"currentConcurrentExecutionCount,int64"`
	CurrentTime          string            `json:"currentTime,string"`
	ErrorPercentage      int64             `json:"errorPercentage,int64"`
	ErrorCount           int64             `json:"errorCount,int64"`
	Group                string            `json:"group,string"`
	IsCircuitBreakerOpen bool              `json:"isCircuitBreakerOpen,bool"`
	LatencyExecute       HystrixHistogram  `json:"latencyExecute,HystrixHistogram"`
	LatencyExecuteMean   int64             `json:"latencyExecute_mean,int64"`
	LatencyTotal         HystrixHistogram  `json:"latencyTotal,HystrixHistogram"`
	LatencyTotalMean     int64             `json:"latencyTotal_mean,int64"`
	Name                 string            `json:"name,string"`
	ReportingHosts       int64             `json:"reportingHosts,int64"`
	RequestCount         int64             `json:"requestCount,int64"`
	RollingCountCollapsedRequests   int64  `json:"rollingCountCollapsedRequests,int64"`
	RollingCountExceptionsThrown    int64  `json:"rollingCountExceptionsThrown,int64"`
	RollingCountFailure             int64  `json:"rollingCountFailure,int64"`
	RollingCountFallbackFailure     int64  `json:"rollingCountFallbackFailure,int64"`
	RollingCountFallbackRejection   int64  `json:"rollingCountFallbackRejection,int64"`
	RollingCountResponseFromCache   int64  `json:"rollingCountResponseFromCache,int64"`
	RollingCountSemaphoreRejected   int64  `json:"rollingCountSemaphoreRejected,int64"`
	RollingCountShortCircuited      int64  `json:"rollingCountShortCircuited,int64"`
	RollingCountSuccess             int64  `json:"rollingCountSuccess,int64"`
	RollingCountThreadPoolRejected  int64  `json:"rollingCountThreadPoolRejected,int64"`
	RollingCountTimeout             int64  `json:"rollingCOuntTimeout,int64"`
	Type                            string `json:"type,string"`
	// Don't blame me for these awful names.
	// I'm preserving the bad names Hystrix uses
	PropertyValueCircuitBreakerEnabled                            bool   `json:"propertyValue_circuitBreakerEnabled,bool"`
	PropertyValueCircuitBreakerErrorThresholdPercentage           int64  `json:"propertyValue_circuitBreakerErrorThresholdPercentage,int64"`
	PropertyValueCircuitBreakerForceOpen                          bool   `json:"propertyValue_circuitBreakerForceOpen,bool"`
	PropertyValueCircuitBreakerForceClosed                        bool   `json:"propertyValue_circuitBreakerForceClosed,bool"`
	PropertyValueCircuitBreakerRequestVolumeThreshold             int64  `json:"propertyValue_circuitBreakerRequestVolumeThreshold,int64"`
	PropertyValueCircuitBreakerSleepWindowInMilliseconds          int64  `json:"propertyValue_circuitBreakerSleepWindowInMilliseconds,int64"`
	PropertyValueExecutionIsolationSemaphoreMaxConcurrentRequests int64  `json:"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests,int64"`
	PropertyValueExecutionIsolationStrategy                       string `json:"propertyValue_executionIsolationStrategy,string"`
	PropertyValueExecutionIsolationThreadPoolKeyOverride          string `json:"propertyValue_executionIsolationThreadPoolKeyOverride,string"`
	PropertyValueExecutionIsolationThreadTimeoutInMilliseconds    int64  `json:"propertyValue_executionIsolationThreadTimeoutInMilliseconds,string"`
	PropertyValueFallbackIsolationSemaphoreMaxConcurrentRequests  int64  `json:"propertyValue_fallbackIsolationSeampahoreMaxConcurrentRequests,int64"`
	PropertyValueMetricsRollingStatisticalWindowInMilliseconds    int64  `json:"propertyValue_metricsRollingStatisticalWindowInMilliseconds,int64"`
	PropertyValueRequestCacheEnabled                              bool   `json:"propertyValue_requestCacheEnabled,bool"`
	PropertyValueRequestLogEnabled                                bool   `json:"propertyValue_requestLogEnabled,bool"`
}

// A snapshot transcription of the histogram objects hystrix.stream JSON object
// This is here for legacy support only. Only update if the fields change or
// In the event of an inevitable bug.
type HystrixHistogram struct {
	//minimum
	Percentile0   int64 `json:"0,int64"`
	Percentile25  int64 `json:"25,int64"`
	//median
	Percentile50  int64 `json:"50,int64"`
	Percentile75  int64 `json:"75,int64"`
	Percentile90  int64 `json:"90,int64"`
	Percentile95  int64 `json:"95,int64"`
	Percentile99  int64 `json:"99,int64"`
	Percentile995 int64 `json:"99.5,int64"`
	//maximum
	Percentile100 int64 `json:"100,int64"`
}

func (s SSEString) ParseHystrixStream() (HystrixStream, error) {
	// The eventsource string isn't big short circuit
	if len(s) < 8 {
		return HystrixStream{}, errors.New("Event string too short to parse")
	}

	// The eventsource string isn't data
	if s[:6] != "data: " {
		return HystrixStream{}, errors.New("Can't parse non-data event")
	}

	// Try to parse JSON
	var ret HystrixStream
	resp := json.Unmarshal([]byte(s[7:]), &ret)

	if resp == nil {
		return ret, nil
	} else {
		return HystrixStream{}, resp
	}
}

func (h HystrixHistogram) ToLatencyHistogram(mean int64) LatencyHistogram {
	return LatencyHistogram {
		Mean: mean,
		Median: h.Percentile50,
		Min: h.Percentile0,
		Max: h.Percentile100,
		Percentile25: h.Percentile25,
		Percentile75: h.Percentile75,
		Percentile90: h.Percentile90,
		Percentile95: h.Percentile95,
		Percentile99: h.Percentile99,
		Percentile995: h.Percentile995,
		// Unfortunately, the closest we have is an estimate between 99.5 and 100. We'll take it
		Percentile999: (h.Percentile100 + h.Percentile995) / 2,
	}
}

func (h HystrixStream) ToCircuitBreaker() (CircuitBreaker, error) {
	var breakerCount BreakerCount
	if h.IsCircuitBreakerOpen {
		breakerCount = BreakerCount{OpenCount: 1, ClosedCount: 0}
	} else {
		breakerCount = BreakerCount{OpenCount: 0, ClosedCount: 1}
	}

	var currentTime time.Time

	// This is how I parse the time.
	parsedTime, err := strconv.Atoi(h.CurrentTime)
	if err != nil {
		return CircuitBreaker{}, err
	} else {
		// Split hystrix ms encoded unix time into s and ns
		currentTime = time.Unix(int64(parsedTime / 1000), int64((parsedTime % 1000) * 1000))
	}

	return CircuitBreaker {
		Name: h.Group + h.Name,
		SuccessCount: h.RollingCountSuccess,
		FailCount: 1,
		FallbackCount: 1,
		ShortCircuitCount: 1,
		WindowDuration: 1,
		CurrentTime: currentTime,
		BreakerStatus: breakerCount,
		Latency: h.LatencyTotal.ToLatencyHistogram(h.LatencyTotalMean),
	}, nil
}

<commit_msg>Update hystrix.go<commit_after>package main

// A snapshot transcription of the hystrix.stream JSON object
// This is here for legacy support only. Only update if the fields change or
// In the event of an inevitable bug.
type HystrixStream struct {
	// Forgive my ridiculous formatting in this ridiculous object
	CurrentConcurrentExecutionCount int64  `json:"currentConcurrentExecutionCount,int64"`
	CurrentTime          string            `json:"currentTime,string"`
	ErrorPercentage      int64             `json:"errorPercentage,int64"`
	ErrorCount           int64             `json:"errorCount,int64"`
	Group                string            `json:"group,string"`
	IsCircuitBreakerOpen bool              `json:"isCircuitBreakerOpen,bool"`
	LatencyExecute       HystrixHistogram  `json:"latencyExecute,HystrixHistogram"`
	LatencyExecuteMean   int64             `json:"latencyExecute_mean,int64"`
	LatencyTotal         HystrixHistogram  `json:"latencyTotal,HystrixHistogram"`
	LatencyTotalMean     int64             `json:"latencyTotal_mean,int64"`
	Name                 string            `json:"name,string"`
	ReportingHosts       int64             `json:"reportingHosts,int64"`
	RequestCount         int64             `json:"requestCount,int64"`
	RollingCountCollapsedRequests   int64  `json:"rollingCountCollapsedRequests,int64"`
	RollingCountExceptionsThrown    int64  `json:"rollingCountExceptionsThrown,int64"`
	RollingCountFailure             int64  `json:"rollingCountFailure,int64"`
	RollingCountFallbackFailure     int64  `json:"rollingCountFallbackFailure,int64"`
	RollingCountFallbackRejection   int64  `json:"rollingCountFallbackRejection,int64"`
	RollingCountResponseFromCache   int64  `json:"rollingCountResponseFromCache,int64"`
	RollingCountSemaphoreRejected   int64  `json:"rollingCountSemaphoreRejected,int64"`
	RollingCountShortCircuited      int64  `json:"rollingCountShortCircuited,int64"`
	RollingCountSuccess             int64  `json:"rollingCountSuccess,int64"`
	RollingCountThreadPoolRejected  int64  `json:"rollingCountThreadPoolRejected,int64"`
	RollingCountTimeout             int64  `json:"rollingCOuntTimeout,int64"`
	Type                            string `json:"type,string"`
	// Don't blame me for these awful names.
	// I'm preserving the bad names Hystrix uses
	PropertyValueCircuitBreakerEnabled                            bool   `json:"propertyValue_circuitBreakerEnabled,bool"`
	PropertyValueCircuitBreakerErrorThresholdPercentage           int64  `json:"propertyValue_circuitBreakerErrorThresholdPercentage,int64"`
	PropertyValueCircuitBreakerForceOpen                          bool   `json:"propertyValue_circuitBreakerForceOpen,bool"`
	PropertyValueCircuitBreakerForceClosed                        bool   `json:"propertyValue_circuitBreakerForceClosed,bool"`
	PropertyValueCircuitBreakerRequestVolumeThreshold             int64  `json:"propertyValue_circuitBreakerRequestVolumeThreshold,int64"`
	PropertyValueCircuitBreakerSleepWindowInMilliseconds          int64  `json:"propertyValue_circuitBreakerSleepWindowInMilliseconds,int64"`
	PropertyValueExecutionIsolationSemaphoreMaxConcurrentRequests int64  `json:"propertyValue_executionIsolationSemaphoreMaxConcurrentRequests,int64"`
	PropertyValueExecutionIsolationStrategy                       string `json:"propertyValue_executionIsolationStrategy,string"`
	PropertyValueExecutionIsolationThreadPoolKeyOverride          string `json:"propertyValue_executionIsolationThreadPoolKeyOverride,string"`
	PropertyValueExecutionIsolationThreadTimeoutInMilliseconds    int64  `json:"propertyValue_executionIsolationThreadTimeoutInMilliseconds,string"`
	PropertyValueFallbackIsolationSemaphoreMaxConcurrentRequests  int64  `json:"propertyValue_fallbackIsolationSeampahoreMaxConcurrentRequests,int64"`
	PropertyValueMetricsRollingStatisticalWindowInMilliseconds    int64  `json:"propertyValue_metricsRollingStatisticalWindowInMilliseconds,int64"`
	PropertyValueRequestCacheEnabled                              bool   `json:"propertyValue_requestCacheEnabled,bool"`
	PropertyValueRequestLogEnabled                                bool   `json:"propertyValue_requestLogEnabled,bool"`
}

// A snapshot transcription of the histogram objects hystrix.stream JSON object
// This is here for legacy support only. Only update if the fields change or
// In the event of an inevitable bug.
type HystrixHistogram struct {
	//minimum
	Percentile0   int64 `json:"0,int64"`
	Percentile25  int64 `json:"25,int64"`
	//median
	Percentile50  int64 `json:"50,int64"`
	Percentile75  int64 `json:"75,int64"`
	Percentile90  int64 `json:"90,int64"`
	Percentile95  int64 `json:"95,int64"`
	Percentile99  int64 `json:"99,int64"`
	Percentile995 int64 `json:"99.5,int64"`
	//maximum
	Percentile100 int64 `json:"100,int64"`
}

func (h HystrixHistogram) ToLatencyHistogram(mean int64) LatencyHistogram {
	return LatencyHistogram {
		Mean: mean,
		Median: h.Percentile50,
		Min: h.Percentile0,
		Max: h.Percentile100,
		Percentile25: h.Percentile25,
		Percentile75: h.Percentile75,
		Percentile90: h.Percentile90,
		Percentile95: h.Percentile95,
		Percentile99: h.Percentile99,
		Percentile995: h.Percentile995,
		// Unfortunately, the closest we have is an estimate between 99.5 and 100. We'll take it
		Percentile999: (h.Percentile100 + h.Percentile995) / 2,
	}
}

func (h HystrixStream) ToCircuitBreaker() (CircuitBreaker, error) {
	var breakerCount BreakerCount
	if h.IsCircuitBreakerOpen {
		breakerCount = BreakerCount{OpenCount: 1, ClosedCount: 0}
	} else {
		breakerCount = BreakerCount{OpenCount: 0, ClosedCount: 1}
	}

	var currentTime time.Time

	// This is how I parse the time.
	parsedTime, err := strconv.Atoi(h.CurrentTime)
	if err != nil {
		return CircuitBreaker{}, err
	} else {
		// Split hystrix ms encoded unix time into s and ns
		currentTime = time.Unix(int64(parsedTime / 1000), int64((parsedTime % 1000) * 1000))
	}

	return CircuitBreaker {
		Name: h.Group + h.Name,
		SuccessCount: h.RollingCountSuccess,
		FailCount: 1,
		FallbackCount: 1,
		ShortCircuitCount: 1,
		WindowDuration: 1,
		CurrentTime: currentTime,
		BreakerStatus: breakerCount,
		Latency: h.LatencyTotal.ToLatencyHistogram(h.LatencyTotalMean),
	}, nil
}

<|endoftext|>


<commit_before>package flash_message

import (
	"os"
	"testing"

	"github.com/oinume/lekcije/backend/assertion"

	"github.com/oinume/lekcije/backend/config"
	"github.com/oinume/lekcije/backend/model"
)

var (
	storeMySQL *StoreMySQL
)

func TestMain(m *testing.M) {
	helper := model.NewTestHelper()
	config.MustProcessDefault()
	db := helper.DB(nil)
	defer func() { _ = db.Close() }()
	storeMySQL = NewStoreMySQL(db)

	os.Exit(m.Run())
}

func TestStoreMySQL_Save_Load(t *testing.T) {
	t.Parallel()
	tests := map[string]struct {
		want *FlashMessage
	}{
		"ok": {
			want: New(KindInfo, "データの削除に成功しました"),
		},
	}
	for name, test := range tests {
		test := test
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			if err := storeMySQL.Save(test.want); err != nil {
				t.Fatalf("Save() failed: %v", err)
			}
			got, err := storeMySQL.Load(test.want.Key)
			if err != nil {
				t.Fatalf("Load() failed: %v", err)
			}
			assertion.RequireEqual(t, test.want.Messages, got.Messages, "unexpected flash message")
		})
	}
}
<commit_msg>Add assertion package for unit test<commit_after>package flash_message

import (
	"os"
	"testing"

	"github.com/oinume/lekcije/backend/assertion"
	"github.com/oinume/lekcije/backend/config"
	"github.com/oinume/lekcije/backend/model"
)

var (
	storeMySQL *StoreMySQL
)

func TestMain(m *testing.M) {
	helper := model.NewTestHelper()
	config.MustProcessDefault()
	db := helper.DB(nil)
	defer func() { _ = db.Close() }()
	storeMySQL = NewStoreMySQL(db)

	os.Exit(m.Run())
}

func TestStoreMySQL_Save_Load(t *testing.T) {
	t.Parallel()
	tests := map[string]struct {
		want *FlashMessage
	}{
		"ok": {
			want: New(KindInfo, "データの削除に成功しました"),
		},
	}
	for name, test := range tests {
		test := test
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			if err := storeMySQL.Save(test.want); err != nil {
				t.Fatalf("Save() failed: %v", err)
			}
			got, err := storeMySQL.Load(test.want.Key)
			if err != nil {
				t.Fatalf("Load() failed: %v", err)
			}
			assertion.RequireEqual(t, test.want.Messages, got.Messages, "unexpected flash message")
		})
	}
}
<|endoftext|>


<commit_before>package objects

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/godbus/dbus"
	"github.com/godbus/dbus/prop"

	"github.com/muka/device-manager/api"
	"github.com/muka/device-manager/db"
	"github.com/muka/device-manager/service"
	"github.com/muka/device-manager/util"
)

// DeviceManagerDatabasePath path to the database file
var deviceManagerDatabasePath = "./data/devices.db"

// DeviceManagerTableName Name of the table containing the devices
var deviceManagerTableName = "Devices"

var deviceManagerFields = []db.DatasetField{
	{"Id", "text", "unique", true},
	{Name: "Name", Type: "text"},
	{Name: "Description", Type: "text"},
	{Name: "Path", Type: "text"},
	{Name: "Protocol", Type: "text"},
	{Name: "Properties", Type: "text"},
	{Name: "Streams", Type: "text"},
}

// NewDeviceManager initialize a new DeviceManager object
func NewDeviceManager() *DeviceManager {
	d := DeviceManager{}

	dmlogger, err := util.NewLogger(d.GetInterface())
	util.CheckError(err)

	d.logger = dmlogger

	d.Devices = make([]dbus.ObjectPath, 0)
	d.services = make(map[string]*service.Service)
	d.devices = make(map[string]*DeviceDefinition)
	d.path = DeviceManagerPath
	d.iface = DeviceManagerInterface
	d.dataset = db.NewSqliteDataSet(deviceManagerTableName, deviceManagerFields, deviceManagerDatabasePath)

	d.restoreDevices()

	return &d
}

// DeviceManager manages devices in the gateway
type DeviceManager struct {
	api.Proxy

	Devices  []dbus.ObjectPath
	services map[string]*service.Service
	devices  map[string]*DeviceDefinition

	path    string
	iface   string
	logger  *log.Logger
	dataset db.DataSet
}

// GetPath return object path
func (d *DeviceManager) GetPath() string {
	return d.path
}

// SetPath set object path
func (d *DeviceManager) SetPath(s string) {
	d.path = s
}

// GetInterface return interface
func (d *DeviceManager) GetInterface() string {
	return d.iface
}

// SetInterface return interface
func (d *DeviceManager) SetInterface(s string) {
	d.iface = s
}

//SetLogger set default logger
func (d *DeviceManager) SetLogger(logger *log.Logger) {
	d.logger = logger
}

//GetLogger return default logger
func (d *DeviceManager) GetLogger() *log.Logger {
	return d.logger
}

//GetProperties return properties
func (d *DeviceManager) GetProperties() map[string]map[string]*prop.Prop {
	return map[string]map[string]*prop.Prop{
		d.GetInterface(): {
			"Devices": {
				Value:    d.Devices,
				Writable: false,
				Emit:     prop.EmitTrue,
				Callback: func(c *prop.Change) *dbus.Error {
					d.logger.Printf("Changed value %s=%v on %s", c.Name, c.Value, c.Iface)
					return nil
				},
			},
		},
	}
}

//restoreDevices reinitialize DBus instances of stored devices
func (d *DeviceManager) restoreDevices() {

	d.logger.Println("Restoring previous device instances")

	rows, err := d.dataset.Find(nil)
	util.CheckError(err)

	defer rows.Close()
	for rows.Next() {
		dev := new(DeviceDefinition)
		var strStreams, strProperties, strPath, strProtocol string
		err := rows.Scan(
			&dev.Id,
			&dev.Name,
			&dev.Description,
			&strPath,
			&strProtocol,
			&strProperties,
			&strStreams,
		)
		util.CheckError(err)

		dev.Protocol = dbus.ObjectPath(strProtocol)
		dev.Path = dbus.ObjectPath(strPath)

		json.Unmarshal([]byte(strProperties), dev.Properties)
		json.Unmarshal([]byte(strProperties), dev.Streams)

		d.logger.Printf("Loading device %s (%s)", dev.Name, dev.Id)
		d.startDeviceInstance(*dev)
	}

}

//startDeviceInstance reinitialize DBus instances of stored devices
func (d *DeviceManager) startDeviceInstance(dev DeviceDefinition) error {

	device := NewDevice(dev)

	service, mErr := service.GetManager().Start(device)
	if mErr != nil {
		msg := fmt.Sprintf("Cannot start Device service: %s\n", mErr.Error())
		d.logger.Fatalf(msg)
		return errors.New(msg)
	}

	dev.Path = dbus.ObjectPath(device.GetPath())

	d.Devices = append(d.Devices, dev.Path)
	d.devices[dev.Id] = &dev
	d.services[dev.Id] = service

	return nil
}

func (d *DeviceManager) saveDevice(dev DeviceDefinition) error {

	jsonProperties, err := json.Marshal(dev.Properties)
	if err != nil {
		return err
	}

	jsonStreams, err := json.Marshal(dev.Streams)
	if err != nil {
		return err
	}

	err = d.dataset.Save(
		[]db.FieldValue{
			{Name: "Id", Value: dev.Id},
			{Name: "Name", Value: dev.Name},
			{Name: "Description", Value: dev.Description},
			{Name: "Path", Value: string(dev.Path)},
			{Name: "Protocol", Value: string(dev.Protocol)},
			{Name: "Properties", Value: string(jsonProperties)},
			{Name: "Streams", Value: string(jsonStreams)},
		},
	)

	if err != nil {
		d.logger.Printf("Error on save: %v\n", err)
		return err
	}

	return nil
}

// -----
// Dbus API implementation

// Find search for devices
func (d *DeviceManager) Find(q *BaseQuery) (devices []dbus.ObjectPath, err *dbus.Error) {
	d.logger.Println("DeviceManager.Find() not implemented")

	var query = db.Query{}
	if q.Criteria != nil {
		query.Criteria = make([]db.Criteria, len(q.Criteria))
		var i = 0
		for key, val := range q.Criteria {

			var op = "="
			var value = val

			if strings.Contains(value, "%") {
				op = "LIKE"
				value = strings.Replace(value, "*", "%", 0)
			}

			query.Criteria[i] = db.Criteria{
				Prefix:    "",
				Field:     key,
				Operation: op,
				Value:     value,
				Suffix:    "",
			}

			i++
		}
	}

	query.Limit = db.Limit{}
	if q.Offset > 0 {
		query.Limit.Offset = int(q.Offset)
	}
	if q.Limit > 0 {
		query.Limit.Size = int(q.Limit)
	}

	// rows, err := d.dataset.Find(&query)

	return d.Devices, err
}

// Create add a device
func (d *DeviceManager) Create(dev DeviceDefinition) (dbus.ObjectPath, *dbus.Error) {

	var err error

	id := util.GenerateID()
	d.logger.Printf("Create new device %s\n", id)
	d.logger.Printf("Data:\n %v\n", dev)
	dev.Id = id

	d.logger.Printf("Save record for device %s\n", dev.Id)
	err = d.saveDevice(dev)

	err = d.startDeviceInstance(dev)
	if err != nil {
		return dbus.ObjectPath("Error"), &dbus.Error{}
	}

	d.logger.Printf("Created new device %s\n", dev.Id)
	return dev.Path, nil
}

// Read a device definition
func (d *DeviceManager) Read(id string) (dev DeviceDefinition, err *dbus.Error) {

	if d.devices[id] != nil {
		d.logger.Printf("Read %s: \n%v\n", id, dev)
		dev = *d.devices[id]
	} else {
		d.logger.Printf("Device %s: Not Found : \n", id)
		err = new(dbus.Error)
	}

	return dev, err
}

// Update a device definition
func (d *DeviceManager) Update(id string, dev DeviceDefinition) (res bool, err *dbus.Error) {
	res = true
	return res, err
}

// Delete a device definition
func (d *DeviceManager) Delete(id string) (res bool, err *dbus.Error) {
	res = true
	return res, err
}

// Batch exec batch ops
func (d *DeviceManager) Batch(operation string, ops map[string]string) (res bool, err *dbus.Error) {
	res = true
	return res, err
}

// BaseQuery base query for devices record
type BaseQuery struct {
	Criteria map[string]string
	OrderBy  map[string]string
	Limit    int32
	Offset   int32
}

// DeviceComponent A device component
type DeviceComponent struct {
	Id         string
	Unit       string
	Format     string
	Properties map[string]string
}

// DeviceDefinition A device details list
type DeviceDefinition struct {
	Id          string
	Name        string
	Description string
	Path        dbus.ObjectPath
	Protocol    dbus.ObjectPath
	Properties  map[string]string
	Streams     []DeviceComponent
}
<commit_msg>added find method<commit_after>package objects

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/godbus/dbus"
	"github.com/godbus/dbus/prop"

	"github.com/muka/device-manager/api"
	"github.com/muka/device-manager/db"
	"github.com/muka/device-manager/service"
	"github.com/muka/device-manager/util"
)

// DeviceManagerDatabasePath path to the database file
var deviceManagerDatabasePath = "./data/devices.db"

// DeviceManagerTableName Name of the table containing the devices
var deviceManagerTableName = "Devices"

var deviceManagerFields = []db.DatasetField{
	{"Id", "text", "unique", true},
	{Name: "Name", Type: "text"},
	{Name: "Description", Type: "text"},
	{Name: "Path", Type: "text"},
	{Name: "Protocol", Type: "text"},
	{Name: "Properties", Type: "text"},
	{Name: "Streams", Type: "text"},
}

// NewDeviceManager initialize a new DeviceManager object
func NewDeviceManager() *DeviceManager {
	d := DeviceManager{}

	dmlogger, err := util.NewLogger(d.GetInterface())
	util.CheckError(err)

	d.logger = dmlogger

	d.Devices = make([]dbus.ObjectPath, 0)
	d.services = make(map[string]*service.Service)
	d.devices = make(map[string]*DeviceDefinition)
	d.path = DeviceManagerPath
	d.iface = DeviceManagerInterface
	d.dataset = db.NewSqliteDataSet(deviceManagerTableName, deviceManagerFields, deviceManagerDatabasePath)

	d.restoreDevices()

	return &d
}

// DeviceManager manages devices in the gateway
type DeviceManager struct {
	api.Proxy

	Devices  []dbus.ObjectPath
	services map[string]*service.Service
	devices  map[string]*DeviceDefinition

	path    string
	iface   string
	logger  *log.Logger
	dataset db.DataSet
}

// GetPath return object path
func (d *DeviceManager) GetPath() string {
	return d.path
}

// SetPath set object path
func (d *DeviceManager) SetPath(s string) {
	d.path = s
}

// GetInterface return interface
func (d *DeviceManager) GetInterface() string {
	return d.iface
}

// SetInterface return interface
func (d *DeviceManager) SetInterface(s string) {
	d.iface = s
}

//SetLogger set default logger
func (d *DeviceManager) SetLogger(logger *log.Logger) {
	d.logger = logger
}

//GetLogger return default logger
func (d *DeviceManager) GetLogger() *log.Logger {
	return d.logger
}

//GetProperties return properties
func (d *DeviceManager) GetProperties() map[string]map[string]*prop.Prop {
	return map[string]map[string]*prop.Prop{
		d.GetInterface(): {
			"Devices": {
				Value:    d.Devices,
				Writable: false,
				Emit:     prop.EmitTrue,
				Callback: func(c *prop.Change) *dbus.Error {
					d.logger.Printf("Changed value %s=%v on %s", c.Name, c.Value, c.Iface)
					return nil
				},
			},
		},
	}
}

//parseDeviceRow parse a row to DeviceDefinition
func (d *DeviceManager) parseDeviceRow(rows *sql.Rows) (*DeviceDefinition, error) {
	dev := new(DeviceDefinition)
	var strStreams, strProperties, strPath, strProtocol string
	err := rows.Scan(
		&dev.Id,
		&dev.Name,
		&dev.Description,
		&strPath,
		&strProtocol,
		&strProperties,
		&strStreams,
	)
	if err != nil {
		return dev, err
	}

	dev.Protocol = dbus.ObjectPath(strProtocol)
	dev.Path = dbus.ObjectPath(strPath)

	json.Unmarshal([]byte(strProperties), dev.Properties)
	json.Unmarshal([]byte(strProperties), dev.Streams)

	return dev, nil
}

//restoreDevices reinitialize DBus instances of stored devices
func (d *DeviceManager) restoreDevices() {

	d.logger.Println("Restoring previous device instances")

	rows, err := d.dataset.Find(nil)
	util.CheckError(err)

	defer rows.Close()
	for rows.Next() {
		dev, err := d.parseDeviceRow(rows)
		util.CheckError(err)
		d.logger.Printf("Loading device %s (%s)", dev.Name, dev.Id)
		d.startDeviceInstance(*dev)
	}

}

//startDeviceInstance reinitialize DBus instances of stored devices
func (d *DeviceManager) startDeviceInstance(dev DeviceDefinition) error {

	device := NewDevice(dev)

	service, mErr := service.GetManager().Start(device)
	if mErr != nil {
		msg := fmt.Sprintf("Cannot start Device service: %s\n", mErr.Error())
		d.logger.Fatalf(msg)
		return errors.New(msg)
	}

	dev.Path = dbus.ObjectPath(device.GetPath())

	d.Devices = append(d.Devices, dev.Path)
	d.devices[dev.Id] = &dev
	d.services[dev.Id] = service

	return nil
}

func (d *DeviceManager) saveDevice(dev DeviceDefinition) error {

	jsonProperties, err := json.Marshal(dev.Properties)
	if err != nil {
		return err
	}

	jsonStreams, err := json.Marshal(dev.Streams)
	if err != nil {
		return err
	}

	err = d.dataset.Save(
		[]db.FieldValue{
			{Name: "Id", Value: dev.Id},
			{Name: "Name", Value: dev.Name},
			{Name: "Description", Value: dev.Description},
			{Name: "Path", Value: string(dev.Path)},
			{Name: "Protocol", Value: string(dev.Protocol)},
			{Name: "Properties", Value: string(jsonProperties)},
			{Name: "Streams", Value: string(jsonStreams)},
		},
	)

	if err != nil {
		d.logger.Printf("Error on save: %v\n", err)
		return err
	}

	return nil
}

// -----
// Dbus API implementation

// Find search for devices
func (d *DeviceManager) Find(q *BaseQuery) (devices []dbus.ObjectPath, err *dbus.Error) {
	d.logger.Println("DeviceManager.Find() not implemented")

	var query = db.Query{}
	if q.Criteria != nil {
		query.Criteria = make([]db.Criteria, len(q.Criteria))
		var i = 0
		for key, val := range q.Criteria {

			var op = "="
			var value = val

			if strings.Contains(value, "*") {
				op = "LIKE"
				value = strings.Replace(value, "*", "%", 0)
			}

			query.Criteria[i] = db.Criteria{
				Prefix:    "",
				Field:     key,
				Operation: op,
				Value:     value,
				Suffix:    "",
			}

			i++
		}
	}

	query.Limit = db.Limit{}
	if q.Offset > 0 {
		query.Limit.Offset = int(q.Offset)
	}
	if q.Limit > 0 {
		query.Limit.Size = int(q.Limit)
	}

	for k, v := range q.OrderBy {
		s := db.SortDESC
		if v == "ASC" {
			s = db.SortASC
		}
		query.OrderBy = OrderBy{k, s}
		break
	}

	rows, err1 := d.dataset.Find(&query)
	util.CheckError(err1)

	defer rows.Close()
	var i = 0
	devs := make([]dbus.ObjectPath, 0)
	for rows.Next() {
		dev, err := d.parseDeviceRow(rows)
		util.CheckError(err)
		devs = append(devs, dev.Path)
		i++
	}

	return devs, err
}

// Create add a device
func (d *DeviceManager) Create(dev DeviceDefinition) (dbus.ObjectPath, *dbus.Error) {

	var err error

	id := util.GenerateID()
	d.logger.Printf("Create new device %s\n", id)
	d.logger.Printf("Data:\n %v\n", dev)
	dev.Id = id

	d.logger.Printf("Save record for device %s\n", dev.Id)
	err = d.saveDevice(dev)

	err = d.startDeviceInstance(dev)
	if err != nil {
		return dbus.ObjectPath("Error"), &dbus.Error{}
	}

	d.logger.Printf("Created new device %s\n", dev.Id)
	return dev.Path, nil
}

// Read a device definition
func (d *DeviceManager) Read(id string) (dev DeviceDefinition, err *dbus.Error) {

	if d.devices[id] != nil {
		d.logger.Printf("Read %s: \n%v\n", id, dev)
		dev = *d.devices[id]
	} else {
		d.logger.Printf("Device %s: Not Found : \n", id)
		err = new(dbus.Error)
	}

	return dev, err
}

// Update a device definition
func (d *DeviceManager) Update(id string, dev DeviceDefinition) (res bool, err *dbus.Error) {
	res = true
	return res, err
}

// Delete a device definition
func (d *DeviceManager) Delete(id string) (res bool, err *dbus.Error) {
	res = true
	return res, err
}

// Batch exec batch ops
func (d *DeviceManager) Batch(operation string, ops map[string]string) (res bool, err *dbus.Error) {
	res = true
	return res, err
}

// BaseQuery base query for devices record
type BaseQuery struct {
	Criteria map[string]string
	OrderBy  map[string]string
	Limit    int32
	Offset   int32
}

// DeviceComponent A device component
type DeviceComponent struct {
	Id         string
	Unit       string
	Format     string
	Properties map[string]string
}

// DeviceDefinition A device details list
type DeviceDefinition struct {
	Id          string
	Name        string
	Description string
	Path        dbus.ObjectPath
	Protocol    dbus.ObjectPath
	Properties  map[string]string
	Streams     []DeviceComponent
}
<|endoftext|>