<commit_before>package views

import (
	"fmt"
	"html/template"
	"io"
	"time"
)

func datetime(t int64) string {
	return time.Unix(t, 0).Format(time.RFC3339)
}

func readable(t int64) string {
	n := time.Now()
	u := time.Unix(t, 0)
	d := n.Sub(u)

	if d.Hours() < 24 && n.Weekday() == u.Weekday() {
		if d.Hours() < 1 {
			return fmt.Sprintf("%d mintues ago", int(d.Minutes()))
		}
		return fmt.Sprintf("%d hours ago", int(d.Hours()))
	}

	if d.Hours() < 48 && n.Weekday() == u.Weekday()+1 {
		return u.Format("Yesterday at 15:04pm")
	}

	if n.Year() == u.Year() {
		return u.Format("02 Jan 15:04pm")
	}

	return u.Format("02 Jan 2006")
}

type Pair struct {
	Name string
	Hide bool
	Data interface{}
}

func pair(name string, show bool, data interface{}) *Pair {
	return &Pair{name, !show, data}
}

var Played interface {
	Execute(io.Writer, interface{}) error
}

func init() {
	var tmpl = template.Must(template.New("played").Funcs(template.FuncMap{
		"datetime": datetime,
		"readable": readable,
		"pair":     pair,
	}).Parse(played))
	tmpl = template.Must(tmpl.New("artistTab").Parse(artistTab))
	tmpl = template.Must(tmpl.New("trackTab").Parse(trackTab))

	Played = &wrappedTemplate{tmpl, "played"}
}

type wrappedTemplate struct {
	t *template.Template
	n string
}

func (w *wrappedTemplate) Execute(wr io.Writer, data interface{}) error {
	return w.t.ExecuteTemplate(wr, w.n, data)
}

const artistTab = `

    {{ range .Data }}

      {{.Artist}}
      {{.Count}} plays

    {{ end }}

`

const trackTab = `

    {{ range .Data }}

      {{.Artist}}
      {{.Track}}
      {{.Count}} plays

    {{ end }}

`

const played = `<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>{{.Title}}</title>
    <link rel="alternate" type="application/rss+xml" href="/feed" />

{{.Title}}

{{.TotalPlays}} plays

      {{ if .NowPlaying }}

        ♫
        {{.NowPlaying.Artist}}
        {{.NowPlaying.Track}}

      {{ end }}

Recently played

        {{ range .RecentlyPlayed }}

          {{.Artist}}
          {{.Track}}
          <time datetime="{{.Timestamp | datetime}}">{{.Timestamp | readable}}</time>

        {{ end }}

Top Artists

Overall

Year

Month

Week

        {{ template "artistTab" pair "tab-artists-overall" false .TopArtists.Overall }}
        {{ template "artistTab" pair "tab-artists-year"    false .TopArtists.Year    }}
        {{ template "artistTab" pair "tab-artists-month"   true  .TopArtists.Month   }}
        {{ template "artistTab" pair "tab-artists-week"    false .TopArtists.Week    }}

Top Tracks

Overall

Year

Month

Week

        {{ template "trackTab" pair "tab-tracks-overall" false .TopTracks.Overall }}
        {{ template "trackTab" pair "tab-tracks-year"    false .TopTracks.Year    }}
        {{ template "trackTab" pair "tab-tracks-month"   true  .TopTracks.Month   }}
        {{ template "trackTab" pair "tab-tracks-week"    false .TopTracks.Week    }}

`
<commit_msg>Use
 for recently played<commit_after>package views

import (
	"fmt"
	"html/template"
	"io"
	"time"
)

func datetime(t int64) string {
	return time.Unix(t, 0).Format(time.RFC3339)
}

func readable(t int64) string {
	n := time.Now()
	u := time.Unix(t, 0)
	d := n.Sub(u)

	if d.Hours() < 24 && n.Weekday() == u.Weekday() {
		if d.Hours() < 1 {
			return fmt.Sprintf("%d mintues ago", int(d.Minutes()))
		}
		return fmt.Sprintf("%d hours ago", int(d.Hours()))
	}

	if d.Hours() < 48 && n.Weekday() == u.Weekday()+1 {
		return u.Format("Yesterday at 15:04pm")
	}

	if n.Year() == u.Year() {
		return u.Format("02 Jan 15:04pm")
	}

	return u.Format("02 Jan 2006")
}

type Pair struct {
	Name string
	Hide bool
	Data interface{}
}

func pair(name string, show bool, data interface{}) *Pair {
	return &Pair{name, !show, data}
}

var Played interface {
	Execute(io.Writer, interface{}) error
}

func init() {
	var tmpl = template.Must(template.New("played").Funcs(template.FuncMap{
		"datetime": datetime,
		"readable": readable,
		"pair":     pair,
	}).Parse(played))
	tmpl = template.Must(tmpl.New("artistTab").Parse(artistTab))
	tmpl = template.Must(tmpl.New("trackTab").Parse(trackTab))

	Played = &wrappedTemplate{tmpl, "played"}
}

type wrappedTemplate struct {
	t *template.Template
	n string
}

func (w *wrappedTemplate) Execute(wr io.Writer, data interface{}) error {
	return w.t.ExecuteTemplate(wr, w.n, data)
}

const artistTab = `

    {{ range .Data }}

      {{.Artist}}
      {{.Count}} plays

    {{ end }}

`

const trackTab = `

    {{ range .Data }}

      {{.Artist}}
      {{.Track}}
      {{.Count}} plays

    {{ end }}

`

const played = `<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>{{.Title}}</title>
    <link rel="alternate" type="application/rss+xml" href="/feed" />

{{.Title}}

{{.TotalPlays}} plays

      {{ if .NowPlaying }}

        ♫
        {{.NowPlaying.Artist}}
        {{.NowPlaying.Track}}

      {{ end }}

Recently played

        {{ range .RecentlyPlayed }}

            {{.Artist}}
            {{.Track}}

          <time datetime="{{.Timestamp | datetime}}">{{.Timestamp | readable}}</time>

        {{ end }}

Top Artists

Overall

Year

Month

Week

        {{ template "artistTab" pair "tab-artists-overall" false .TopArtists.Overall }}
        {{ template "artistTab" pair "tab-artists-year"    false .TopArtists.Year    }}
        {{ template "artistTab" pair "tab-artists-month"   true  .TopArtists.Month   }}
        {{ template "artistTab" pair "tab-artists-week"    false .TopArtists.Week    }}

Top Tracks

Overall

Year

Month

Week

        {{ template "trackTab" pair "tab-tracks-overall" false .TopTracks.Overall }}
        {{ template "trackTab" pair "tab-tracks-year"    false .TopTracks.Year    }}
        {{ template "trackTab" pair "tab-tracks-month"   true  .TopTracks.Month   }}
        {{ template "trackTab" pair "tab-tracks-week"    false .TopTracks.Week    }}

`
<|endoftext|>


<commit_before>package vxlan

import (
	//"fmt"
	//"strings"
	//"time"
	"net"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/network"
	//"github.com/samalba/dockerclient"
	//"github.com/davecgh/go-spew/spew"
	"github.com/vishvananda/netlink"
)

type Driver struct {
	network.Driver
	networks map[string]*NetworkState
}

// NetworkState is filled in at network creation time
// it contains state that we wish to keep for each network
type NetworkState struct {
	Bridge   *netlink.Bridge
	VXLan    *netlink.Vxlan
	Gateway  string
	IPv4Data []*network.IPAMData
	IPv6Data []*network.IPAMData
}

func NewDriver() (*Driver, error) {
	d := &Driver{
		networks: make(map[string]*NetworkState),
	}
	return d, nil
}

func (d *Driver) CreateNetwork(r *network.CreateNetworkRequest) error {
	log.Debugf("Create network request: %+v", r)

	netID := r.NetworkID
	var err error

	bridgeName := "br_" + netID[:12]
	vxlanName := "vx_" + netID[:12]

	// get interface names from options first
	for k, v := range r.Options {
		if k == "com.docker.network.generic" {
			if genericOpts, ok := v.(map[string]interface{}); ok {
				for key, val := range genericOpts {
					if key == "vxlanName" {
						vxlanName = val.(string)
					}
					if key == "bridgeName" {
						bridgeName = val.(string)
					}
				}
			}
		}
	}

	// create links
	bridge := &netlink.Bridge{
		LinkAttrs: netlink.LinkAttrs{
			Name: bridgeName,
		},
	}
	vxlan := &netlink.Vxlan{
		LinkAttrs: netlink.LinkAttrs{
			Name: vxlanName,
		},
	}

	// Parse interface options
	for k, v := range r.Options {
		if k == "com.docker.network.generic" {
			if genericOpts, ok := v.(map[string]interface{}); ok {
				for key, val := range genericOpts {
					log.Debugf("Libnetwork Opts Sent: [ %s ] Value: [ %s ]", key, val)
					if key == "vxlanMTU" {
						vxlan.LinkAttrs.MTU, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "bridgeMTU" {
						bridge.LinkAttrs.MTU, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "vxlanHardwareAddr" {
						vxlan.LinkAttrs.HardwareAddr, err = net.ParseMAC(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "bridgeHardwareAddr" {
						bridge.LinkAttrs.HardwareAddr, err = net.ParseMAC(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "vxlanTxQLen" {
						vxlan.LinkAttrs.TxQLen, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "bridgeTxQLen" {
						bridge.LinkAttrs.TxQLen, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "VxlanId" {
						vxlan.VxlanId, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "VtepDev" {
						vtepDev, err := netlink.LinkByName(val.(string))
						if err != nil {
							return err
						}
						vxlan.VtepDevIndex = vtepDev.Attrs().Index
					}
					if key == "SrcAddr" {
						vxlan.SrcAddr = net.ParseIP(val.(string))
					}
					if key == "Group" {
						vxlan.Group = net.ParseIP(val.(string))
					}
					if key == "TTL" {
						vxlan.TTL, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "TOS" {
						vxlan.TOS, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Learning" {
						vxlan.Learning, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Proxy" {
						vxlan.Proxy, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "RSC" {
						vxlan.RSC, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "L2miss" {
						vxlan.L2miss, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "L3miss" {
						vxlan.L3miss, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "NoAge" {
						vxlan.NoAge, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "GBP" {
						vxlan.GBP, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Age" {
						vxlan.Age, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Limit" {
						vxlan.Limit, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Port" {
						vxlan.Port, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "PortLow" {
						vxlan.PortLow, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "PortHigh" {
						vxlan.PortHigh, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
				}
			}
		}
	}
	// Done parsing options

	// delete links if they already exist, don't worry about errors
	netlink.LinkDel(bridge)
	netlink.LinkDel(vxlan)

	// add links
	err = netlink.LinkAdd(bridge)
	if err != nil {
		return err
	}
	err = netlink.LinkAdd(vxlan)
	if err != nil {
		return err
	}

	// add vxlan to bridge
	err = netlink.LinkSetMaster(vxlan, bridge)
	if err != nil {
		return err
	}

	// bring interfaces up
	err = netlink.LinkSetUp(bridge)
	if err != nil {
		return err
	}
	err = netlink.LinkSetUp(vxlan)
	if err != nil {
		return err
	}

	// store interfaces to be used later
	ns := &NetworkState{
		VXLan:    vxlan,
		Bridge:   bridge,
		IPv4Data: r.IPv4Data,
		IPv6Data: r.IPv6Data,
	}

	// Add IPs to interfaces
	// Process IPv6 first. If both are inclued, IPv4 gateway will be the one that
	// remains, because JoinResponse can only include one Gateway
	for i := range r.IPv6Data {
		gatewayIP, err := netlink.ParseAddr(r.IPv6Data[i].Gateway)
		if err != nil {
			return err
		}
		ns.Gateway = r.IPv6Data[i].Gateway
		netlink.AddrAdd(bridge, gatewayIP)
	}
	for i := range r.IPv4Data {
		gatewayIP, err := netlink.ParseAddr(r.IPv4Data[i].Gateway)
		if err != nil {
			return err
		}
		ns.Gateway = r.IPv4Data[i].Gateway
		netlink.AddrAdd(bridge, gatewayIP)
	}

	d.networks[netID] = ns

	return nil
}

func (d *Driver) DeleteNetwork(r *network.DeleteNetworkRequest) error {
	netID := r.NetworkID

	err := netlink.LinkDel(d.networks[netID].VXLan)
	if err != nil {
		return err
	}
	err = netlink.LinkDel(d.networks[netID].Bridge)
	if err != nil {
		return err
	}

	return nil
}

func (d *Driver) CreateEndpoint(r *network.CreateEndpointRequest) error {
	log.Debugf("Create endpoint request: %+v", r)
	return nil
}

func (d *Driver) DeleteEndpoint(r *network.DeleteEndpointRequest) error {
	log.Debugf("Delete endpoint request: %+v", r)
	return nil
}

func (d *Driver) EndpointInfo(r *network.InfoRequest) (*network.InfoResponse, error) {
	res := &network.InfoResponse{
		Value: make(map[string]string),
	}
	return res, nil
}

func (d *Driver) Join(r *network.JoinRequest) (*network.JoinResponse, error) {
	// create and attach local name to the bridge
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "veth_" + r.EndpointID[:5]},
		PeerName:  "ethc" + r.EndpointID[:5],
	}
	if err := netlink.LinkAdd(veth); err != nil {
		log.Errorf("failed to create the veth pair named: [ %v ] error: [ %s ] ", veth, err)
		return nil, err
	}

	// bring up the veth pair
	err := netlink.LinkSetUp(veth)
	if err != nil {
		log.Warnf("Error enabling  Veth local iface: [ %v ]", veth)
		return nil, err
	}

	bridge := d.networks[r.NetworkID].Bridge
	// add veth to bridge
	err = netlink.LinkSetMaster(veth, bridge)
	if err != nil {
		return nil, err
	}

	// SrcName gets renamed to DstPrefix + ID on the container iface
	res := &network.JoinResponse{
		InterfaceName: network.InterfaceName{
			SrcName:   veth.PeerName,
			DstPrefix: "eth",
		},
		Gateway: d.networks[r.NetworkID].Gateway,
	}
	log.Debugf("Join endpoint %s:%s to %s", r.NetworkID, r.EndpointID, r.SandboxKey)
	return res, nil
}
<commit_msg>leaving works<commit_after>package vxlan

import (
	//"fmt"
	//"strings"
	//"time"
	"net"
	"strconv"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/network"
	//"github.com/samalba/dockerclient"
	//"github.com/davecgh/go-spew/spew"
	"github.com/vishvananda/netlink"
)

type Driver struct {
	network.Driver
	networks map[string]*NetworkState
}

// NetworkState is filled in at network creation time
// it contains state that we wish to keep for each network
type NetworkState struct {
	Bridge   *netlink.Bridge
	VXLan    *netlink.Vxlan
	Gateway  string
	IPv4Data []*network.IPAMData
	IPv6Data []*network.IPAMData
}

func NewDriver() (*Driver, error) {
	d := &Driver{
		networks: make(map[string]*NetworkState),
	}
	return d, nil
}

func (d *Driver) CreateNetwork(r *network.CreateNetworkRequest) error {
	log.Debugf("Create network request: %+v", r)

	netID := r.NetworkID
	var err error

	bridgeName := "br_" + netID[:12]
	vxlanName := "vx_" + netID[:12]

	// get interface names from options first
	for k, v := range r.Options {
		if k == "com.docker.network.generic" {
			if genericOpts, ok := v.(map[string]interface{}); ok {
				for key, val := range genericOpts {
					if key == "vxlanName" {
						vxlanName = val.(string)
					}
					if key == "bridgeName" {
						bridgeName = val.(string)
					}
				}
			}
		}
	}

	// create links
	bridge := &netlink.Bridge{
		LinkAttrs: netlink.LinkAttrs{
			Name: bridgeName,
		},
	}
	vxlan := &netlink.Vxlan{
		LinkAttrs: netlink.LinkAttrs{
			Name: vxlanName,
		},
	}

	// Parse interface options
	for k, v := range r.Options {
		if k == "com.docker.network.generic" {
			if genericOpts, ok := v.(map[string]interface{}); ok {
				for key, val := range genericOpts {
					log.Debugf("Libnetwork Opts Sent: [ %s ] Value: [ %s ]", key, val)
					if key == "vxlanMTU" {
						vxlan.LinkAttrs.MTU, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "bridgeMTU" {
						bridge.LinkAttrs.MTU, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "vxlanHardwareAddr" {
						vxlan.LinkAttrs.HardwareAddr, err = net.ParseMAC(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "bridgeHardwareAddr" {
						bridge.LinkAttrs.HardwareAddr, err = net.ParseMAC(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "vxlanTxQLen" {
						vxlan.LinkAttrs.TxQLen, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "bridgeTxQLen" {
						bridge.LinkAttrs.TxQLen, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "VxlanId" {
						vxlan.VxlanId, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "VtepDev" {
						vtepDev, err := netlink.LinkByName(val.(string))
						if err != nil {
							return err
						}
						vxlan.VtepDevIndex = vtepDev.Attrs().Index
					}
					if key == "SrcAddr" {
						vxlan.SrcAddr = net.ParseIP(val.(string))
					}
					if key == "Group" {
						vxlan.Group = net.ParseIP(val.(string))
					}
					if key == "TTL" {
						vxlan.TTL, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "TOS" {
						vxlan.TOS, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Learning" {
						vxlan.Learning, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Proxy" {
						vxlan.Proxy, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "RSC" {
						vxlan.RSC, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "L2miss" {
						vxlan.L2miss, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "L3miss" {
						vxlan.L3miss, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "NoAge" {
						vxlan.NoAge, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "GBP" {
						vxlan.GBP, err = strconv.ParseBool(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Age" {
						vxlan.Age, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Limit" {
						vxlan.Limit, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "Port" {
						vxlan.Port, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "PortLow" {
						vxlan.PortLow, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
					if key == "PortHigh" {
						vxlan.PortHigh, err = strconv.Atoi(val.(string))
						if err != nil {
							return err
						}
					}
				}
			}
		}
	}
	// Done parsing options

	// delete links if they already exist, don't worry about errors
	netlink.LinkDel(bridge)
	netlink.LinkDel(vxlan)

	// add links
	err = netlink.LinkAdd(bridge)
	if err != nil {
		return err
	}
	err = netlink.LinkAdd(vxlan)
	if err != nil {
		return err
	}

	// add vxlan to bridge
	err = netlink.LinkSetMaster(vxlan, bridge)
	if err != nil {
		return err
	}

	// bring interfaces up
	err = netlink.LinkSetUp(bridge)
	if err != nil {
		return err
	}
	err = netlink.LinkSetUp(vxlan)
	if err != nil {
		return err
	}

	// store interfaces to be used later
	ns := &NetworkState{
		VXLan:    vxlan,
		Bridge:   bridge,
		IPv4Data: r.IPv4Data,
		IPv6Data: r.IPv6Data,
	}

	// Add IPs to interfaces
	// Process IPv6 first. If both are inclued, IPv4 gateway will be the one that
	// remains, because JoinResponse can only include one Gateway
	for i := range r.IPv6Data {
		gatewayIP, err := netlink.ParseAddr(r.IPv6Data[i].Gateway)
		if err != nil {
			return err
		}
		ns.Gateway = gatewayIP.IP.String()
		netlink.AddrAdd(bridge, gatewayIP)
	}
	for i := range r.IPv4Data {
		gatewayIP, err := netlink.ParseAddr(r.IPv4Data[i].Gateway)
		if err != nil {
			return err
		}
		ns.Gateway = gatewayIP.IP.String()
		netlink.AddrAdd(bridge, gatewayIP)
	}

	d.networks[netID] = ns

	return nil
}

func (d *Driver) DeleteNetwork(r *network.DeleteNetworkRequest) error {
	netID := r.NetworkID

	err := netlink.LinkDel(d.networks[netID].VXLan)
	if err != nil {
		return err
	}
	err = netlink.LinkDel(d.networks[netID].Bridge)
	if err != nil {
		return err
	}

	return nil
}

func (d *Driver) CreateEndpoint(r *network.CreateEndpointRequest) error {
	log.Debugf("Create endpoint request: %+v", r)
	return nil
}

func (d *Driver) DeleteEndpoint(r *network.DeleteEndpointRequest) error {
	log.Debugf("Delete endpoint request: %+v", r)
	return nil
}

func (d *Driver) EndpointInfo(r *network.InfoRequest) (*network.InfoResponse, error) {
	res := &network.InfoResponse{
		Value: make(map[string]string),
	}
	return res, nil
}

func (d *Driver) Join(r *network.JoinRequest) (*network.JoinResponse, error) {
	// create and attach local name to the bridge
	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "veth_" + r.EndpointID[:5]},
		PeerName:  "ethc" + r.EndpointID[:5],
	}
	if err := netlink.LinkAdd(veth); err != nil {
		log.Errorf("failed to create the veth pair named: [ %v ] error: [ %s ] ", veth, err)
		return nil, err
	}

	// bring up the veth pair
	err := netlink.LinkSetUp(veth)
	if err != nil {
		log.Warnf("Error enabling  Veth local iface: [ %v ]", veth)
		return nil, err
	}

	bridge := d.networks[r.NetworkID].Bridge
	// add veth to bridge
	err = netlink.LinkSetMaster(veth, bridge)
	if err != nil {
		return nil, err
	}

	// SrcName gets renamed to DstPrefix + ID on the container iface
	res := &network.JoinResponse{
		InterfaceName: network.InterfaceName{
			SrcName:   veth.PeerName,
			DstPrefix: "eth",
		},
		Gateway: d.networks[r.NetworkID].Gateway,
	}
	log.Debugf("Join endpoint %s:%s to %s", r.NetworkID, r.EndpointID, r.SandboxKey)
	return res, nil
}

func (d *Driver) Leave(r *network.LeaveRequest) error {
	log.Debugf("Leave request: %+v", r)

	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: "veth_" + r.EndpointID[:5]},
		PeerName:  "ethc" + r.EndpointID[:5],
	}

	// bring down the veth pair
	err := netlink.LinkSetDown(veth)
	if err != nil {
		log.Warnf("Error enabling  Veth local iface: [ %v ]", veth)
		return err
	}

	// remove veth from bridge
	err = netlink.LinkSetNoMaster(veth)
	if err != nil {
		return err
	}

	// delete the veth interface
	err = netlink.LinkDel(veth)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package crdt

type Counter struct {
	Process string

	IncAtoms map[string]int64
	DecAtoms map[string]int64
}

// retrieves the current value of the distributed counter
func (c *Counter) Value() int64 {
	x := int64(0)
	for _, value := range c.IncAtoms {
		x = x + value
	}
	for _, value := range c.DecAtoms {
		x = x - value
	}
	return x
}

// called when we want to merge our counter with the state of the same
// counter from another node.
func (c *Counter) Merge(other *Counter) {
	for key, value := range other.IncAtoms {
		ourValue := c.IncAtoms[key]
		if value > ourValue {
			c.IncAtoms[key] = value
		}
	}

	for key, value := range other.DecAtoms {
		ourValue := c.DecAtoms[key]
		if value > ourValue {
			c.DecAtoms[key] = value
		}
	}
}

func (c *Counter) Increment() {
	c.IncAtoms[c.Process] += 1
}

func (c *Counter) Decrement() {
	c.DecAtoms[c.Process] += 1
}

// creates a new counter, each node that has a replica of the counter
// state must have a unique identity
func NewCounter(Process string) *Counter {
	return &Counter{Process, make(map[string]int64), make(map[string]int64)}
}
<commit_msg>ensure access to counter values is synchronised<commit_after>package crdt

import (
	"sync"
)

type Counter struct {
	Process string

	IncAtoms map[string]int64
	DecAtoms map[string]int64

	lock *sync.RWMutex
}

// retrieves the current value of the distributed counter
func (c *Counter) Value() int64 {
	c.lock.RLock()
	defer c.lock.RUnlock()

	x := int64(0)
	for _, value := range c.IncAtoms {
		x = x + value
	}
	for _, value := range c.DecAtoms {
		x = x - value
	}
	return x
}

// called when we want to merge our counter with the state of the same
// counter from another node.
func (c *Counter) Merge(other *Counter) {
	c.lock.Lock()
	defer c.lock.Unlock()

	for key, value := range other.IncAtoms {
		ourValue := c.IncAtoms[key]
		if value > ourValue {
			c.IncAtoms[key] = value
		}
	}

	for key, value := range other.DecAtoms {
		ourValue := c.DecAtoms[key]
		if value > ourValue {
			c.DecAtoms[key] = value
		}
	}
}

func (c *Counter) Increment() {
	c.lock.Lock()
	defer c.lock.Unlock()

	c.IncAtoms[c.Process] += 1
}

func (c *Counter) Decrement() {
	c.lock.Lock()
	defer c.lock.Unlock()

	c.DecAtoms[c.Process] += 1
}

// creates a new counter, each node that has a replica of the counter
// state must have a unique identity
func NewCounter(process string) *Counter {
	return &Counter{
		Process:  process,
		IncAtoms: make(map[string]int64),
		DecAtoms: make(map[string]int64),
		lock:     &sync.RWMutex{},
	}
}
<|endoftext|>


<commit_before>// defines timestamp types to interface with go-coubhbase and also provides
// functions for set-operations on time-stamps.

package common

import "github.com/couchbase/indexing/secondary/logging"
import "bytes"
import "fmt"
import "sync"

// TsVb is logical clock for a subset of vbuckets.
type TsVb struct {
	Bucket string
	Vbnos  []uint16
	Seqnos []uint64
}

// TsVbFull is logical clock for full set of vbuckets.
type TsVbFull struct {
	Bucket string
	Seqnos []uint64
}

// TsVbuuid is logical clock for full set of vbuckets along with branch value
// and last seen snapshot.
type TsVbuuid struct {
	Bucket    string
	Seqnos    []uint64
	Vbuuids   []uint64
	Snapshots [][2]uint64
	Persisted bool
	LargeSnap bool
}

// NewTsVbuuid returns reference to new instance of TsVbuuid.
// `numVbuckets` is same as `maxVbuckets`.
func NewTsVbuuid(bucket string, numVbuckets int) *TsVbuuid {
	return &TsVbuuid{
		Bucket:    bucket,
		Seqnos:    make([]uint64, numVbuckets),
		Vbuuids:   make([]uint64, numVbuckets),
		Snapshots: make([][2]uint64, numVbuckets),
	}
}

func newTsVbuuid() interface{} {
	return &TsVbuuid{
		Bucket:    "",
		Seqnos:    make([]uint64, NUM_VBUCKETS),
		Vbuuids:   make([]uint64, NUM_VBUCKETS),
		Snapshots: make([][2]uint64, NUM_VBUCKETS),
	}
}

var tsVbuuidPool = sync.Pool{New: newTsVbuuid}
var NUM_VBUCKETS int

func NewTsVbuuidCached(bucket string, numVbuckets int) *TsVbuuid {

	NUM_VBUCKETS = numVbuckets

	ts := tsVbuuidPool.Get().(*TsVbuuid)

	//re-init
	for i, _ := range ts.Vbuuids {
		ts.Seqnos[i] = 0
		ts.Vbuuids[i] = 0
		ts.Snapshots[i][0] = 0
		ts.Snapshots[i][1] = 0
	}
	ts.Bucket = bucket
	return ts
}

func (ts *TsVbuuid) Free() {
	tsVbuuidPool.Put(ts)
}

// GetVbnos will return the list of all vbnos.
func (ts *TsVbuuid) GetVbnos() []uint16 {
	var vbnos []uint16
	for i := 0; i < len(ts.Vbuuids); i++ {
		if ts.Vbuuids[i] != 0 { //if vbuuid is valid
			vbnos = append(vbnos, uint16(i))
		}
	}
	return vbnos
}

// CompareVbuuids will compare two timestamps for its bucket and vbuuids
func (ts *TsVbuuid) CompareVbuuids(other *TsVbuuid) bool {
	if ts == nil || other == nil {
		return false
	}
	if ts.Bucket != other.Bucket || ts.Len() != other.Len() {
		return false
	}
	for i, vbuuid := range ts.Vbuuids {
		if (vbuuid != other.Vbuuids[i]) ||
			(ts.Snapshots[i][0] != other.Snapshots[i][0]) ||
			(ts.Snapshots[i][1] != other.Snapshots[i][1]) {
			return false
		}
	}
	return true
}

// AsRecent will check whether timestamp `ts` is atleast as recent as
// timestamp `other`.
func (ts *TsVbuuid) AsRecent(other *TsVbuuid) bool {
	if ts == nil || other == nil {
		return false
	}
	if ts.Bucket != other.Bucket {
		return false
	}
	for i, vbuuid := range ts.Vbuuids {
		//skip comparing the vbucket if "other" ts has vbuuid 0
		if other.Vbuuids[i] == 0 {
			continue
		}

		if vbuuid != other.Vbuuids[i] || ts.Seqnos[i] < other.Seqnos[i] {
			return false
		}
	}
	return true
}

// Len return number of entries in the timestamp.
func (ts *TsVbuuid) Len() int {
	length := 0
	for i := 0; i < len(ts.Vbuuids); i++ {
		if ts.Vbuuids[i] != 0 { //if vbuuid is valid
			length++
		}
	}
	return length
}

//Persisted returns the value of persisted flag
func (ts *TsVbuuid) IsPersisted() bool {
	return ts.Persisted
}

//Persisted sets the persisted flag
func (ts *TsVbuuid) SetPersisted(persist bool) {
	ts.Persisted = persist
}

//HasLargeSnapshot returns the value of largeSnap flag
func (ts *TsVbuuid) HasLargeSnapshot() bool {
	return ts.LargeSnap
}

//SetLargeSnapshot sets the largeSnap flag
func (ts *TsVbuuid) SetLargeSnapshot(largeSnap bool) {
	ts.LargeSnap = largeSnap
}

// Copy will return a clone of this timestamp.
func (ts *TsVbuuid) Copy() *TsVbuuid {
	newTs := NewTsVbuuid(ts.Bucket, len(ts.Seqnos))
	copy(newTs.Seqnos, ts.Seqnos)
	copy(newTs.Vbuuids, ts.Vbuuids)
	copy(newTs.Snapshots, ts.Snapshots)
	newTs.Persisted = ts.Persisted
	newTs.LargeSnap = ts.LargeSnap
	return newTs
}

func (ts *TsVbuuid) CopyFrom(src *TsVbuuid) {
	copy(ts.Seqnos, src.Seqnos)
	copy(ts.Vbuuids, src.Vbuuids)
	copy(ts.Snapshots, src.Snapshots)
	ts.Persisted = src.Persisted
}

// Equal returns whether `ts` and `other` compare equal.
func (ts *TsVbuuid) Equal(other *TsVbuuid) bool {
	if ts != nil && other == nil ||
		ts == nil && other != nil {
		return false
	}

	if ts == nil && other == nil {
		return true
	}

	if len(ts.Seqnos) != len(other.Seqnos) {
		return false
	}

	for i, seqno := range ts.Seqnos {
		if other.Seqnos[i] != seqno {
			return false
		}
	}

	for i, vbuuid := range ts.Vbuuids {
		if other.Vbuuids[i] != vbuuid {
			return false
		}
	}

	for i, sn := range ts.Snapshots {
		if other.Snapshots[i][0] != sn[0] {
			return false
		}

		if other.Snapshots[i][1] != sn[1] {
			return false
		}
	}

	return true
}

// Clone of TsVbuuid
func (ts *TsVbuuid) Clone() *TsVbuuid {

	other := NewTsVbuuid(ts.Bucket, len(ts.Seqnos))
	for i, seqno := range ts.Seqnos {
		other.Seqnos[i] = seqno
	}

	for i, vbuuid := range ts.Vbuuids {
		other.Vbuuids[i] = vbuuid
	}

	for i, sn := range ts.Snapshots {
		other.Snapshots[i][0] = sn[0]
		other.Snapshots[i][1] = sn[1]
	}

	return other
}

// Convert into a human readable format
func (ts *TsVbuuid) String() string {
	var buf bytes.Buffer
	vbnos := ts.GetVbnos()
	fmsg := "bucket: %v, vbuckets: %v -\n"
	buf.WriteString(fmt.Sprintf(fmsg, ts.Bucket, len(vbnos)))
	fmsg = "    {vbno, vbuuid, seqno, snapshot-start, snapshot-end}\n"
	buf.WriteString(fmt.Sprintf(fmsg))
	for _, v := range vbnos {
		start, end := ts.Snapshots[v][0], ts.Snapshots[v][1]
		buf.WriteString(fmt.Sprintf("    {%5d %16x %10d %10d %10d}\n",
			v, ts.Vbuuids[v], ts.Seqnos[v], start, end))
	}
	return buf.String()
}

// Convert the difference between two timestamps to human readable format
func (ts *TsVbuuid) Diff(other *TsVbuuid) string {

	var buf bytes.Buffer
	if ts.Equal(other) {
		buf.WriteString("Timestamps are equal\n")
		return buf.String()
	}

	if other == nil {
		buf.WriteString("This timestamp:\n")
		buf.WriteString(ts.String())
		buf.WriteString("Other timestamp is nil\n")
		return buf.String()
	}

	if len(other.Seqnos) != len(ts.Seqnos) {
		logging.Debugf("Two timestamps contain different number of vbuckets\n")
		buf.WriteString("This timestamp:\n")
		buf.WriteString(ts.String())
		buf.WriteString("Other timestamp:\n")
		buf.WriteString(other.String())
		return buf.String()
	}

	for i := range ts.Seqnos {
		if ts.Seqnos[i] != other.Seqnos[i] || ts.Vbuuids[i] != other.Vbuuids[i] ||
			ts.Snapshots[i][0] != other.Snapshots[i][0] || ts.Snapshots[i][1] != other.Snapshots[i][1] {
			buf.WriteString(fmt.Sprintf("This timestamp: bucket %s, vb = %d, vbuuid = %d, seqno = %d, snapshot[0] = %d, snapshot[1] = %d\n",
				ts.Bucket, i, ts.Vbuuids[i], ts.Seqnos[i], ts.Snapshots[0], ts.Snapshots[1]))
			buf.WriteString(fmt.Sprintf("Other timestamp: bucket %s, vb = %d, vbuuid = %d, seqno = %d, snapshot[0] = %d, snapshot[1] = %d\n",
				other.Bucket, i, other.Vbuuids[i], other.Seqnos[i], other.Snapshots[0], other.Snapshots[1]))
		}
	}

	return buf.String()
}

//check if seqnum of all vbuckets are aligned with the snapshot end
func (ts *TsVbuuid) IsSnapAligned() bool {

	if ts == nil {
		return false
	}

	for i, s := range ts.Snapshots {
		if ts.Seqnos[i] != s[1] {
			return false
		}
	}
	return true

}
<commit_msg>MB-13590 Indexer - Sync pool for Timestamp<commit_after>// defines timestamp types to interface with go-coubhbase and also provides
// functions for set-operations on time-stamps.

package common

import "github.com/couchbase/indexing/secondary/logging"
import "bytes"
import "fmt"
import "sync"

// TsVb is logical clock for a subset of vbuckets.
type TsVb struct {
	Bucket string
	Vbnos  []uint16
	Seqnos []uint64
}

// TsVbFull is logical clock for full set of vbuckets.
type TsVbFull struct {
	Bucket string
	Seqnos []uint64
}

// TsVbuuid is logical clock for full set of vbuckets along with branch value
// and last seen snapshot.
type TsVbuuid struct {
	Bucket    string
	Seqnos    []uint64
	Vbuuids   []uint64
	Snapshots [][2]uint64
	Persisted bool
	LargeSnap bool
}

// NewTsVbuuid returns reference to new instance of TsVbuuid.
// `numVbuckets` is same as `maxVbuckets`.
func NewTsVbuuid(bucket string, numVbuckets int) *TsVbuuid {
	return &TsVbuuid{
		Bucket:    bucket,
		Seqnos:    make([]uint64, numVbuckets),
		Vbuuids:   make([]uint64, numVbuckets),
		Snapshots: make([][2]uint64, numVbuckets),
	}
}

func newTsVbuuid() interface{} {
	return &TsVbuuid{
		Bucket:    "",
		Seqnos:    make([]uint64, NUM_VBUCKETS),
		Vbuuids:   make([]uint64, NUM_VBUCKETS),
		Snapshots: make([][2]uint64, NUM_VBUCKETS),
	}
}

var tsVbuuidPool = sync.Pool{New: newTsVbuuid}
var NUM_VBUCKETS int

func NewTsVbuuidCached(bucket string, numVbuckets int) *TsVbuuid {

	NUM_VBUCKETS = numVbuckets

	ts := tsVbuuidPool.Get().(*TsVbuuid)

	//re-init
	for i, _ := range ts.Vbuuids {
		ts.Seqnos[i] = 0
		ts.Vbuuids[i] = 0
		ts.Snapshots[i][0] = 0
		ts.Snapshots[i][1] = 0
	}
	ts.Bucket = bucket
	return ts
}

func (ts *TsVbuuid) Free() {
	tsVbuuidPool.Put(ts)
}

// GetVbnos will return the list of all vbnos.
func (ts *TsVbuuid) GetVbnos() []uint16 {
	var vbnos []uint16
	for i := 0; i < len(ts.Vbuuids); i++ {
		if ts.Vbuuids[i] != 0 { //if vbuuid is valid
			vbnos = append(vbnos, uint16(i))
		}
	}
	return vbnos
}

// CompareVbuuids will compare two timestamps for its bucket and vbuuids
func (ts *TsVbuuid) CompareVbuuids(other *TsVbuuid) bool {
	if ts == nil || other == nil {
		return false
	}
	if ts.Bucket != other.Bucket || ts.Len() != other.Len() {
		return false
	}
	for i, vbuuid := range ts.Vbuuids {
		if (vbuuid != other.Vbuuids[i]) ||
			(ts.Snapshots[i][0] != other.Snapshots[i][0]) ||
			(ts.Snapshots[i][1] != other.Snapshots[i][1]) {
			return false
		}
	}
	return true
}

// AsRecent will check whether timestamp `ts` is atleast as recent as
// timestamp `other`.
func (ts *TsVbuuid) AsRecent(other *TsVbuuid) bool {
	if ts == nil || other == nil {
		return false
	}
	if ts.Bucket != other.Bucket {
		return false
	}
	for i, vbuuid := range ts.Vbuuids {
		//skip comparing the vbucket if "other" ts has vbuuid 0
		if other.Vbuuids[i] == 0 {
			continue
		}

		if vbuuid != other.Vbuuids[i] || ts.Seqnos[i] < other.Seqnos[i] {
			return false
		}
	}
	return true
}

// Len return number of entries in the timestamp.
func (ts *TsVbuuid) Len() int {
	length := 0
	for i := 0; i < len(ts.Vbuuids); i++ {
		if ts.Vbuuids[i] != 0 { //if vbuuid is valid
			length++
		}
	}
	return length
}

//Persisted returns the value of persisted flag
func (ts *TsVbuuid) IsPersisted() bool {
	return ts.Persisted
}

//Persisted sets the persisted flag
func (ts *TsVbuuid) SetPersisted(persist bool) {
	ts.Persisted = persist
}

//HasLargeSnapshot returns the value of largeSnap flag
func (ts *TsVbuuid) HasLargeSnapshot() bool {
	return ts.LargeSnap
}

//SetLargeSnapshot sets the largeSnap flag
func (ts *TsVbuuid) SetLargeSnapshot(largeSnap bool) {
	ts.LargeSnap = largeSnap
}

// Copy will return a clone of this timestamp.
func (ts *TsVbuuid) Copy() *TsVbuuid {
	newTs := NewTsVbuuid(ts.Bucket, len(ts.Seqnos))
	copy(newTs.Seqnos, ts.Seqnos)
	copy(newTs.Vbuuids, ts.Vbuuids)
	copy(newTs.Snapshots, ts.Snapshots)
	newTs.Persisted = ts.Persisted
	newTs.LargeSnap = ts.LargeSnap
	return newTs
}

func (ts *TsVbuuid) CopyFrom(src *TsVbuuid) {
	copy(ts.Seqnos, src.Seqnos)
	copy(ts.Vbuuids, src.Vbuuids)
	copy(ts.Snapshots, src.Snapshots)
	ts.Persisted = src.Persisted
	ts.LargeSnap = src.LargeSnap
}

// Equal returns whether `ts` and `other` compare equal.
func (ts *TsVbuuid) Equal(other *TsVbuuid) bool {
	if ts != nil && other == nil ||
		ts == nil && other != nil {
		return false
	}

	if ts == nil && other == nil {
		return true
	}

	if len(ts.Seqnos) != len(other.Seqnos) {
		return false
	}

	for i, seqno := range ts.Seqnos {
		if other.Seqnos[i] != seqno {
			return false
		}
	}

	for i, vbuuid := range ts.Vbuuids {
		if other.Vbuuids[i] != vbuuid {
			return false
		}
	}

	for i, sn := range ts.Snapshots {
		if other.Snapshots[i][0] != sn[0] {
			return false
		}

		if other.Snapshots[i][1] != sn[1] {
			return false
		}
	}

	return true
}

// Clone of TsVbuuid
func (ts *TsVbuuid) Clone() *TsVbuuid {

	other := NewTsVbuuid(ts.Bucket, len(ts.Seqnos))
	for i, seqno := range ts.Seqnos {
		other.Seqnos[i] = seqno
	}

	for i, vbuuid := range ts.Vbuuids {
		other.Vbuuids[i] = vbuuid
	}

	for i, sn := range ts.Snapshots {
		other.Snapshots[i][0] = sn[0]
		other.Snapshots[i][1] = sn[1]
	}

	return other
}

// Convert into a human readable format
func (ts *TsVbuuid) String() string {
	var buf bytes.Buffer
	vbnos := ts.GetVbnos()
	fmsg := "bucket: %v, vbuckets: %v -\n"
	buf.WriteString(fmt.Sprintf(fmsg, ts.Bucket, len(vbnos)))
	fmsg = "    {vbno, vbuuid, seqno, snapshot-start, snapshot-end}\n"
	buf.WriteString(fmt.Sprintf(fmsg))
	for _, v := range vbnos {
		start, end := ts.Snapshots[v][0], ts.Snapshots[v][1]
		buf.WriteString(fmt.Sprintf("    {%5d %16x %10d %10d %10d}\n",
			v, ts.Vbuuids[v], ts.Seqnos[v], start, end))
	}
	return buf.String()
}

// Convert the difference between two timestamps to human readable format
func (ts *TsVbuuid) Diff(other *TsVbuuid) string {

	var buf bytes.Buffer
	if ts.Equal(other) {
		buf.WriteString("Timestamps are equal\n")
		return buf.String()
	}

	if other == nil {
		buf.WriteString("This timestamp:\n")
		buf.WriteString(ts.String())
		buf.WriteString("Other timestamp is nil\n")
		return buf.String()
	}

	if len(other.Seqnos) != len(ts.Seqnos) {
		logging.Debugf("Two timestamps contain different number of vbuckets\n")
		buf.WriteString("This timestamp:\n")
		buf.WriteString(ts.String())
		buf.WriteString("Other timestamp:\n")
		buf.WriteString(other.String())
		return buf.String()
	}

	for i := range ts.Seqnos {
		if ts.Seqnos[i] != other.Seqnos[i] || ts.Vbuuids[i] != other.Vbuuids[i] ||
			ts.Snapshots[i][0] != other.Snapshots[i][0] || ts.Snapshots[i][1] != other.Snapshots[i][1] {
			buf.WriteString(fmt.Sprintf("This timestamp: bucket %s, vb = %d, vbuuid = %d, seqno = %d, snapshot[0] = %d, snapshot[1] = %d\n",
				ts.Bucket, i, ts.Vbuuids[i], ts.Seqnos[i], ts.Snapshots[0], ts.Snapshots[1]))
			buf.WriteString(fmt.Sprintf("Other timestamp: bucket %s, vb = %d, vbuuid = %d, seqno = %d, snapshot[0] = %d, snapshot[1] = %d\n",
				other.Bucket, i, other.Vbuuids[i], other.Seqnos[i], other.Snapshots[0], other.Snapshots[1]))
		}
	}

	return buf.String()
}

//check if seqnum of all vbuckets are aligned with the snapshot end
func (ts *TsVbuuid) IsSnapAligned() bool {

	if ts == nil {
		return false
	}

	for i, s := range ts.Snapshots {
		if ts.Seqnos[i] != s[1] {
			return false
		}
	}
	return true

}
<|endoftext|>


<commit_before>package web

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/gorilla/mux"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/dao"

	"mime"
	"net/http"
	"net/http/httputil"
	"net/url"
)

type ServiceConfig struct {
	bindPort    string
	agentPort   string
	zookeepers  []string
	stats       bool
	hostaliases []string
}

func NewServiceConfig(bindPort string, agentPort string, zookeepers []string, stats bool, hostaliases string) *ServiceConfig {
	cfg := ServiceConfig{bindPort, agentPort, zookeepers, stats, []string{}}
	if hostaliases != "" {
		cfg.hostaliases = strings.Split(hostaliases, ":")
	}
	if len(cfg.agentPort) == 0 {
		cfg.agentPort = "127.0.0.1:4979"
	}
	if len(cfg.zookeepers) == 0 {
		cfg.zookeepers = []string{"127.0.0.1:2181"}
	}
	return &cfg
}

// Serve handles control plane web UI requests and virtual host requests for zenoss web based services.
// The UI server actually listens on port 7878, the uihandler defined here just reverse proxies to it.
// Virutal host routing to zenoss web based services is done by the vhosthandler function.
func (sc *ServiceConfig) Serve() {
	client, err := sc.getClient()
	if err != nil {
		glog.Errorf("Unable to get control plane client: %v", err)
		return
	}

	// Reverse proxy to the web UI server.
	uihandler := func(w http.ResponseWriter, r *http.Request) {
		uiUrl, err := url.Parse("http://127.0.0.1:7878")
		if err != nil {
			glog.Errorf("Can't parse UI URL: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui := httputil.NewSingleHostReverseProxy(uiUrl)
		if ui == nil {
			glog.Errorf("Can't proxy UI request: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui.ServeHTTP(w, r)
	}

	// Lookup the appropriate virtual host and forward the request to it.
	// TODO: when zookeeper registration is integrated we can be more event
	// driven and only refresh the vhost map when service states change.
	vhosthandler := func(w http.ResponseWriter, r *http.Request) {
		var empty interface{}
		services := []*dao.RunningService{}
		client.GetRunningServices(&empty, &services)

		vhosts := make(map[string][]*dao.ServiceState, 0)

		for _, s := range services {
			var svc dao.Service

			if err := client.GetService(s.ServiceId, &svc); err != nil {
				glog.Errorf("Can't get service: %s (%v)", s.Id, err)
			}

			vheps := svc.GetServiceVHosts()

			for _, vhep := range vheps {
				for _, vh := range vhep.VHosts {
					svcstates := []*dao.ServiceState{}
					if err := client.GetServiceStates(s.ServiceId, &svcstates); err != nil {
						http.Error(w, fmt.Sprintf("can't retrieve service states for %s (%v)", s.ServiceId, err), http.StatusInternalServerError)
						return
					}

					for _, ss := range svcstates {
						vhosts[vh] = append(vhosts[vh], ss)
					}
				}
			}

		}

		muxvars := mux.Vars(r)
		svcstates, ok := vhosts[muxvars["subdomain"]]
		if !ok {
			http.Error(w, fmt.Sprintf("unknown vhost: %v", muxvars["subdomain"]), http.StatusNotFound)
			return
		}

		// TODO: implement a more intelligent strategy than "always pick the first one" when more
		// than one service state is mapped to a given virtual host
		for _, svcep := range svcstates[0].Endpoints {
			for _, vh := range svcep.VHosts {
				if vh == muxvars["subdomain"] {
					rp := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", svcstates[0].PrivateIp, svcep.PortNumber)})
					rp.ServeHTTP(w, r)
					return
				}
			}
		}

		http.Error(w, fmt.Sprintf("unrecognized endpoint: %s", muxvars["subdomain"]), http.StatusNotImplemented)
	}

	r := mux.NewRouter()

	if hnm, err := os.Hostname(); err == nil {
		sc.hostaliases = append(sc.hostaliases, hnm)
	}

	cmd := exec.Command("hostname", "--fqdn")
	if hnm, err := cmd.CombinedOutput(); err == nil {
		sc.hostaliases = append(sc.hostaliases, string(hnm[:len(hnm)-1]))
	}

	for _, ha := range sc.hostaliases {
		r.HandleFunc("/", vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
		r.HandleFunc("/{path:.*}", vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
	}

	r.HandleFunc("/{path:.*}", uihandler)

	http.Handle("/", r)

	certfile, err := serviced.TempCertFile()
	if err != nil {
		glog.Error("Could not prepare cert.pem file.")
	}
	keyfile, err := serviced.TempKeyFile()
	if err != nil {
		glog.Error("Could not prepare key.pem file.")
	}
	http.ListenAndServeTLS(sc.bindPort, certfile, keyfile, nil)
}

func (this *ServiceConfig) ServeUI() {
	mime.AddExtensionType(".json", "application/json")
	mime.AddExtensionType(".woff", "application/font-woff")

	handler := rest.ResourceHandler{
		EnableRelaxedContentType: true,
	}
	routes := []rest.Route{
		rest.Route{"GET", "/", MainPage},
		rest.Route{"GET", "/test", TestPage},
		rest.Route{"GET", "/stats", this.IsCollectingStats()},
		// Hosts
		rest.Route{"GET", "/hosts", this.AuthorizedClient(RestGetHosts)},
		rest.Route{"POST", "/hosts/add", this.AuthorizedClient(RestAddHost)},
		rest.Route{"DELETE", "/hosts/:hostId", this.AuthorizedClient(RestRemoveHost)},
		rest.Route{"PUT", "/hosts/:hostId", this.AuthorizedClient(RestUpdateHost)},
		rest.Route{"GET", "/hosts/:hostId/running", this.AuthorizedClient(RestGetRunningForHost)},
		rest.Route{"DELETE", "/hosts/:hostId/:serviceStateId", this.AuthorizedClient(RestKillRunning)},
		// Pools
		rest.Route{"POST", "/pools/add", this.AuthorizedClient(RestAddPool)},
		rest.Route{"GET", "/pools/:poolId/hosts", this.AuthorizedClient(RestGetHostsForResourcePool)},
		rest.Route{"DELETE", "/pools/:poolId", this.AuthorizedClient(RestRemovePool)},
		rest.Route{"PUT", "/pools/:poolId", this.AuthorizedClient(RestUpdatePool)},
		rest.Route{"GET", "/pools", this.AuthorizedClient(RestGetPools)},
		// Services (Apps)
		rest.Route{"GET", "/services", this.AuthorizedClient(RestGetAllServices)},
		rest.Route{"GET", "/services/:serviceId", this.AuthorizedClient(RestGetService)},
		rest.Route{"GET", "/services/:serviceId/running", this.AuthorizedClient(RestGetRunningForService)},
		rest.Route{"GET", "/services/:serviceId/running/:serviceStateId", this.AuthorizedClient(RestGetRunningService)},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs", this.AuthorizedClient(RestGetServiceStateLogs)},
		rest.Route{"POST", "/services/add", this.AuthorizedClient(RestAddService)},
		rest.Route{"DELETE", "/services/:serviceId", this.AuthorizedClient(RestRemoveService)},
		rest.Route{"GET", "/services/:serviceId/logs", this.AuthorizedClient(RestGetServiceLogs)},
		rest.Route{"PUT", "/services/:serviceId", this.AuthorizedClient(RestUpdateService)},
		rest.Route{"GET", "/services/:serviceId/snapshot", this.AuthorizedClient(RestSnapshotService)},
		rest.Route{"PUT", "/services/:serviceId/startService", this.AuthorizedClient(RestStartService)},
		rest.Route{"PUT", "/services/:serviceId/stopService", this.AuthorizedClient(RestStopService)},

		// Services (Virtual Host)
		rest.Route{"GET", "/vhosts", this.AuthorizedClient(RestGetVirtualHosts)},
		rest.Route{"POST", "/vhosts/:serviceId/:application/:vhostName", this.AuthorizedClient(RestAddVirtualHost)},
		rest.Route{"DELETE", "/vhosts/:serviceId/:application/:vhostName", this.AuthorizedClient(RestRemoveVirtualHost)},

		// Service templates (App templates)
		rest.Route{"GET", "/templates", this.AuthorizedClient(RestGetAppTemplates)},
		rest.Route{"POST", "/templates/deploy", this.AuthorizedClient(RestDeployAppTemplate)},

		// Login
		rest.Route{"POST", "/login", this.UnAuthorizedClient(RestLogin)},
		rest.Route{"DELETE", "/login", RestLogout},
		// "Misc" stuff
		rest.Route{"GET", "/top/services", this.AuthorizedClient(RestGetTopServices)},
		rest.Route{"GET", "/running", this.AuthorizedClient(RestGetAllRunning)},
		// Generic static data
		rest.Route{"GET", "/favicon.ico", FavIcon},
		rest.Route{"GET", "/static*resource", StaticData},
	}

	// Hardcoding these target URLs for now.
	// TODO: When internal services are allowed to run on other hosts, look that up.
	routes = routeToInternalServiceProxy("/elastic", "http://127.0.0.1:9200/", routes)
	routes = routeToInternalServiceProxy("/api/controlplane/elastic", "http://127.0.0.1:443/", routes)
	routes = routeToInternalServiceProxy("/metrics", "http://127.0.0.1:8888/", routes)

	handler.SetRoutes(routes...)

	http.ListenAndServe(":7878", &handler)
}

var methods []string = []string{"GET", "POST", "PUT", "DELETE"}

func routeToInternalServiceProxy(path string, target string, routes []rest.Route) []rest.Route {
	targetUrl, err := url.Parse(target)
	if err != nil {
		glog.Errorf("Unable to parse proxy target URL: %s", target)
		return routes
	}
	// Wrap the normal http.Handler in a rest.HandlerFunc
	handlerFunc := func(w *rest.ResponseWriter, r *rest.Request) {
		proxy := serviced.NewReverseProxy(path, targetUrl)
		proxy.ServeHTTP(w.ResponseWriter, r.Request)
	}
	// Add on a glob to match subpaths
	andsubpath := path + "*x"
	for _, method := range methods {
		routes = append(routes, rest.Route{method, path, handlerFunc})
		routes = append(routes, rest.Route{method, andsubpath, handlerFunc})
	}
	return routes
}

func (this *ServiceConfig) UnAuthorizedClient(realfunc HandlerClientFunc) HandlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		client, err := this.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			RestServerError(w)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (this *ServiceConfig) AuthorizedClient(realfunc HandlerClientFunc) HandlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !LoginOk(r) {
			RestUnauthorized(w)
			return
		}
		client, err := this.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			RestServerError(w)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (this *ServiceConfig) IsCollectingStats() HandlerFunc {
	if this.stats {
		return func(w *rest.ResponseWriter, r *rest.Request) {
			w.WriteHeader(http.StatusOK)
		}
	} else {
		return func(w *rest.ResponseWriter, r *rest.Request) {
			w.WriteHeader(http.StatusNotImplemented)
		}
	}
}

func (this *ServiceConfig) getClient() (c *serviced.ControlClient, err error) {
	// setup the client
	c, err = serviced.NewControlClient(this.agentPort)
	if err != nil {
		glog.Fatalf("Could not create a control plane client: %v", err)
	}
	return c, err
}
<commit_msg>fix instead of break it<commit_after>package web

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/gorilla/mux"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
	"github.com/zenoss/serviced"
	"github.com/zenoss/serviced/dao"

	"mime"
	"net/http"
	"net/http/httputil"
	"net/url"
)

type ServiceConfig struct {
	bindPort    string
	agentPort   string
	zookeepers  []string
	stats       bool
	hostaliases []string
}

func NewServiceConfig(bindPort string, agentPort string, zookeepers []string, stats bool, hostaliases string) *ServiceConfig {
	cfg := ServiceConfig{bindPort, agentPort, zookeepers, stats, []string{}}
	if hostaliases != "" {
		cfg.hostaliases = strings.Split(hostaliases, ":")
	}
	if len(cfg.agentPort) == 0 {
		cfg.agentPort = "127.0.0.1:4979"
	}
	if len(cfg.zookeepers) == 0 {
		cfg.zookeepers = []string{"127.0.0.1:2181"}
	}
	return &cfg
}

// Serve handles control plane web UI requests and virtual host requests for zenoss web based services.
// The UI server actually listens on port 7878, the uihandler defined here just reverse proxies to it.
// Virutal host routing to zenoss web based services is done by the vhosthandler function.
func (sc *ServiceConfig) Serve() {
	client, err := sc.getClient()
	if err != nil {
		glog.Errorf("Unable to get control plane client: %v", err)
		return
	}

	// Reverse proxy to the web UI server.
	uihandler := func(w http.ResponseWriter, r *http.Request) {
		uiUrl, err := url.Parse("http://127.0.0.1:7878")
		if err != nil {
			glog.Errorf("Can't parse UI URL: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui := httputil.NewSingleHostReverseProxy(uiUrl)
		if ui == nil {
			glog.Errorf("Can't proxy UI request: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui.ServeHTTP(w, r)
	}

	// Lookup the appropriate virtual host and forward the request to it.
	// TODO: when zookeeper registration is integrated we can be more event
	// driven and only refresh the vhost map when service states change.
	vhosthandler := func(w http.ResponseWriter, r *http.Request) {
		var empty interface{}
		services := []*dao.RunningService{}
		client.GetRunningServices(&empty, &services)

		vhosts := make(map[string][]*dao.ServiceState, 0)

		for _, s := range services {
			var svc dao.Service

			if err := client.GetService(s.ServiceId, &svc); err != nil {
				glog.Errorf("Can't get service: %s (%v)", s.Id, err)
			}

			vheps := svc.GetServiceVHosts()

			for _, vhep := range vheps {
				for _, vh := range vhep.VHosts {
					svcstates := []*dao.ServiceState{}
					if err := client.GetServiceStates(s.ServiceId, &svcstates); err != nil {
						http.Error(w, fmt.Sprintf("can't retrieve service states for %s (%v)", s.ServiceId, err), http.StatusInternalServerError)
						return
					}

					for _, ss := range svcstates {
						vhosts[vh] = append(vhosts[vh], ss)
					}
				}
			}

		}

		muxvars := mux.Vars(r)
		svcstates, ok := vhosts[muxvars["subdomain"]]
		if !ok {
			http.Error(w, fmt.Sprintf("unknown vhost: %v", muxvars["subdomain"]), http.StatusNotFound)
			return
		}

		// TODO: implement a more intelligent strategy than "always pick the first one" when more
		// than one service state is mapped to a given virtual host
		for _, svcep := range svcstates[0].Endpoints {
			for _, vh := range svcep.VHosts {
				if vh == muxvars["subdomain"] {
					rp := httputil.NewSingleHostReverseProxy(&url.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", svcstates[0].PrivateIp, svcep.PortNumber)})
					rp.ServeHTTP(w, r)
					return
				}
			}
		}

		http.Error(w, fmt.Sprintf("unrecognized endpoint: %s", muxvars["subdomain"]), http.StatusNotImplemented)
	}

	r := mux.NewRouter()

	if hnm, err := os.Hostname(); err == nil {
		sc.hostaliases = append(sc.hostaliases, hnm)
	}

	cmd := exec.Command("hostname", "--fqdn")
	if hnm, err := cmd.CombinedOutput(); err == nil {
		sc.hostaliases = append(sc.hostaliases, string(hnm[:len(hnm)-1]))
	}

	for _, ha := range sc.hostaliases {
		r.HandleFunc("/", vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
		r.HandleFunc("/{path:.*}", vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
	}

	r.HandleFunc("/{path:.*}", uihandler)

	http.Handle("/", r)

	certfile, err := serviced.TempCertFile()
	if err != nil {
		glog.Error("Could not prepare cert.pem file.")
	}
	keyfile, err := serviced.TempKeyFile()
	if err != nil {
		glog.Error("Could not prepare key.pem file.")
	}
	http.ListenAndServeTLS(sc.bindPort, certfile, keyfile, nil)
}

func (this *ServiceConfig) ServeUI() {
	mime.AddExtensionType(".json", "application/json")
	mime.AddExtensionType(".woff", "application/font-woff")

	handler := rest.ResourceHandler{
		EnableRelaxedContentType: true,
	}
	routes := []rest.Route{
		rest.Route{"GET", "/", MainPage},
		rest.Route{"GET", "/test", TestPage},
		rest.Route{"GET", "/stats", this.IsCollectingStats()},
		// Hosts
		rest.Route{"GET", "/hosts", this.AuthorizedClient(RestGetHosts)},
		rest.Route{"POST", "/hosts/add", this.AuthorizedClient(RestAddHost)},
		rest.Route{"DELETE", "/hosts/:hostId", this.AuthorizedClient(RestRemoveHost)},
		rest.Route{"PUT", "/hosts/:hostId", this.AuthorizedClient(RestUpdateHost)},
		rest.Route{"GET", "/hosts/:hostId/running", this.AuthorizedClient(RestGetRunningForHost)},
		rest.Route{"DELETE", "/hosts/:hostId/:serviceStateId", this.AuthorizedClient(RestKillRunning)},
		// Pools
		rest.Route{"POST", "/pools/add", this.AuthorizedClient(RestAddPool)},
		rest.Route{"GET", "/pools/:poolId/hosts", this.AuthorizedClient(RestGetHostsForResourcePool)},
		rest.Route{"DELETE", "/pools/:poolId", this.AuthorizedClient(RestRemovePool)},
		rest.Route{"PUT", "/pools/:poolId", this.AuthorizedClient(RestUpdatePool)},
		rest.Route{"GET", "/pools", this.AuthorizedClient(RestGetPools)},
		// Services (Apps)
		rest.Route{"GET", "/services", this.AuthorizedClient(RestGetAllServices)},
		rest.Route{"GET", "/services/:serviceId", this.AuthorizedClient(RestGetService)},
		rest.Route{"GET", "/services/:serviceId/running", this.AuthorizedClient(RestGetRunningForService)},
		rest.Route{"GET", "/services/:serviceId/running/:serviceStateId", this.AuthorizedClient(RestGetRunningService)},
		rest.Route{"GET", "/services/:serviceId/:serviceStateId/logs", this.AuthorizedClient(RestGetServiceStateLogs)},
		rest.Route{"POST", "/services/add", this.AuthorizedClient(RestAddService)},
		rest.Route{"DELETE", "/services/:serviceId", this.AuthorizedClient(RestRemoveService)},
		rest.Route{"GET", "/services/:serviceId/logs", this.AuthorizedClient(RestGetServiceLogs)},
		rest.Route{"PUT", "/services/:serviceId", this.AuthorizedClient(RestUpdateService)},
		rest.Route{"GET", "/services/:serviceId/snapshot", this.AuthorizedClient(RestSnapshotService)},
		rest.Route{"PUT", "/services/:serviceId/startService", this.AuthorizedClient(RestStartService)},
		rest.Route{"PUT", "/services/:serviceId/stopService", this.AuthorizedClient(RestStopService)},

		// Services (Virtual Host)
		rest.Route{"GET", "/vhosts", this.AuthorizedClient(RestGetVirtualHosts)},
		rest.Route{"POST", "/vhosts/:serviceId/:application/:vhostName", this.AuthorizedClient(RestAddVirtualHost)},
		rest.Route{"DELETE", "/vhosts/:serviceId/:application/:vhostName", this.AuthorizedClient(RestRemoveVirtualHost)},

		// Service templates (App templates)
		rest.Route{"GET", "/templates", this.AuthorizedClient(RestGetAppTemplates)},
		rest.Route{"POST", "/templates/deploy", this.AuthorizedClient(RestDeployAppTemplate)},

		// Login
		rest.Route{"POST", "/login", this.UnAuthorizedClient(RestLogin)},
		rest.Route{"DELETE", "/login", RestLogout},
		// "Misc" stuff
		rest.Route{"GET", "/top/services", this.AuthorizedClient(RestGetTopServices)},
		rest.Route{"GET", "/running", this.AuthorizedClient(RestGetAllRunning)},
		// Generic static data
		rest.Route{"GET", "/favicon.ico", FavIcon},
		rest.Route{"GET", "/static*resource", StaticData},
	}

	// Hardcoding these target URLs for now.
	// TODO: When internal services are allowed to run on other hosts, look that up.
	routes = routeToInternalServiceProxy("/elastic", "http://127.0.0.1:9200/", routes)
	routes = routeToInternalServiceProxy("/api/controlplane/elastic", "http://127.0.0.1:9200/", routes)
	routes = routeToInternalServiceProxy("/metrics", "http://127.0.0.1:8888/", routes)

	handler.SetRoutes(routes...)

	http.ListenAndServe(":7878", &handler)
}

var methods []string = []string{"GET", "POST", "PUT", "DELETE"}

func routeToInternalServiceProxy(path string, target string, routes []rest.Route) []rest.Route {
	targetUrl, err := url.Parse(target)
	if err != nil {
		glog.Errorf("Unable to parse proxy target URL: %s", target)
		return routes
	}
	// Wrap the normal http.Handler in a rest.HandlerFunc
	handlerFunc := func(w *rest.ResponseWriter, r *rest.Request) {
		proxy := serviced.NewReverseProxy(path, targetUrl)
		proxy.ServeHTTP(w.ResponseWriter, r.Request)
	}
	// Add on a glob to match subpaths
	andsubpath := path + "*x"
	for _, method := range methods {
		routes = append(routes, rest.Route{method, path, handlerFunc})
		routes = append(routes, rest.Route{method, andsubpath, handlerFunc})
	}
	return routes
}

func (this *ServiceConfig) UnAuthorizedClient(realfunc HandlerClientFunc) HandlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		client, err := this.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			RestServerError(w)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (this *ServiceConfig) AuthorizedClient(realfunc HandlerClientFunc) HandlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !LoginOk(r) {
			RestUnauthorized(w)
			return
		}
		client, err := this.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			RestServerError(w)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (this *ServiceConfig) IsCollectingStats() HandlerFunc {
	if this.stats {
		return func(w *rest.ResponseWriter, r *rest.Request) {
			w.WriteHeader(http.StatusOK)
		}
	} else {
		return func(w *rest.ResponseWriter, r *rest.Request) {
			w.WriteHeader(http.StatusNotImplemented)
		}
	}
}

func (this *ServiceConfig) getClient() (c *serviced.ControlClient, err error) {
	// setup the client
	c, err = serviced.NewControlClient(this.agentPort)
	if err != nil {
		glog.Fatalf("Could not create a control plane client: %v", err)
	}
	return c, err
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcwire

// These constants are deprecated as they do not follow the standard Go style
// guidelines and are only provided for backwards compatibility.  Use the
// InvType* constants instead.
const (
	InvVect_Error InvType = InvTypeError
	InvVect_Tx    InvType = InvTypeTx
	InvVect_Block InvType = InvTypeBlock
)
<commit_msg>Add deprecated comments to legacy InvVect_* consts.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package btcwire

// These constants are deprecated as they do not follow the standard Go style
// guidelines and are only provided for backwards compatibility.  Use the
// InvType* constants instead.
const (
	InvVect_Error InvType = InvTypeError // DEPRECATED
	InvVect_Tx    InvType = InvTypeTx    // DEPRECATED
	InvVect_Block InvType = InvTypeBlock // DEPRECATED
)
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 web

import (
	"fmt"
	"mime"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/exec"

	"github.com/control-center/serviced/node"
	"github.com/control-center/serviced/proxy"
	"github.com/control-center/serviced/rpc/master"
	"github.com/gorilla/mux"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
)

// ServiceConfig is the ui/rest handler for control center
type ServiceConfig struct {
	bindPort    string
	agentPort   string
	stats       bool
	hostaliases []string
	muxTLS      bool
	muxPort     int
}

var defaultHostAlias string

// NewServiceConfig creates a new ServiceConfig
func NewServiceConfig(bindPort string, agentPort string, stats bool, hostaliases []string, muxTLS bool, muxPort int) *ServiceConfig {
	cfg := ServiceConfig{
		bindPort:    bindPort,
		agentPort:   agentPort,
		stats:       stats,
		hostaliases: []string{},
		muxTLS:      muxTLS,
		muxPort:     muxPort,
	}
	if len(cfg.agentPort) == 0 {
		cfg.agentPort = "127.0.0.1:4979"
	}
	return &cfg
}

// Serve handles control center web UI requests and virtual host requests for zenoss web based services.
// The UI server actually listens on port 7878, the uihandler defined here just reverse proxies to it.
// Virtual host routing to zenoss web based services is done by the vhosthandler function.
func (sc *ServiceConfig) Serve(shutdown <-chan (interface{})) {

	//start getting vhost endpoints
	go sc.syncVhosts(shutdown)

	// Reverse proxy to the web UI server.
	uihandler := func(w http.ResponseWriter, r *http.Request) {
		uiURL, err := url.Parse("http://127.0.0.1:7878")
		if err != nil {
			glog.Errorf("Can't parse UI URL: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui := httputil.NewSingleHostReverseProxy(uiURL)
		if ui == nil {
			glog.Errorf("Can't proxy UI request: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui.ServeHTTP(w, r)
	}

	r := mux.NewRouter()

	if hnm, err := os.Hostname(); err == nil {
		sc.hostaliases = append(sc.hostaliases, hnm)
	}

	cmd := exec.Command("hostname", "--fqdn")
	if hnm, err := cmd.CombinedOutput(); err == nil {
		sc.hostaliases = append(sc.hostaliases, string(hnm[:len(hnm)-1]))
	}

	defaultHostAlias = sc.hostaliases[0]

	for _, ha := range sc.hostaliases {
		glog.V(1).Infof("Use vhosthandler for: %s", fmt.Sprintf("{subdomain}.%s", ha))
		r.HandleFunc("/{path:.*}", sc.vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
		r.HandleFunc("/", sc.vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
	}

	r.HandleFunc("/{path:.*}", uihandler)

	http.Handle("/", r)

	// FIXME: bubble up these errors to the caller
	certfile, err := proxy.TempCertFile()
	if err != nil {
		glog.Fatalf("Could not prepare cert.pem file: %s", err)
	}
	keyfile, err := proxy.TempKeyFile()
	if err != nil {
		glog.Fatalf("Could not prepare key.pem file: %s", err)
	}
	err = http.ListenAndServeTLS(sc.bindPort, certfile, keyfile, nil)
	if err != nil {
		glog.Fatalf("could not setup webserver: %s", err)
	}
}

// ServeUI is a blocking call that runs the UI hander on port :7878
func (sc *ServiceConfig) ServeUI() {
	mime.AddExtensionType(".json", "application/json")
	mime.AddExtensionType(".woff", "application/font-woff")

	handler := rest.ResourceHandler{
		EnableRelaxedContentType: true,
	}

	routes := sc.getRoutes()
	handler.SetRoutes(routes...)

	// FIXME: bubble up these errors to the caller
	if err := http.ListenAndServe(":7878", &handler); err != nil {
		glog.Fatalf("could not setup internal web server: %s", err)
	}
}

var methods = []string{"GET", "POST", "PUT", "DELETE"}

func routeToInternalServiceProxy(path string, target string, routes []rest.Route) []rest.Route {
	targetURL, err := url.Parse(target)
	if err != nil {
		glog.Errorf("Unable to parse proxy target URL: %s", target)
		return routes
	}
	// Wrap the normal http.Handler in a rest.handlerFunc
	handlerFunc := func(w *rest.ResponseWriter, r *rest.Request) {
		proxy := node.NewReverseProxy(path, targetURL)
		proxy.ServeHTTP(w.ResponseWriter, r.Request)
	}
	// Add on a glob to match subpaths
	andsubpath := path + "*x"
	for _, method := range methods {
		routes = append(routes, rest.Route{method, path, handlerFunc})
		routes = append(routes, rest.Route{method, andsubpath, handlerFunc})
	}
	return routes
}

func (sc *ServiceConfig) unAuthorizedClient(realfunc handlerClientFunc) handlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		client, err := sc.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			restServerError(w, err)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (sc *ServiceConfig) authorizedClient(realfunc handlerClientFunc) handlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !loginOK(r) {
			restUnauthorized(w)
			return
		}
		client, err := sc.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			restServerError(w, err)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (sc *ServiceConfig) isCollectingStats() handlerFunc {
	if sc.stats {
		return func(w *rest.ResponseWriter, r *rest.Request) {
			w.WriteHeader(http.StatusOK)
		}
	}
	return func(w *rest.ResponseWriter, r *rest.Request) {
		w.WriteHeader(http.StatusNotImplemented)
	}
}

func (sc *ServiceConfig) getClient() (c *node.ControlClient, err error) {
	// setup the client
	c, err = node.NewControlClient(sc.agentPort)
	if err != nil {
		glog.Fatalf("Could not create a control center client: %v", err)
	}
	return c, err
}

func (sc *ServiceConfig) getMasterClient() (*master.Client, error) {
	glog.Info("start getMasterClient ... sc.agentPort: %+v", sc.agentPort)
	c, err := master.NewClient(sc.agentPort)
	if err != nil {
		glog.Errorf("Could not create a control center client to %v: %v", sc.agentPort, err)
		return nil, err
	}
	glog.Info("end getMasterClient")
	return c, nil
}

func (sc *ServiceConfig) newRequestHandler(check checkFunc, realfunc ctxhandlerFunc) handlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !check(w, r) {
			return
		}
		reqCtx := newRequestContext(sc)
		defer reqCtx.end()
		realfunc(w, r, reqCtx)
	}
}

func (sc *ServiceConfig) checkAuth(realfunc ctxhandlerFunc) handlerFunc {
	check := func(w *rest.ResponseWriter, r *rest.Request) bool {
		if !loginOK(r) {
			restUnauthorized(w)
			return false
		}
		return true
	}
	return sc.newRequestHandler(check, realfunc)
}

func (sc *ServiceConfig) noAuth(realfunc ctxhandlerFunc) handlerFunc {
	check := func(w *rest.ResponseWriter, r *rest.Request) bool {
		return true
	}
	return sc.newRequestHandler(check, realfunc)
}

type requestContext struct {
	sc     *ServiceConfig
	master *master.Client
}

func newRequestContext(sc *ServiceConfig) *requestContext {
	return &requestContext{sc: sc}
}

func (ctx *requestContext) getMasterClient() (*master.Client, error) {
	if ctx.master == nil {
		c, err := ctx.sc.getMasterClient()
		if err != nil {
			glog.Errorf("Could not create a control center client: %v", err)
			return nil, err
		}
		ctx.master = c
	}
	return ctx.master, nil
}

func (ctx *requestContext) end() error {
	if ctx.master != nil {
		return ctx.master.Close()
	}
	return nil
}

type ctxhandlerFunc func(w *rest.ResponseWriter, r *rest.Request, ctx *requestContext)
type checkFunc func(w *rest.ResponseWriter, r *rest.Request) bool

type getRoutes func(sc *ServiceConfig) []rest.Route
<commit_msg>* fixes CC-157, pass domain aliases to webhandler<commit_after>// Copyright 2014 The Serviced 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 web

import (
	"fmt"
	"mime"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
	"os/exec"

	"github.com/control-center/serviced/node"
	"github.com/control-center/serviced/proxy"
	"github.com/control-center/serviced/rpc/master"
	"github.com/gorilla/mux"
	"github.com/zenoss/glog"
	"github.com/zenoss/go-json-rest"
)

// ServiceConfig is the ui/rest handler for control center
type ServiceConfig struct {
	bindPort    string
	agentPort   string
	stats       bool
	hostaliases []string
	muxTLS      bool
	muxPort     int
}

var defaultHostAlias string

// NewServiceConfig creates a new ServiceConfig
func NewServiceConfig(bindPort string, agentPort string, stats bool, hostaliases []string, muxTLS bool, muxPort int) *ServiceConfig {
	cfg := ServiceConfig{
		bindPort:    bindPort,
		agentPort:   agentPort,
		stats:       stats,
		hostaliases: hostaliases,
		muxTLS:      muxTLS,
		muxPort:     muxPort,
	}
	if len(cfg.agentPort) == 0 {
		cfg.agentPort = "127.0.0.1:4979"
	}
	return &cfg
}

// Serve handles control center web UI requests and virtual host requests for zenoss web based services.
// The UI server actually listens on port 7878, the uihandler defined here just reverse proxies to it.
// Virtual host routing to zenoss web based services is done by the vhosthandler function.
func (sc *ServiceConfig) Serve(shutdown <-chan (interface{})) {

	//start getting vhost endpoints
	go sc.syncVhosts(shutdown)

	// Reverse proxy to the web UI server.
	uihandler := func(w http.ResponseWriter, r *http.Request) {
		uiURL, err := url.Parse("http://127.0.0.1:7878")
		if err != nil {
			glog.Errorf("Can't parse UI URL: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui := httputil.NewSingleHostReverseProxy(uiURL)
		if ui == nil {
			glog.Errorf("Can't proxy UI request: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		ui.ServeHTTP(w, r)
	}

	r := mux.NewRouter()

	if hnm, err := os.Hostname(); err == nil {
		sc.hostaliases = append(sc.hostaliases, hnm)
	}

	cmd := exec.Command("hostname", "--fqdn")
	if hnm, err := cmd.CombinedOutput(); err == nil {
		sc.hostaliases = append(sc.hostaliases, string(hnm[:len(hnm)-1]))
	}

	defaultHostAlias = sc.hostaliases[0]

	for _, ha := range sc.hostaliases {
		glog.V(1).Infof("Use vhosthandler for: %s", fmt.Sprintf("{subdomain}.%s", ha))
		r.HandleFunc("/{path:.*}", sc.vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
		r.HandleFunc("/", sc.vhosthandler).Host(fmt.Sprintf("{subdomain}.%s", ha))
	}

	r.HandleFunc("/{path:.*}", uihandler)

	http.Handle("/", r)

	// FIXME: bubble up these errors to the caller
	certfile, err := proxy.TempCertFile()
	if err != nil {
		glog.Fatalf("Could not prepare cert.pem file: %s", err)
	}
	keyfile, err := proxy.TempKeyFile()
	if err != nil {
		glog.Fatalf("Could not prepare key.pem file: %s", err)
	}
	err = http.ListenAndServeTLS(sc.bindPort, certfile, keyfile, nil)
	if err != nil {
		glog.Fatalf("could not setup webserver: %s", err)
	}
}

// ServeUI is a blocking call that runs the UI hander on port :7878
func (sc *ServiceConfig) ServeUI() {
	mime.AddExtensionType(".json", "application/json")
	mime.AddExtensionType(".woff", "application/font-woff")

	handler := rest.ResourceHandler{
		EnableRelaxedContentType: true,
	}

	routes := sc.getRoutes()
	handler.SetRoutes(routes...)

	// FIXME: bubble up these errors to the caller
	if err := http.ListenAndServe(":7878", &handler); err != nil {
		glog.Fatalf("could not setup internal web server: %s", err)
	}
}

var methods = []string{"GET", "POST", "PUT", "DELETE"}

func routeToInternalServiceProxy(path string, target string, routes []rest.Route) []rest.Route {
	targetURL, err := url.Parse(target)
	if err != nil {
		glog.Errorf("Unable to parse proxy target URL: %s", target)
		return routes
	}
	// Wrap the normal http.Handler in a rest.handlerFunc
	handlerFunc := func(w *rest.ResponseWriter, r *rest.Request) {
		proxy := node.NewReverseProxy(path, targetURL)
		proxy.ServeHTTP(w.ResponseWriter, r.Request)
	}
	// Add on a glob to match subpaths
	andsubpath := path + "*x"
	for _, method := range methods {
		routes = append(routes, rest.Route{method, path, handlerFunc})
		routes = append(routes, rest.Route{method, andsubpath, handlerFunc})
	}
	return routes
}

func (sc *ServiceConfig) unAuthorizedClient(realfunc handlerClientFunc) handlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		client, err := sc.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			restServerError(w, err)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (sc *ServiceConfig) authorizedClient(realfunc handlerClientFunc) handlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !loginOK(r) {
			restUnauthorized(w)
			return
		}
		client, err := sc.getClient()
		if err != nil {
			glog.Errorf("Unable to acquire client: %v", err)
			restServerError(w, err)
			return
		}
		defer client.Close()
		realfunc(w, r, client)
	}
}

func (sc *ServiceConfig) isCollectingStats() handlerFunc {
	if sc.stats {
		return func(w *rest.ResponseWriter, r *rest.Request) {
			w.WriteHeader(http.StatusOK)
		}
	}
	return func(w *rest.ResponseWriter, r *rest.Request) {
		w.WriteHeader(http.StatusNotImplemented)
	}
}

func (sc *ServiceConfig) getClient() (c *node.ControlClient, err error) {
	// setup the client
	c, err = node.NewControlClient(sc.agentPort)
	if err != nil {
		glog.Fatalf("Could not create a control center client: %v", err)
	}
	return c, err
}

func (sc *ServiceConfig) getMasterClient() (*master.Client, error) {
	glog.Info("start getMasterClient ... sc.agentPort: %+v", sc.agentPort)
	c, err := master.NewClient(sc.agentPort)
	if err != nil {
		glog.Errorf("Could not create a control center client to %v: %v", sc.agentPort, err)
		return nil, err
	}
	glog.Info("end getMasterClient")
	return c, nil
}

func (sc *ServiceConfig) newRequestHandler(check checkFunc, realfunc ctxhandlerFunc) handlerFunc {
	return func(w *rest.ResponseWriter, r *rest.Request) {
		if !check(w, r) {
			return
		}
		reqCtx := newRequestContext(sc)
		defer reqCtx.end()
		realfunc(w, r, reqCtx)
	}
}

func (sc *ServiceConfig) checkAuth(realfunc ctxhandlerFunc) handlerFunc {
	check := func(w *rest.ResponseWriter, r *rest.Request) bool {
		if !loginOK(r) {
			restUnauthorized(w)
			return false
		}
		return true
	}
	return sc.newRequestHandler(check, realfunc)
}

func (sc *ServiceConfig) noAuth(realfunc ctxhandlerFunc) handlerFunc {
	check := func(w *rest.ResponseWriter, r *rest.Request) bool {
		return true
	}
	return sc.newRequestHandler(check, realfunc)
}

type requestContext struct {
	sc     *ServiceConfig
	master *master.Client
}

func newRequestContext(sc *ServiceConfig) *requestContext {
	return &requestContext{sc: sc}
}

func (ctx *requestContext) getMasterClient() (*master.Client, error) {
	if ctx.master == nil {
		c, err := ctx.sc.getMasterClient()
		if err != nil {
			glog.Errorf("Could not create a control center client: %v", err)
			return nil, err
		}
		ctx.master = c
	}
	return ctx.master, nil
}

func (ctx *requestContext) end() error {
	if ctx.master != nil {
		return ctx.master.Close()
	}
	return nil
}

type ctxhandlerFunc func(w *rest.ResponseWriter, r *rest.Request, ctx *requestContext)
type checkFunc func(w *rest.ResponseWriter, r *rest.Request) bool

type getRoutes func(sc *ServiceConfig) []rest.Route
<|endoftext|>


<commit_before>/*
Package lessgo implements a simple, stable, efficient and flexible web framework for Go.

Author1: https://github.com/henrylee2cn
Author2: https://github.com/changyu72
*/
package lessgo

import (
	"net"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/go-xorm/xorm"

	_ "github.com/lessgo/lessgo/_fixture"
	"github.com/lessgo/lessgo/dbservice"
	"github.com/lessgo/lessgo/engine"
	"github.com/lessgo/lessgo/logs"
	"github.com/lessgo/lessgo/virtrouter"
)

type (
	Lessgo struct {
		*Echo
		AppConfig    *Config
		home         string // 根路径"/"对应的url
		serverEnable bool   // 服务是否启用
		DBAccess     *dbservice.DBAccess
		lock         sync.RWMutex
	}
	NewServer func(engine.Config) engine.Server
)

const (
	NAME    = "Lessgo"
	VERSION = "0.4.0"
	ADDRESS = "https://github.com/lessgo/lessgo"
)

const (
	MB = 1 << 20
)

// 初始化全局Lessgo实例
var DefLessgo = func() *Lessgo {
	printInfo()
	registerAppConfig()
	registerDBConfig()
	registerMime()
	l := &Lessgo{
		Echo:         New(),
		AppConfig:    AppConfig,
		home:         "/",
		serverEnable: true,
	}
	// 初始化日志
	l.Echo.Logger().SetMsgChan(AppConfig.Log.AsyncChan)
	l.Echo.SetLogLevel(AppConfig.Log.Level)
	// 设置运行模式
	l.Echo.SetDebug(AppConfig.Debug)
	// 设置静态资源缓存
	l.Echo.SetMemoryCache(NewMemoryCache(
		AppConfig.FileCache.SingleFileAllowMB*MB,
		AppConfig.FileCache.MaxCapMB*MB,
		time.Duration(AppConfig.FileCache.CacheSecond)*time.Second),
	)
	// 设置渲染接口
	l.Echo.SetRenderer(NewPongo2Render(AppConfig.Debug))
	// 设置大小写敏感
	l.Echo.SetCaseSensitive(AppConfig.RouterCaseSensitive)
	// 设置上传文件允许的最大尺寸
	engine.MaxMemory = AppConfig.MaxMemoryMB * MB
	// 配置数据库
	l.DBAccess = newDBAccess()
	return l
}()

/*
 * 设置主页
 */
func SetHome(homeurl string) {
	if DefLessgo.AppConfig.RouterCaseSensitive {
		DefLessgo.home = homeurl
	} else {
		DefLessgo.home = strings.ToLower(homeurl)
	}
}

/*
 * 返回设置的主页
 */
func Home() string {
	return DefLessgo.home
}

/*
 * 开启网站服务
 */
func EnableServer() {
	DefLessgo.lock.Lock()
	DefLessgo.serverEnable = true
	DefLessgo.lock.Unlock()
}

/*
 * 关闭网站服务
 */
func DisableServer() {
	DefLessgo.lock.Lock()
	DefLessgo.serverEnable = false
	DefLessgo.lock.Unlock()
}

/*
 * 查询网站服务状态
 */
func ServerEnable() bool {
	DefLessgo.lock.RLock()
	defer DefLessgo.lock.RUnlock()
	return DefLessgo.serverEnable
}

/*
 * 运行服务
 */
func Run(server NewServer, listener ...net.Listener) {
	checkHooks(registerRouter())
	checkHooks(registerSession())

	// 配置服务器引擎
	c := engine.Config{
		Address:      AppConfig.Listen.Address,
		ReadTimeout:  time.Duration(AppConfig.Listen.ReadTimeout),
		WriteTimeout: time.Duration(AppConfig.Listen.WriteTimeout),
	}
	h := "HTTP"
	if AppConfig.Listen.EnableHTTPS {
		h = "HTTPS"
		c.TLSKeyfile = AppConfig.Listen.HTTPSKeyFile
		c.TLSCertfile = AppConfig.Listen.HTTPSCertFile
	}
	if len(listener) > 0 && listener[0] != nil {
		c.Listener = listener[0]
	}

	// 开启最大核心数运行
	runtime.GOMAXPROCS(runtime.NumCPU())

	// 启动服务
	mode := "release"
	if AppConfig.Debug {
		mode = "debug"
	}
	DefLessgo.Logger().Sys("> %s listening and serving %s on %v (%s-mode)", AppConfig.AppName, h, c.Address, mode)
	DefLessgo.Run(server(c))
}

/*
 * 在路由执行位置之前紧邻插入中间件队列
 */
func Before(middleware ...interface{}) {
	DefLessgo.Echo.BeforeUse(wrapMiddlewares(middleware)...)
}

/*
 * 在路由执行位置之后紧邻插入中间件队列
 */
func After(middleware ...interface{}) {
	DefLessgo.Echo.AfterUse(wrapMiddlewares(middleware)...)
}

/*
 * 获取默认数据库引擎
 */
func DefaultDB() *xorm.Engine {
	return DefLessgo.DBAccess.DefaultDB()
}

/*
 * 获取全部数据库引擎列表
 */
func DBList() map[string]*xorm.Engine {
	return DefLessgo.DBAccess.DBList()
}

/*
 * 设置默认数据库引擎
 */
func SetDefaultDB(name string) error {
	return DefLessgo.DBAccess.SetDefaultDB(name)
}

/*
 * 获取指定数据库引擎
 */
func GetDB(name string) (*xorm.Engine, bool) {
	return DefLessgo.DBAccess.GetDB(name)
}

/*
 * 重建真实路由
 */
func ResetRealRoute() {
	if err := middlewareExistCheck(DefVirtRouter); err != nil {
		DefLessgo.Logger().Error("Create/Recreate the router is faulty: %v", err)
		return
	}

	DefLessgo.Echo.lock.Lock()
	defer DefLessgo.Echo.lock.Unlock()

	defer func() {
		// 创建静态路由
		staticRoute()
	}()

	// 创建动态路由
	DefLessgo.Echo.router = NewRouter(DefLessgo.Echo)
	DefLessgo.Echo.middleware = []MiddlewareFunc{DefLessgo.Echo.router.Process}
	DefLessgo.Echo.head = DefLessgo.Echo.pristineHead
	registerRootMiddlewares()
	DefLessgo.Echo.BeforeUse(getMiddlewares(beforeMiddlewares)...)
	DefLessgo.Echo.AfterUse(getMiddlewares(afterMiddlewares)...)
	for _, child := range DefVirtRouter.Children() {
		if !child.Enable() {
			continue
		}
		var group *Group
		for _, d := range child.Progeny() {
			if !d.Enable() {
				continue
			}
			mws := getMiddlewares(d.Middleware())
			prefix := d.VirtHandler().Prefix()
			prefix2 := strings.TrimSuffix(d.VirtHandler().PrefixPath(), "/index") + d.VirtHandler().PrefixParam() + "/"
			hasIndex := prefix2 != prefix
			switch d.Type() {
			case virtrouter.GROUP:
				if group == nil {
					if hasIndex {
						// "/index"分组会被默认为"/"
						group = DefLessgo.Echo.Group(prefix2, mws...)
					} else {
						group = DefLessgo.Echo.Group(prefix, mws...)
					}
					break
				}
				if hasIndex {
					// "/index"分组会被默认为"/"
					group = group.Group(prefix2, mws...)
				} else {
					group = group.Group(prefix, mws...)
				}
			case virtrouter.HANDLER:
				methods := d.VirtHandler().Methods()
				handler := getHandlerMap(d.VirtHandler().Id())
				if group == nil {
					if hasIndex {
						DefLessgo.Echo.Match(methods, prefix2, handler, mws...)
					}
					DefLessgo.Echo.Match(methods, prefix, handler, mws...)
					break
				}
				if hasIndex {
					group.Match(methods, prefix2, handler, mws...)
				}
				group.Match(methods, prefix, handler, mws...)
			}
		}
	}
}

/*
 * 返回打印实例
 */
func Logger() logs.Logger {
	return DefLessgo.Echo.Logger()
}
<commit_msg>Home()改为GetHome()<commit_after>/*
Package lessgo implements a simple, stable, efficient and flexible web framework for Go.

Author1: https://github.com/henrylee2cn
Author2: https://github.com/changyu72
*/
package lessgo

import (
	"net"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/go-xorm/xorm"

	_ "github.com/lessgo/lessgo/_fixture"
	"github.com/lessgo/lessgo/dbservice"
	"github.com/lessgo/lessgo/engine"
	"github.com/lessgo/lessgo/logs"
	"github.com/lessgo/lessgo/virtrouter"
)

type (
	Lessgo struct {
		*Echo
		AppConfig    *Config
		home         string // 根路径"/"对应的url
		serverEnable bool   // 服务是否启用
		DBAccess     *dbservice.DBAccess
		lock         sync.RWMutex
	}
	NewServer func(engine.Config) engine.Server
)

const (
	NAME    = "Lessgo"
	VERSION = "0.4.0"
	ADDRESS = "https://github.com/lessgo/lessgo"
)

const (
	MB = 1 << 20
)

// 初始化全局Lessgo实例
var DefLessgo = func() *Lessgo {
	printInfo()
	registerAppConfig()
	registerDBConfig()
	registerMime()
	l := &Lessgo{
		Echo:         New(),
		AppConfig:    AppConfig,
		home:         "/",
		serverEnable: true,
	}
	// 初始化日志
	l.Echo.Logger().SetMsgChan(AppConfig.Log.AsyncChan)
	l.Echo.SetLogLevel(AppConfig.Log.Level)
	// 设置运行模式
	l.Echo.SetDebug(AppConfig.Debug)
	// 设置静态资源缓存
	l.Echo.SetMemoryCache(NewMemoryCache(
		AppConfig.FileCache.SingleFileAllowMB*MB,
		AppConfig.FileCache.MaxCapMB*MB,
		time.Duration(AppConfig.FileCache.CacheSecond)*time.Second),
	)
	// 设置渲染接口
	l.Echo.SetRenderer(NewPongo2Render(AppConfig.Debug))
	// 设置大小写敏感
	l.Echo.SetCaseSensitive(AppConfig.RouterCaseSensitive)
	// 设置上传文件允许的最大尺寸
	engine.MaxMemory = AppConfig.MaxMemoryMB * MB
	// 配置数据库
	l.DBAccess = newDBAccess()
	return l
}()

/*
 * 设置主页
 */
func SetHome(homeurl string) {
	if DefLessgo.AppConfig.RouterCaseSensitive {
		DefLessgo.home = homeurl
	} else {
		DefLessgo.home = strings.ToLower(homeurl)
	}
}

/*
 * 返回设置的主页
 */
func GetHome() string {
	return DefLessgo.home
}

/*
 * 开启网站服务
 */
func EnableServer() {
	DefLessgo.lock.Lock()
	DefLessgo.serverEnable = true
	DefLessgo.lock.Unlock()
}

/*
 * 关闭网站服务
 */
func DisableServer() {
	DefLessgo.lock.Lock()
	DefLessgo.serverEnable = false
	DefLessgo.lock.Unlock()
}

/*
 * 查询网站服务状态
 */
func ServerEnable() bool {
	DefLessgo.lock.RLock()
	defer DefLessgo.lock.RUnlock()
	return DefLessgo.serverEnable
}

/*
 * 运行服务
 */
func Run(server NewServer, listener ...net.Listener) {
	checkHooks(registerRouter())
	checkHooks(registerSession())

	// 配置服务器引擎
	c := engine.Config{
		Address:      AppConfig.Listen.Address,
		ReadTimeout:  time.Duration(AppConfig.Listen.ReadTimeout),
		WriteTimeout: time.Duration(AppConfig.Listen.WriteTimeout),
	}
	h := "HTTP"
	if AppConfig.Listen.EnableHTTPS {
		h = "HTTPS"
		c.TLSKeyfile = AppConfig.Listen.HTTPSKeyFile
		c.TLSCertfile = AppConfig.Listen.HTTPSCertFile
	}
	if len(listener) > 0 && listener[0] != nil {
		c.Listener = listener[0]
	}

	// 开启最大核心数运行
	runtime.GOMAXPROCS(runtime.NumCPU())

	// 启动服务
	mode := "release"
	if AppConfig.Debug {
		mode = "debug"
	}
	DefLessgo.Logger().Sys("> %s listening and serving %s on %v (%s-mode)", AppConfig.AppName, h, c.Address, mode)
	DefLessgo.Run(server(c))
}

/*
 * 在路由执行位置之前紧邻插入中间件队列
 */
func Before(middleware ...interface{}) {
	DefLessgo.Echo.BeforeUse(wrapMiddlewares(middleware)...)
}

/*
 * 在路由执行位置之后紧邻插入中间件队列
 */
func After(middleware ...interface{}) {
	DefLessgo.Echo.AfterUse(wrapMiddlewares(middleware)...)
}

/*
 * 获取默认数据库引擎
 */
func DefaultDB() *xorm.Engine {
	return DefLessgo.DBAccess.DefaultDB()
}

/*
 * 获取全部数据库引擎列表
 */
func DBList() map[string]*xorm.Engine {
	return DefLessgo.DBAccess.DBList()
}

/*
 * 设置默认数据库引擎
 */
func SetDefaultDB(name string) error {
	return DefLessgo.DBAccess.SetDefaultDB(name)
}

/*
 * 获取指定数据库引擎
 */
func GetDB(name string) (*xorm.Engine, bool) {
	return DefLessgo.DBAccess.GetDB(name)
}

/*
 * 重建真实路由
 */
func ResetRealRoute() {
	if err := middlewareExistCheck(DefVirtRouter); err != nil {
		DefLessgo.Logger().Error("Create/Recreate the router is faulty: %v", err)
		return
	}

	DefLessgo.Echo.lock.Lock()
	defer DefLessgo.Echo.lock.Unlock()

	defer func() {
		// 创建静态路由
		staticRoute()
	}()

	// 创建动态路由
	DefLessgo.Echo.router = NewRouter(DefLessgo.Echo)
	DefLessgo.Echo.middleware = []MiddlewareFunc{DefLessgo.Echo.router.Process}
	DefLessgo.Echo.head = DefLessgo.Echo.pristineHead
	registerRootMiddlewares()
	DefLessgo.Echo.BeforeUse(getMiddlewares(beforeMiddlewares)...)
	DefLessgo.Echo.AfterUse(getMiddlewares(afterMiddlewares)...)
	for _, child := range DefVirtRouter.Children() {
		if !child.Enable() {
			continue
		}
		var group *Group
		for _, d := range child.Progeny() {
			if !d.Enable() {
				continue
			}
			mws := getMiddlewares(d.Middleware())
			prefix := d.VirtHandler().Prefix()
			prefix2 := strings.TrimSuffix(d.VirtHandler().PrefixPath(), "/index") + d.VirtHandler().PrefixParam() + "/"
			hasIndex := prefix2 != prefix
			switch d.Type() {
			case virtrouter.GROUP:
				if group == nil {
					if hasIndex {
						// "/index"分组会被默认为"/"
						group = DefLessgo.Echo.Group(prefix2, mws...)
					} else {
						group = DefLessgo.Echo.Group(prefix, mws...)
					}
					break
				}
				if hasIndex {
					// "/index"分组会被默认为"/"
					group = group.Group(prefix2, mws...)
				} else {
					group = group.Group(prefix, mws...)
				}
			case virtrouter.HANDLER:
				methods := d.VirtHandler().Methods()
				handler := getHandlerMap(d.VirtHandler().Id())
				if group == nil {
					if hasIndex {
						DefLessgo.Echo.Match(methods, prefix2, handler, mws...)
					}
					DefLessgo.Echo.Match(methods, prefix, handler, mws...)
					break
				}
				if hasIndex {
					group.Match(methods, prefix2, handler, mws...)
				}
				group.Match(methods, prefix, handler, mws...)
			}
		}
	}
}

/*
 * 返回打印实例
 */
func Logger() logs.Logger {
	return DefLessgo.Echo.Logger()
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/platforms/ardrone"
)

func main() {
	gbot := gobot.NewGobot()

	ardroneAdaptor := ardrone.NewArdroneAdaptor("Drone")
	drone := ardrone.NewArdroneDriver(ardroneAdaptor, "Drone")

	work := func() {
		drone.TakeOff()
		gobot.On(drone.Event("flying"), func(data interface{}) {
			gobot.After(3*time.Second, func() {
				drone.Land()
			})
		})
	}

	robot := gobot.NewRobot("drone",
		[]gobot.Connection{ardroneAdaptor},
		[]gobot.Device{drone},
		work,
	)
	gbot.AddRobot(robot)

	gbot.Start()
}
<commit_msg>Fixed event race condition<commit_after>package main

import (
	"time"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/platforms/ardrone"
)

func main() {
	gbot := gobot.NewGobot()

	ardroneAdaptor := ardrone.NewArdroneAdaptor("Drone")
	drone := ardrone.NewArdroneDriver(ardroneAdaptor, "Drone")

	work := func() {
		gobot.On(drone.Event("flying"), func(data interface{}) {
			gobot.After(3*time.Second, func() {
				drone.Land()
			})
		})
		drone.TakeOff()
	}

	robot := gobot.NewRobot("drone",
		[]gobot.Connection{ardroneAdaptor},
		[]gobot.Device{drone},
		work,
	)
	gbot.AddRobot(robot)

	gbot.Start()
}
<|endoftext|>