<commit_before>package actions

import (
	"math/rand"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/v2tec/watchtower/container"
)

var (
	letters  = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	waitTime = 10 * time.Second
)

func allContainersFilter(container.Container) bool { return true }

func containerFilter(names []string) container.Filter {
	if len(names) == 0 {
		return allContainersFilter
	}

	return func(c container.Container) bool {
		for _, name := range names {
			if (name == c.Name()) || (name == c.Name()[1:]) {
				return true
			}
		}
		return false
	}
}

// Update looks at the running Docker containers to see if any of the images
// used to start those containers have been updated. If a change is detected in
// any of the images, the associated containers are stopped and restarted with
// the new image.
func Update(client container.Client, names []string, cleanup bool, noRestart bool) error {
	log.Info("Checking containers for updated images")

	containers, err := client.ListContainers(containerFilter(names))
	if err != nil {
		return err
	}

	for i, container := range containers {
		stale, err := client.IsContainerStale(container)
		if err != nil {
			log.Infof("Unable to update container %s. Proceeding to next.", containers[i].Name())
			log.Debug(err)
			stale = false
		}
		containers[i].Stale = stale
	}

	containers, err = container.SortByDependencies(containers)
	if err != nil {
		return err
	}

	checkDependencies(containers)

	// Stop stale containers in reverse order
	for i := len(containers) - 1; i >= 0; i-- {
		container := containers[i]

		if container.IsWatchtower() {
			continue
		}

		if container.Stale {
			if err := client.StopContainer(container, waitTime); err != nil {
				log.Error(err)
			}
		}
	}

	// Restart stale containers in sorted order
	for _, container := range containers {
		if container.Stale {
			// Since we can't shutdown a watchtower container immediately, we need to
			// start the new one while the old one is still running. This prevents us
			// from re-using the same container name so we first rename the current
			// instance so that the new one can adopt the old name.
			if container.IsWatchtower() {
				if err := client.RenameContainer(container, randName()); err != nil {
					log.Error(err)
					continue
				}
			}

			if !noRestart {
				if err := client.StartContainer(container); err != nil {
					log.Error(err)
				}
			}

			if cleanup {
				client.RemoveImage(container)
			}
		}
	}

	return nil
}

func checkDependencies(containers []container.Container) {

	for i, parent := range containers {
		if parent.Stale {
			continue
		}

	LinkLoop:
		for _, linkName := range parent.Links() {
			for _, child := range containers {
				if child.Name() == linkName && child.Stale {
					containers[i].Stale = true
					break LinkLoop
				}
			}
		}
	}
}

// Generates a random, 32-character, Docker-compatible container name.
func randName() string {
	b := make([]rune, 32)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}

	return string(b)
}
<commit_msg>Output "Checking containers for updated images" as debug entry. fixes GH-66<commit_after>package actions

import (
	"math/rand"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/v2tec/watchtower/container"
)

var (
	letters  = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
	waitTime = 10 * time.Second
)

func allContainersFilter(container.Container) bool { return true }

func containerFilter(names []string) container.Filter {
	if len(names) == 0 {
		return allContainersFilter
	}

	return func(c container.Container) bool {
		for _, name := range names {
			if (name == c.Name()) || (name == c.Name()[1:]) {
				return true
			}
		}
		return false
	}
}

// Update looks at the running Docker containers to see if any of the images
// used to start those containers have been updated. If a change is detected in
// any of the images, the associated containers are stopped and restarted with
// the new image.
func Update(client container.Client, names []string, cleanup bool, noRestart bool) error {
	log.Debug("Checking containers for updated images")

	containers, err := client.ListContainers(containerFilter(names))
	if err != nil {
		return err
	}

	for i, container := range containers {
		stale, err := client.IsContainerStale(container)
		if err != nil {
			log.Infof("Unable to update container %s. Proceeding to next.", containers[i].Name())
			log.Debug(err)
			stale = false
		}
		containers[i].Stale = stale
	}

	containers, err = container.SortByDependencies(containers)
	if err != nil {
		return err
	}

	checkDependencies(containers)

	// Stop stale containers in reverse order
	for i := len(containers) - 1; i >= 0; i-- {
		container := containers[i]

		if container.IsWatchtower() {
			continue
		}

		if container.Stale {
			if err := client.StopContainer(container, waitTime); err != nil {
				log.Error(err)
			}
		}
	}

	// Restart stale containers in sorted order
	for _, container := range containers {
		if container.Stale {
			// Since we can't shutdown a watchtower container immediately, we need to
			// start the new one while the old one is still running. This prevents us
			// from re-using the same container name so we first rename the current
			// instance so that the new one can adopt the old name.
			if container.IsWatchtower() {
				if err := client.RenameContainer(container, randName()); err != nil {
					log.Error(err)
					continue
				}
			}

			if !noRestart {
				if err := client.StartContainer(container); err != nil {
					log.Error(err)
				}
			}

			if cleanup {
				client.RemoveImage(container)
			}
		}
	}

	return nil
}

func checkDependencies(containers []container.Container) {

	for i, parent := range containers {
		if parent.Stale {
			continue
		}

	LinkLoop:
		for _, linkName := range parent.Links() {
			for _, child := range containers {
				if child.Name() == linkName && child.Stale {
					containers[i].Stale = true
					break LinkLoop
				}
			}
		}
	}
}

// Generates a random, 32-character, Docker-compatible container name.
func randName() string {
	b := make([]rune, 32)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}

	return string(b)
}
<|endoftext|>


<commit_before>package controller

import (
	. "eaciit/wfdemo-git/library/models"
	"eaciit/wfdemo-git/web/helper"
	"errors"
	"reflect"
	"strings"
	"time"

	"github.com/eaciit/acl/v1.0"
	// "github.com/eaciit/dbox"
	"github.com/eaciit/knot/knot.v1"
	"github.com/eaciit/toolkit"

	. "eaciit/wfdemo-git/library/core"
)

type LoginController struct {
	App
}

func CreateLoginController() *LoginController {
	var controller = new(LoginController)
	return controller
}

func (l *LoginController) GetSession(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	sessionId := r.Session("sessionid", "")
	return helper.CreateResult(true, sessionId, "")
}

func (l *LoginController) CheckCurrentSession(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	sessionid := r.Session("sessionid", "")

	// toolkit.Printf("CheckCurrentSession: %#v \v", sessionid)

	if !acl.IsSessionIDActive(toolkit.ToString(sessionid)) {
		r.SetSession("sessionid", "")
		return helper.CreateResult(false, false, "inactive")
	}
	return helper.CreateResult(true, true, "active")
}

func (l *LoginController) GetMenuList(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	menuList, err := GetListOfMenu(toolkit.ToString(r.Session("sessionid", "")))
	if err != nil {
		return helper.CreateResult(false, "", err.Error())
	}

	// remarked by ams, 2016-10-15
	// issue ServerAddress is localhost blablabla
	// suggestion : if you want to check with the real address please put it (the address / base url) in the configuration file
	//              if not, please find by segment or split by /

	payload := toolkit.M{}
	if err := r.GetPayload(&payload); err != nil {
		return helper.CreateResult(false, "", err.Error())
	}

	maxURLLen := 4
	urlSplit := strings.SplitN(payload.GetString("url"), "/", maxURLLen)
	if len(urlSplit) == maxURLLen {
		url := "/" + urlSplit[maxURLLen-1]

		isFound := false
		if len(MenuList) > 0 {
			for _, val := range MenuList {
				if val == url {
					isFound = true
				}
			}
			if url == "/web/page/login" {
				isFound = true
			}
			if !isFound {

				return helper.CreateResult(false, "", "You don't have access to this page")
			}
		}
	}

	return helper.CreateResult(true, menuList, "success")
}

func getMenus(r *knot.WebContext) (interface{}, error) {
	menuList, err := GetListOfMenu(toolkit.ToString(r.Session("sessionid", "")))
	if err != nil {
		return nil, err
	}

	payload := toolkit.M{}
	if err := r.GetPayload(&payload); err != nil {
		return nil, err
	}

	maxURLLen := 4
	urlSplit := strings.SplitN(payload.GetString("url"), "/", maxURLLen)
	if len(urlSplit) == maxURLLen {
		url := "/" + urlSplit[maxURLLen-1]

		isFound := false
		if len(MenuList) > 0 {
			for _, val := range MenuList {
				if val == url {
					isFound = true
				}
			}
			if url == "/web/page/login" {
				isFound = true
			}
			if !isFound {
				return nil, err
			}
		}
	}

	return menuList, err
}

func (l *LoginController) GetUserName(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	sessionId := r.Session("sessionid", "")

	if toolkit.ToString(sessionId) == "" {
		err := error(errors.New("Sessionid is not found"))
		return helper.CreateResult(false, nil, err.Error())
	}
	tUser, err := GetUserName(sessionId)

	if err != nil {
		return helper.CreateResult(false, nil, "Get username failed")
	}

	return helper.CreateResult(true, tUser.LoginID, "")
}

func (l *LoginController) ProcessLogin(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	lastDateData, _ := time.Parse("2006-01-02 15:04", "2016-10-31 23:59")

	payload := toolkit.M{}
	if err := r.GetPayload(&payload); err != nil {
		return helper.CreateResult(false, "", err.Error())
	}
	MenuList = []string{}
	menus, sessid, err := LoginProcess(payload)
	if err != nil {
		return helper.CreateResult(false, "", err.Error())
	}
	WriteLog(sessid, "login", r.Request.URL.String())
	r.SetSession("sessionid", sessid)
	r.SetSession("menus", menus)
	helper.WC = r
	MenuList = menus

	// temporary add last date hardcode, then will change to get it from database automatically
	// add by ams, 2016-10-04

	query := DB().Connection.NewQuery().From(new(ScadaData).TableName()).Order("-timestamp").Take(1)

	csr, e := query.Cursor(nil)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	Result := make([]ScadaData, 0)
	e = csr.Fetch(&Result, 0, false)

	csr.Close()

	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	for _, val := range Result {
		// toolkit.Printf("Result : %s \n", val.TimeStamp.UTC())
		lastDateData = val.TimeStamp.UTC()
	}

	// toolkit.Printf("Result : %s \n", lastDateData)
	lastDateData = lastDateData.UTC()
	r.SetSession("lastdate_data", lastDateData)

	// Get Available Date All Collection
	latestDataPeriods := make([]LatestDataPeriod, 0)
	csr, e = DB().Connection.NewQuery().From(NewLatestDataPeriod().TableName()).Cursor(nil)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	e = csr.Fetch(&latestDataPeriods, 0, false)
	csr.Close()

	// toolkit.Println(latestDataPeriods)

	type availdatedata struct {
		ScadaData         []time.Time
		DGRData           []time.Time
		Alarm             []time.Time
		JMR               []time.Time
		MET               []time.Time
		Duration          []time.Time
		ScadaAnomaly      []time.Time
		AlarmOverlapping  []time.Time
		AlarmScadaAnomaly []time.Time
	}

	datePeriod := new(availdatedata)
	xdp := reflect.ValueOf(datePeriod).Elem()
	for _, d := range latestDataPeriods {
		f := xdp.FieldByName(d.Type)
		if f.IsValid() {
			if f.CanSet() {
				f.Set(reflect.ValueOf(d.Data))
			}
		}
	}

	r.SetSession("availdate", datePeriod)

	data := toolkit.M{
		"status":    true,
		"sessionid": sessid,
	}

	return helper.CreateResult(true, data, "Login Success")
}

func (l *LoginController) Logout(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	err := SetExpired(toolkit.M{"_id": r.Session("sessionid", "")})
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}
	WriteLog(r.Session("sessionid", ""), "logout", r.Request.URL.String())
	r.SetSession("sessionid", "")

	return helper.CreateResult(true, nil, "Logout Success")
}

func (l *LoginController) ResetPassword(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	payload := toolkit.M{}
	err := r.GetPayload(&payload)
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}
	if err = ResetPassword(payload); err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	return helper.CreateResult(true, nil, "Reset Password Success")
}

func (l *LoginController) SavePassword(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	payload := toolkit.M{}
	err := r.GetPayload(&payload)
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	if err = SavePassword(payload); err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	return helper.CreateResult(true, nil, "Save Password Success")
}

func (l *LoginController) Authenticate(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	payload := toolkit.M{}

	if err := r.GetPayload(&payload); err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	result, err := AuthenticateProc(payload)
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	return helper.CreateResult(true, result, "Authenticate Success")
}
<commit_msg>Bug fix availdata for scadahfd<commit_after>package controller

import (
	. "eaciit/wfdemo-git/library/models"
	"eaciit/wfdemo-git/web/helper"
	"errors"
	"reflect"
	"strings"
	"time"

	"github.com/eaciit/acl/v1.0"
	// "github.com/eaciit/dbox"
	"github.com/eaciit/knot/knot.v1"
	"github.com/eaciit/toolkit"

	. "eaciit/wfdemo-git/library/core"
)

type LoginController struct {
	App
}

func CreateLoginController() *LoginController {
	var controller = new(LoginController)
	return controller
}

func (l *LoginController) GetSession(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	sessionId := r.Session("sessionid", "")
	return helper.CreateResult(true, sessionId, "")
}

func (l *LoginController) CheckCurrentSession(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	sessionid := r.Session("sessionid", "")

	// toolkit.Printf("CheckCurrentSession: %#v \v", sessionid)

	if !acl.IsSessionIDActive(toolkit.ToString(sessionid)) {
		r.SetSession("sessionid", "")
		return helper.CreateResult(false, false, "inactive")
	}
	return helper.CreateResult(true, true, "active")
}

func (l *LoginController) GetMenuList(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	menuList, err := GetListOfMenu(toolkit.ToString(r.Session("sessionid", "")))
	if err != nil {
		return helper.CreateResult(false, "", err.Error())
	}

	// remarked by ams, 2016-10-15
	// issue ServerAddress is localhost blablabla
	// suggestion : if you want to check with the real address please put it (the address / base url) in the configuration file
	//              if not, please find by segment or split by /

	payload := toolkit.M{}
	if err := r.GetPayload(&payload); err != nil {
		return helper.CreateResult(false, "", err.Error())
	}

	maxURLLen := 4
	urlSplit := strings.SplitN(payload.GetString("url"), "/", maxURLLen)
	if len(urlSplit) == maxURLLen {
		url := "/" + urlSplit[maxURLLen-1]

		isFound := false
		if len(MenuList) > 0 {
			for _, val := range MenuList {
				if val == url {
					isFound = true
				}
			}
			if url == "/web/page/login" {
				isFound = true
			}
			if !isFound {

				return helper.CreateResult(false, "", "You don't have access to this page")
			}
		}
	}

	return helper.CreateResult(true, menuList, "success")
}

func getMenus(r *knot.WebContext) (interface{}, error) {
	menuList, err := GetListOfMenu(toolkit.ToString(r.Session("sessionid", "")))
	if err != nil {
		return nil, err
	}

	payload := toolkit.M{}
	if err := r.GetPayload(&payload); err != nil {
		return nil, err
	}

	maxURLLen := 4
	urlSplit := strings.SplitN(payload.GetString("url"), "/", maxURLLen)
	if len(urlSplit) == maxURLLen {
		url := "/" + urlSplit[maxURLLen-1]

		isFound := false
		if len(MenuList) > 0 {
			for _, val := range MenuList {
				if val == url {
					isFound = true
				}
			}
			if url == "/web/page/login" {
				isFound = true
			}
			if !isFound {
				return nil, err
			}
		}
	}

	return menuList, err
}

func (l *LoginController) GetUserName(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson
	sessionId := r.Session("sessionid", "")

	if toolkit.ToString(sessionId) == "" {
		err := error(errors.New("Sessionid is not found"))
		return helper.CreateResult(false, nil, err.Error())
	}
	tUser, err := GetUserName(sessionId)

	if err != nil {
		return helper.CreateResult(false, nil, "Get username failed")
	}

	return helper.CreateResult(true, tUser.LoginID, "")
}

func (l *LoginController) ProcessLogin(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	lastDateData, _ := time.Parse("2006-01-02 15:04", "2016-10-31 23:59")

	payload := toolkit.M{}
	if err := r.GetPayload(&payload); err != nil {
		return helper.CreateResult(false, "", err.Error())
	}
	MenuList = []string{}
	menus, sessid, err := LoginProcess(payload)
	if err != nil {
		return helper.CreateResult(false, "", err.Error())
	}
	WriteLog(sessid, "login", r.Request.URL.String())
	r.SetSession("sessionid", sessid)
	r.SetSession("menus", menus)
	helper.WC = r
	MenuList = menus

	// temporary add last date hardcode, then will change to get it from database automatically
	// add by ams, 2016-10-04

	query := DB().Connection.NewQuery().From(new(ScadaData).TableName()).Order("-timestamp").Take(1)

	csr, e := query.Cursor(nil)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	Result := make([]ScadaData, 0)
	e = csr.Fetch(&Result, 0, false)

	csr.Close()

	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	for _, val := range Result {
		// toolkit.Printf("Result : %s \n", val.TimeStamp.UTC())
		lastDateData = val.TimeStamp.UTC()
	}

	// toolkit.Printf("Result : %s \n", lastDateData)
	lastDateData = lastDateData.UTC()
	r.SetSession("lastdate_data", lastDateData)

	// Get Available Date All Collection
	latestDataPeriods := make([]LatestDataPeriod, 0)
	csr, e = DB().Connection.NewQuery().From(NewLatestDataPeriod().TableName()).Cursor(nil)
	if e != nil {
		return helper.CreateResult(false, nil, e.Error())
	}

	e = csr.Fetch(&latestDataPeriods, 0, false)
	csr.Close()

	// toolkit.Println(latestDataPeriods)

	type availdatedata struct {
		ScadaData         []time.Time
		DGRData           []time.Time
		Alarm             []time.Time
		JMR               []time.Time
		MET               []time.Time
		Duration          []time.Time
		ScadaAnomaly      []time.Time
		AlarmOverlapping  []time.Time
		AlarmScadaAnomaly []time.Time
		ScadaDataOEM      []time.Time
		ScadaDataHFD      []time.Time
	}

	datePeriod := new(availdatedata)
	xdp := reflect.ValueOf(datePeriod).Elem()
	for _, d := range latestDataPeriods {
		f := xdp.FieldByName(d.Type)
		if f.IsValid() {
			if f.CanSet() {
				f.Set(reflect.ValueOf(d.Data))
			}
		}
	}

	r.SetSession("availdate", datePeriod)

	data := toolkit.M{
		"status":    true,
		"sessionid": sessid,
	}

	return helper.CreateResult(true, data, "Login Success")
}

func (l *LoginController) Logout(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	err := SetExpired(toolkit.M{"_id": r.Session("sessionid", "")})
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}
	WriteLog(r.Session("sessionid", ""), "logout", r.Request.URL.String())
	r.SetSession("sessionid", "")

	return helper.CreateResult(true, nil, "Logout Success")
}

func (l *LoginController) ResetPassword(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	payload := toolkit.M{}
	err := r.GetPayload(&payload)
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}
	if err = ResetPassword(payload); err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	return helper.CreateResult(true, nil, "Reset Password Success")
}

func (l *LoginController) SavePassword(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	payload := toolkit.M{}
	err := r.GetPayload(&payload)
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	if err = SavePassword(payload); err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	return helper.CreateResult(true, nil, "Save Password Success")
}

func (l *LoginController) Authenticate(r *knot.WebContext) interface{} {
	r.Config.OutputType = knot.OutputJson

	payload := toolkit.M{}

	if err := r.GetPayload(&payload); err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	result, err := AuthenticateProc(payload)
	if err != nil {
		return helper.CreateResult(false, nil, err.Error())
	}

	return helper.CreateResult(true, result, "Authenticate Success")
}
<|endoftext|>


<commit_before>package whitelist

import (
	"strings"
	"sync"

	"github.com/rancher/rancher/pkg/settings"
)

var (
	Proxy = ProxyList{
		RWMutex:        sync.RWMutex{},
		whitelistProxy: map[string]bool{},
	}
)

type ProxyList struct {
	sync.RWMutex
	whitelistProxy map[string]bool
}

func (p *ProxyList) Get() []string {
	p.RLock()
	p.RUnlock()
	v := settings.WhitelistDomain.Get()
	r := strings.Split(v, ",")
	for k := range p.whitelistProxy {
		r = append(r, k)
	}
	return r
}

func (p *ProxyList) Add(key string) {
	p.Lock()
	p.Unlock()
	p.whitelistProxy[key] = true
}

func (p *ProxyList) Rm(key string) {
	p.Lock()
	p.Unlock()
	delete(p.whitelistProxy, key)
}
<commit_msg>add defer<commit_after>package whitelist

import (
	"strings"
	"sync"

	"github.com/rancher/rancher/pkg/settings"
)

var (
	Proxy = ProxyList{
		RWMutex:        sync.RWMutex{},
		whitelistProxy: map[string]bool{},
	}
)

type ProxyList struct {
	sync.RWMutex
	whitelistProxy map[string]bool
}

func (p *ProxyList) Get() []string {
	p.RLock()
	defer p.RUnlock()
	v := settings.WhitelistDomain.Get()
	r := strings.Split(v, ",")
	for k := range p.whitelistProxy {
		r = append(r, k)
	}
	return r
}

func (p *ProxyList) Add(key string) {
	p.Lock()
	defer p.Unlock()
	p.whitelistProxy[key] = true
}

func (p *ProxyList) Rm(key string) {
	p.Lock()
	defer p.Unlock()
	delete(p.whitelistProxy, key)
}
<|endoftext|>


<commit_before>package admin

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
)

type scopeFunc func(db *gorm.DB, context *qor.Context) *gorm.DB

type Pagination struct {
	Total       int
	Pages       int
	CurrentPage int
	PrePage     int
}

type Searcher struct {
	*Context
	scopes         []*Scope
	filters        map[string]string
	withPagination bool
	Pagination     Pagination
}

func (s *Searcher) WithPagination() *Searcher {
	s.withPagination = true
	return s
}

func (s *Searcher) Page(num int) *Searcher {
	s.Pagination.CurrentPage = num
	return s
}

func (s *Searcher) PrePage(num int) *Searcher {
	s.Pagination.PrePage = num
	return s
}

func (s *Searcher) clone() *Searcher {
	return &Searcher{Context: s.Context, scopes: s.scopes, filters: s.filters}
}

func (s *Searcher) Scope(names ...string) *Searcher {
	newSearcher := s.clone()
	for _, name := range names {
		for _, scope := range s.Resource.scopes {
			if scope.Name == name && !scope.Default {
				newSearcher.scopes = append(newSearcher.scopes, scope)
				break
			}
		}
	}
	return newSearcher
}

func (s *Searcher) Filter(name, query string) *Searcher {
	newSearcher := s.clone()
	if newSearcher.filters == nil {
		newSearcher.filters = map[string]string{}
	}
	newSearcher.filters[name] = query
	return newSearcher
}

var filterRegexp = regexp.MustCompile(`^filters\[(.*?)\]$`)

func (s *Searcher) callScopes(context *qor.Context) *qor.Context {
	db := context.GetDB()

	// call default scopes
	for _, scope := range s.Resource.scopes {
		if scope.Default {
			db = scope.Handle(db, context)
		}
	}

	// call scopes
	for _, scope := range s.scopes {
		db = scope.Handle(db, context)
	}

	// call filters
	if s.filters != nil {
		for key, value := range s.filters {
			filter := s.Resource.filters[key]
			if filter != nil && filter.Handler != nil {
				db = filter.Handler(key, value, db, context)
			} else {
				db = DefaultHandler(key, value, db, context)
			}
		}
	}

	// add order by
	if order_by := context.Request.Form.Get("order_by"); order_by != "" {
		if strings.HasSuffix(order_by, "_desc") {
			db = db.Order(strings.TrimSuffix(order_by, "_desc")+" DESC", true)
		} else {
			db = db.Order(order_by, true)
		}
	}

	// call search
	if keyword := context.Request.Form.Get("keyword"); keyword != "" {
		if s.Resource.SearchHandler != nil {
			context.SetDB(s.Resource.SearchHandler(keyword, context))
			return context
		}
	}

	context.SetDB(db)
	return context
}

func (s *Searcher) cloneContext() *qor.Context {
	context := s.Context.Context
	return &qor.Context{
		Request:    context.Request,
		Writer:     context.Writer,
		ResourceID: context.ResourceID,
		Config:     context.Config,
		DB:         context.DB,
	}
}

func (s *Searcher) parseContext() *qor.Context {
	var context = s.cloneContext()
	var searcher = s.clone()

	if context != nil && context.Request != nil {
		// parse scopes
		scopes := context.Request.Form["scopes"]
		searcher = searcher.Scope(scopes...)

		// parse filters
		for key, value := range context.Request.Form {
			if matches := filterRegexp.FindStringSubmatch(key); len(matches) > 0 {
				searcher = searcher.Filter(matches[1], value[0])
			}
		}
	}

	searcher.callScopes(context)

	// pagination
	db := context.GetDB()
	paginationDB := db.Select("count(*) total").Model(s.Resource.Value).Set("gorm:query_destination", &s.Pagination)
	context.SetDB(paginationDB)
	s.Resource.CallFindMany(s.Resource.Value, context)

	if s.Pagination.CurrentPage == 0 {
		if s.Context.Request != nil {
			if page, err := strconv.Atoi(s.Context.Request.Form.Get("page")); err == nil {
				s.Pagination.CurrentPage = page
			}
		}

		if s.Pagination.CurrentPage == 0 {
			s.Pagination.CurrentPage = 1
		}
	}

	if s.Pagination.PrePage == 0 {
		s.Pagination.PrePage = s.Resource.Config.PageCount
	}

	if s.Pagination.CurrentPage > 0 {
		s.Pagination.Pages = (s.Pagination.Total-1)/s.Pagination.PrePage + 1

		db = db.Limit(s.Pagination.PrePage).Offset((s.Pagination.CurrentPage - 1) * s.Pagination.PrePage)
	}

	context.SetDB(db)

	return context
}

func (s *Searcher) FindMany() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewSlice()
	err := s.Resource.CallFindMany(result, context)
	return result, err
}

func (s *Searcher) FindOne() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewStruct()
	err := s.Resource.CallFindOne(result, nil, context)
	return result, err
}
<commit_msg>Fix possible SQL injection with order by<commit_after>package admin

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
)

type scopeFunc func(db *gorm.DB, context *qor.Context) *gorm.DB

type Pagination struct {
	Total       int
	Pages       int
	CurrentPage int
	PrePage     int
}

type Searcher struct {
	*Context
	scopes         []*Scope
	filters        map[string]string
	withPagination bool
	Pagination     Pagination
}

func (s *Searcher) WithPagination() *Searcher {
	s.withPagination = true
	return s
}

func (s *Searcher) Page(num int) *Searcher {
	s.Pagination.CurrentPage = num
	return s
}

func (s *Searcher) PrePage(num int) *Searcher {
	s.Pagination.PrePage = num
	return s
}

func (s *Searcher) clone() *Searcher {
	return &Searcher{Context: s.Context, scopes: s.scopes, filters: s.filters}
}

func (s *Searcher) Scope(names ...string) *Searcher {
	newSearcher := s.clone()
	for _, name := range names {
		for _, scope := range s.Resource.scopes {
			if scope.Name == name && !scope.Default {
				newSearcher.scopes = append(newSearcher.scopes, scope)
				break
			}
		}
	}
	return newSearcher
}

func (s *Searcher) Filter(name, query string) *Searcher {
	newSearcher := s.clone()
	if newSearcher.filters == nil {
		newSearcher.filters = map[string]string{}
	}
	newSearcher.filters[name] = query
	return newSearcher
}

var filterRegexp = regexp.MustCompile(`^filters\[(.*?)\]$`)

func (s *Searcher) callScopes(context *qor.Context) *qor.Context {
	db := context.GetDB()

	// call default scopes
	for _, scope := range s.Resource.scopes {
		if scope.Default {
			db = scope.Handle(db, context)
		}
	}

	// call scopes
	for _, scope := range s.scopes {
		db = scope.Handle(db, context)
	}

	// call filters
	if s.filters != nil {
		for key, value := range s.filters {
			filter := s.Resource.filters[key]
			if filter != nil && filter.Handler != nil {
				db = filter.Handler(key, value, db, context)
			} else {
				db = DefaultHandler(key, value, db, context)
			}
		}
	}

	// add order by
	if order_by := context.Request.Form.Get("order_by"); order_by != "" {
		if regexp.MustCompile("^[a-zA-Z_]+$").MatchString(order_by) {
			if strings.HasSuffix(order_by, "_desc") {
				db = db.Order(strings.TrimSuffix(order_by, "_desc")+" DESC", true)
			} else {
				db = db.Order(order_by, true)
			}
		}
	}

	// call search
	if keyword := context.Request.Form.Get("keyword"); keyword != "" {
		if s.Resource.SearchHandler != nil {
			context.SetDB(s.Resource.SearchHandler(keyword, context))
			return context
		}
	}

	context.SetDB(db)
	return context
}

func (s *Searcher) cloneContext() *qor.Context {
	context := s.Context.Context
	return &qor.Context{
		Request:    context.Request,
		Writer:     context.Writer,
		ResourceID: context.ResourceID,
		Config:     context.Config,
		DB:         context.DB,
	}
}

func (s *Searcher) parseContext() *qor.Context {
	var context = s.cloneContext()
	var searcher = s.clone()

	if context != nil && context.Request != nil {
		// parse scopes
		scopes := context.Request.Form["scopes"]
		searcher = searcher.Scope(scopes...)

		// parse filters
		for key, value := range context.Request.Form {
			if matches := filterRegexp.FindStringSubmatch(key); len(matches) > 0 {
				searcher = searcher.Filter(matches[1], value[0])
			}
		}
	}

	searcher.callScopes(context)

	// pagination
	db := context.GetDB()
	paginationDB := db.Select("count(*) total").Model(s.Resource.Value).Set("gorm:query_destination", &s.Pagination)
	context.SetDB(paginationDB)
	s.Resource.CallFindMany(s.Resource.Value, context)

	if s.Pagination.CurrentPage == 0 {
		if s.Context.Request != nil {
			if page, err := strconv.Atoi(s.Context.Request.Form.Get("page")); err == nil {
				s.Pagination.CurrentPage = page
			}
		}

		if s.Pagination.CurrentPage == 0 {
			s.Pagination.CurrentPage = 1
		}
	}

	if s.Pagination.PrePage == 0 {
		s.Pagination.PrePage = s.Resource.Config.PageCount
	}

	if s.Pagination.CurrentPage > 0 {
		s.Pagination.Pages = (s.Pagination.Total-1)/s.Pagination.PrePage + 1

		db = db.Limit(s.Pagination.PrePage).Offset((s.Pagination.CurrentPage - 1) * s.Pagination.PrePage)
	}

	context.SetDB(db)

	return context
}

func (s *Searcher) FindMany() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewSlice()
	err := s.Resource.CallFindMany(result, context)
	return result, err
}

func (s *Searcher) FindOne() (interface{}, error) {
	context := s.parseContext()
	result := s.Resource.NewStruct()
	err := s.Resource.CallFindOne(result, nil, context)
	return result, err
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/julienschmidt/httprouter"
)

var (
	apiServerBaseURL       = flag.String("api-server-base-url", "https://kubernetes.default", "Kubernetes API server base URL")
	apiServerUser          = flag.String("api-server-username", "admin", "Kubernetes API server username to use if no service acccount API token is present.")
	apiServerPassword      = flag.String("api-server-password", "admin123", "Kubernetes API server password to use if no service acccount API token is present.")
	awsKey                 = flag.String("aws-access-key", "", "Default decap AWS access key.  /etc/secrets/aws-key in the cluster overrides this.")
	awsSecret              = flag.String("aws-secret-key", "", "Default decap AWS access secret.  /etc/secrets/aws-secret in the cluster overrides this.")
	awsRegion              = flag.String("aws-region", "us-west-1", "Default decap AWS region.  /etc/secrets/aws-region in the cluster overrides this.")
	githubClientID         = flag.String("github-client-id", "", "Default Github ClientID for quering Github repos.  /etc/secrets/github-client-id in the cluster overrides this.")
	githubClientSecret     = flag.String("github-client-secret", "", "Default Github Client Secret for quering Github repos.  /etc/secrets/github-client-secret in the cluster overrides this.")
	buildScriptsRepo       = flag.String("build-scripts-repo", "https://github.com/ae6rt/decap-build-scripts.git", "Git repo where userland build scripts are held.")
	buildScriptsRepoBranch = flag.String("build-scripts-repo-branch", "master", "Branch or revision to use on git repo where userland build scripts are held.")
	versionFlag            = flag.Bool("version", false, "Print version info and exit.")

	Log *log.Logger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile)

	buildVersion string
	buildCommit  string
	buildDate    string
	buildGoSDK   string
)

func init() {
	flag.Parse()
	Log.Printf("Version: %s, Commit: %s, Date: %s, Go SDK: %s\n", buildVersion, buildCommit, buildDate, buildGoSDK)
	if *versionFlag {
		os.Exit(0)
	}

	*awsKey = kubeSecret("/etc/secrets/aws-key", *awsKey)
	*awsSecret = kubeSecret("/etc/secrets/aws-secret", *awsSecret)
	*awsRegion = kubeSecret("/etc/secrets/aws-region", *awsRegion)
	*githubClientID = kubeSecret("/etc/secrets/github-client-id", *githubClientID)
	*githubClientSecret = kubeSecret("/etc/secrets/github-client-secret", *githubClientSecret)
}

func main() {
	locker := NewDefaultLock([]string{"http://localhost:2379"})
	k8s := NewDefaultDecap(*apiServerBaseURL, *apiServerUser, *apiServerPassword, *awsKey, *awsSecret, *awsRegion, locker)
	awsStorageService := NewAWSStorageService(*awsKey, *awsSecret, *awsRegion)
	scmManagers := map[string]SCMClient{
		"github": NewGithubClient("https://api.github.com", *githubClientID, *githubClientSecret),
	}

	router := httprouter.New()
	router.ServeFiles("/decap/*filepath", http.Dir("./static"))
	router.GET("/api/v1/version", VersionHandler)
	router.GET("/api/v1/projects", ProjectsHandler)
	router.GET("/api/v1/projects/:team/:library/branches", ProjectBranchesHandler(scmManagers))
	router.GET("/api/v1/builds/:team/:library", BuildsHandler(awsStorageService))
	router.DELETE("/api/v1/builds/:id", StopBuildHandler(k8s))
	router.POST("/api/v1/builds/:team/:library", ExecuteBuildHandler(k8s))
	router.GET("/api/v1/logs/:id", LogHandler(awsStorageService))
	router.GET("/api/v1/teams", TeamsHandler)
	router.GET("/api/v1/artifacts/:id", ArtifactsHandler(awsStorageService))
	router.POST("/hooks/:repomanager", HooksHandler(*buildScriptsRepo, *buildScriptsRepoBranch, k8s))

	var err error
	projects, err = assembleProjects(*buildScriptsRepo, *buildScriptsRepoBranch)
	if err != nil {
		Log.Printf("Cannot clone build scripts repository: %v\n", err)
	}
	for _, v := range projects {
		Log.Printf("Project: %+v\n", v)
	}

	Log.Println("decap ready on port 9090...")
	http.ListenAndServe(":9090", router)
}

func kubeSecret(file string, defaultValue string) string {
	if v, err := ioutil.ReadFile(file); err != nil {
		Log.Printf("Secret %s not found in the filesystem.  Using default.\n", file)
		return defaultValue
	} else {
		Log.Printf("Successfully read secret %s from the filesystem\n", file)
		return string(v)
	}

}
<commit_msg>minor cleanup<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/julienschmidt/httprouter"
)

var (
	apiServerBaseURL       = flag.String("api-server-base-url", "https://kubernetes.default", "Kubernetes API server base URL")
	apiServerUser          = flag.String("api-server-username", "admin", "Kubernetes API server username to use if no service acccount API token is present.")
	apiServerPassword      = flag.String("api-server-password", "admin123", "Kubernetes API server password to use if no service acccount API token is present.")
	awsKey                 = flag.String("aws-access-key", "", "Default decap AWS access key.  /etc/secrets/aws-key in the cluster overrides this.")
	awsSecret              = flag.String("aws-secret-key", "", "Default decap AWS access secret.  /etc/secrets/aws-secret in the cluster overrides this.")
	awsRegion              = flag.String("aws-region", "us-west-1", "Default decap AWS region.  /etc/secrets/aws-region in the cluster overrides this.")
	githubClientID         = flag.String("github-client-id", "", "Default Github ClientID for quering Github repos.  /etc/secrets/github-client-id in the cluster overrides this.")
	githubClientSecret     = flag.String("github-client-secret", "", "Default Github Client Secret for quering Github repos.  /etc/secrets/github-client-secret in the cluster overrides this.")
	buildScriptsRepo       = flag.String("build-scripts-repo", "https://github.com/ae6rt/decap-build-scripts.git", "Git repo where userland build scripts are held.")
	buildScriptsRepoBranch = flag.String("build-scripts-repo-branch", "master", "Branch or revision to use on git repo where userland build scripts are held.")
	versionFlag            = flag.Bool("version", false, "Print version info and exit.")

	Log *log.Logger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile)

	buildVersion string
	buildCommit  string
	buildDate    string
	buildGoSDK   string
)

func init() {
	flag.Parse()
	Log.Printf("Version: %s, Commit: %s, Date: %s, Go SDK: %s\n", buildVersion, buildCommit, buildDate, buildGoSDK)
	if *versionFlag {
		os.Exit(0)
	}

	*awsKey = kubeSecret("/etc/secrets/aws-key", *awsKey)
	*awsSecret = kubeSecret("/etc/secrets/aws-secret", *awsSecret)
	*awsRegion = kubeSecret("/etc/secrets/aws-region", *awsRegion)
	*githubClientID = kubeSecret("/etc/secrets/github-client-id", *githubClientID)
	*githubClientSecret = kubeSecret("/etc/secrets/github-client-secret", *githubClientSecret)
}

func main() {
	locker := NewDefaultLock([]string{"http://localhost:2379"})
	k8s := NewDefaultDecap(*apiServerBaseURL, *apiServerUser, *apiServerPassword, *awsKey, *awsSecret, *awsRegion, locker)
	awsStorageService := NewAWSStorageService(*awsKey, *awsSecret, *awsRegion)
	scmManagers := map[string]SCMClient{
		"github": NewGithubClient("https://api.github.com", *githubClientID, *githubClientSecret),
	}

	router := httprouter.New()
	router.ServeFiles("/decap/*filepath", http.Dir("./static"))
	router.GET("/api/v1/version", VersionHandler)
	router.GET("/api/v1/projects", ProjectsHandler)
	router.GET("/api/v1/projects/:team/:library/branches", ProjectBranchesHandler(scmManagers))
	router.GET("/api/v1/builds/:team/:library", BuildsHandler(awsStorageService))
	router.DELETE("/api/v1/builds/:id", StopBuildHandler(k8s))
	router.POST("/api/v1/builds/:team/:library", ExecuteBuildHandler(k8s))
	router.GET("/api/v1/teams", TeamsHandler)
	router.GET("/api/v1/logs/:id", LogHandler(awsStorageService))
	router.GET("/api/v1/artifacts/:id", ArtifactsHandler(awsStorageService))
	router.POST("/hooks/:repomanager", HooksHandler(*buildScriptsRepo, *buildScriptsRepoBranch, k8s))

	var err error
	projects, err = assembleProjects(*buildScriptsRepo, *buildScriptsRepoBranch)
	if err != nil {
		Log.Printf("Cannot clone build scripts repository: %v\n", err)
	}
	for _, v := range projects {
		Log.Printf("Project: %+v\n", v)
	}

	Log.Println("decap ready on port 9090...")
	http.ListenAndServe(":9090", router)
}

func kubeSecret(file string, defaultValue string) string {
	if v, err := ioutil.ReadFile(file); err != nil {
		Log.Printf("Secret %s not found in the filesystem.  Using default.\n", file)
		return defaultValue
	} else {
		Log.Printf("Successfully read secret %s from the filesystem\n", file)
		return string(v)
	}

}
<|endoftext|>


<commit_before>package main

const (
	HTML_TMPL = `
<!doctype html>

<title>Slides</title>

{{data}}

`
	STYLESHEET = `
* { border: 0; margin: 0; padding: 0; box-sizing: border-box; }
body { background-color: #ffffea; }
#slides {
	display: flex;
	flex-flow: row nowrap;
}
p {
	display: none;
	flex: none;
	width: 100vw;
	height: 100vh;
	align-items: center;
	justify-content: center;
	font-size: 24pt;
	font-family: monospace;
	line-height: 1.7;
	text-align: left;
	padding: 1em;
}
.current {
	display: flex;
}
`
	JAVASCRIPT = `
var slideIndex = 0;
showSlides(slideIndex);

function plusSlides(n) {
  showSlides(slideIndex += n);
}

function currentSlide(n) {
  showSlides(slideIndex = n);
}

function showSlides(n) {
  var i;
  var slides = document.getElementsByTagName("p");
//  var dots = document.getElementsByClassName("dot");
  if (n > slides.length-1) {slideIndex = slides.length-1}
  if (n < 0) {slideIndex = 0}
  for (i = 0; i < slides.length; i++) {
      slides[i].classList.remove("current");
      slides[i].onclick = function (){
        plusSlides(1);
      };
  }
//  for (i = 0; i < dots.length; i++) {
//      dots[i].className = dots[i].className.replace(" active", "");
//  }
  console.log(slideIndex);
  slides[slideIndex].style.display = "flex";
//  dots[slideIndex].className += " active";
}

window.onkeydown = function (e) {
  var e=window.event || e;
  // left, up, right, down: 37 38 39 40
  switch (e.keyCode) {
    case 37:
    case 38:
      plusSlides(-1);
      break;
    case 39:
    case 40:
      plusSlides(1);
      break;
  }
};
`
)
<commit_msg>Add current class to current slide...<commit_after>package main

const (
	HTML_TMPL = `
<!doctype html>

<title>Slides</title>

{{data}}

`
	STYLESHEET = `
* { border: 0; margin: 0; padding: 0; box-sizing: border-box; }
body { background-color: #ffffea; }
#slides {
	display: flex;
	flex-flow: row nowrap;
}
p {
	display: none;
	flex: none;
	width: 100vw;
	height: 100vh;
	align-items: center;
	justify-content: center;
	font-size: 24pt;
	font-family: monospace;
	line-height: 1.7;
	text-align: left;
	padding: 1em;
}
.current {
	display: flex;
}
`
	JAVASCRIPT = `
var slideIndex = 0;
showSlides(slideIndex);

function plusSlides(n) {
  showSlides(slideIndex += n);
}

function currentSlide(n) {
  showSlides(slideIndex = n);
}

function showSlides(n) {
  var i;
  var slides = document.getElementsByTagName("p");
//  var dots = document.getElementsByClassName("dot");
  if (n > slides.length-1) {slideIndex = slides.length-1}
  if (n < 0) {slideIndex = 0}
  for (i = 0; i < slides.length; i++) {
      slides[i].classList.remove("current");
      slides[i].onclick = function (){
        plusSlides(1);
      };
  }
//  for (i = 0; i < dots.length; i++) {
//      dots[i].className = dots[i].className.replace(" active", "");
//  }
  slides[slideIndex].classList.add("current");

//  dots[slideIndex].className += " active";
}

window.onkeydown = function (e) {
  var e=window.event || e;
  // left, up, right, down: 37 38 39 40
  switch (e.keyCode) {
    case 37:
    case 38:
      plusSlides(-1);
      break;
    case 39:
    case 40:
      plusSlides(1);
      break;
  }
};
`
)
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "115.28.143.67:8081", "http service address")

var (
	MESSAGE_CHAT = "LHTTP/1.0 chat\r\ncontent-type:json\r\ncontent-length:10\r\n\r\njsonbody"
	MESSAGE_SUB  = "LHTTP/1.0 subpub\r\nsubscribe:channel_mike\r\n\r\n"
	MESSAGE_PUB  = "LHTTP/1.0 subpub\r\npublish:channel_mike\r\n\r\nhello mike, I am jack"
)

func sendSubscribe(c *websocket.Conn) {
	/*
		fmt.Println("input your channels split by blank:")
		in := make([]byte, 1024)
		os.Stdin.Read(in)
	*/
	msg := "LHTTP/1.0 suubpub\r\nsubscribe:cam_123" + "\r\n\r\n"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}
func sendUnsubscribe(c *websocket.Conn) {
	/*
		fmt.Println("input your channels split by blank:")
		in := make([]byte, 1024)
		os.Stdin.Read(in)
	*/
	msg := "LHTTP/1.0 suubpub\r\nunsubscribe:camera_123" + "\r\n\r\n"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}
func sendPublish(c *websocket.Conn) {
	/*
		fmt.Println("input your channels split by blank:")
		in := make([]byte, 1024)
		os.Stdin.Read(in)
	*/
	msg := "LHTTP/1.0 suubpub\r\npublish:camera_123" + "\r\n\r\nhello world"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}

func sendUpstream(c *websocket.Conn) {
	msg := "LHTTP/1.0 upstream\r\nupstream:GET http://115.28.143.67:8080/v1/user/10000/reports?AlgID=1\r\n\r\n"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
	msg = "LHTTP/1.0 upstream\r\nupstream:POST http://115.28.143.67:8080/v1/camera/10000/alarms\r\n\r\n{}"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}

func sendMultipart(c *websocket.Conn) {
	msg := "LHTTP/1.0 upload\r\nmultipart:0 14\r\n\r\nk1:v1\r\n\r\nbody1k2:v2\r\n\r\nbody2"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}

func main() {
	flag.Parse()
	log.SetFlags(0)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
	log.Printf("connecting to %s", u.String())

	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close()

	done := make(chan struct{})

	go func() {
		defer c.Close()
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)
		}
	}()

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case _ = <-ticker.C:
			//err := c.WriteMessage(websocket.TextMessage, []byte(MESSAGE_CHAT))
			fmt.Println("input your commands:multipart subscribe publish unsubscribe upstream")
			input := make([]byte, 1024)
			os.Stdin.Read(input)
			if strings.HasPrefix(string(input), "subscribe") {
				sendSubscribe(c)
			}
			if strings.HasPrefix(string(input), "unsubscribe") {
				sendUnsubscribe(c)
			}
			if strings.HasPrefix(string(input), "publish") {
				sendPublish(c)
			}
			if strings.HasPrefix(string(input), "upstream") {
				sendUpstream(c)
			}
			if strings.HasPrefix(string(input), "multipart") {
				sendMultipart(c)
			}
			//err := c.WriteMessage(websocket.TextMessage, []byte(MESSAGE_SUB))
			//err2 := c.WriteMessage(websocket.TextMessage, []byte(MESSAGE_PUB))
			//if err != nil || err2 != nil {
			//	log.Println("write:", err)
			//	return
			//}
		case <-interrupt:
			log.Println("interrupt")
			// To cleanly close a connection, a client should send a close
			// frame and wait for the server to close the connection.
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			c.Close()
			return
		}
	}
}
<commit_msg>fiexd sample error<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/url"
	"os"
	"os/signal"
	"strings"
	"time"

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "115.28.143.67:8081", "http service address")

var (
	MESSAGE_CHAT = "LHTTP/1.0 chat\r\ncontent-type:json\r\ncontent-length:10\r\n\r\njsonbody"
	MESSAGE_SUB  = "LHTTP/1.0 subpub\r\nsubscribe:channel_mike\r\n\r\n"
	MESSAGE_PUB  = "LHTTP/1.0 subpub\r\npublish:channel_mike\r\n\r\nhello mike, I am jack"
)

func sendSubscribe(c *websocket.Conn) {
	/*
		fmt.Println("input your channels split by blank:")
		in := make([]byte, 1024)
		os.Stdin.Read(in)
	*/
	msg := "LHTTP/1.0 subpub\r\nsubscribe:camera_123" + "\r\n\r\n"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}
func sendUnsubscribe(c *websocket.Conn) {
	/*
		fmt.Println("input your channels split by blank:")
		in := make([]byte, 1024)
		os.Stdin.Read(in)
	*/
	msg := "LHTTP/1.0 subpub\r\nunsubscribe:camera_123" + "\r\n\r\n"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}
func sendPublish(c *websocket.Conn) {
	/*
		fmt.Println("input your channels split by blank:")
		in := make([]byte, 1024)
		os.Stdin.Read(in)
	*/
	msg := "LHTTP/1.0 subpub\r\npublish:camera_123" + "\r\n\r\nhello world"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}

func sendUpstream(c *websocket.Conn) {
	msg := "LHTTP/1.0 upstream\r\nupstream:GET http://115.28.143.67:8080/v1/user/10000/reports?AlgID=1\r\n\r\n"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
	msg = "LHTTP/1.0 upstream\r\nupstream:POST http://115.28.143.67:8080/v1/camera/10000/alarms\r\n\r\n{}"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}

func sendMultipart(c *websocket.Conn) {
	msg := "LHTTP/1.0 upload\r\nmultipart:0 14\r\n\r\nk1:v1\r\n\r\nbody1k2:v2\r\n\r\nbody2"
	c.WriteMessage(websocket.TextMessage, []byte(msg))
}

func main() {
	flag.Parse()
	log.SetFlags(0)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
	log.Printf("connecting to %s", u.String())

	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close()

	done := make(chan struct{})

	go func() {
		defer c.Close()
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)
		}
	}()

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case _ = <-ticker.C:
			//err := c.WriteMessage(websocket.TextMessage, []byte(MESSAGE_CHAT))
			fmt.Println("input your commands:multipart subscribe publish unsubscribe upstream")
			input := make([]byte, 1024)
			os.Stdin.Read(input)
			if strings.HasPrefix(string(input), "subscribe") {
				sendSubscribe(c)
			}
			if strings.HasPrefix(string(input), "unsubscribe") {
				sendUnsubscribe(c)
			}
			if strings.HasPrefix(string(input), "publish") {
				sendPublish(c)
			}
			if strings.HasPrefix(string(input), "upstream") {
				sendUpstream(c)
			}
			if strings.HasPrefix(string(input), "multipart") {
				sendMultipart(c)
			}
			//err := c.WriteMessage(websocket.TextMessage, []byte(MESSAGE_SUB))
			//err2 := c.WriteMessage(websocket.TextMessage, []byte(MESSAGE_PUB))
			//if err != nil || err2 != nil {
			//	log.Println("write:", err)
			//	return
			//}
		case <-interrupt:
			log.Println("interrupt")
			// To cleanly close a connection, a client should send a close
			// frame and wait for the server to close the connection.
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			c.Close()
			return
		}
	}
}
<|endoftext|>


<commit_before>package fuse

import (
	"os"
	"syscall"
)

const (
	FUSE_ROOT_ID = 1

	FUSE_UNKNOWN_INO = 0xffffffff

	CUSE_UNRESTRICTED_IOCTL = (1 << 0)

	FUSE_LK_FLOCK = (1 << 0)

	FUSE_IOCTL_MAX_IOV = 256

	FUSE_POLL_SCHEDULE_NOTIFY = (1 << 0)

	CUSE_INIT_INFO_MAX = 4096

	S_IFDIR = syscall.S_IFDIR
	S_IFREG = syscall.S_IFREG
	S_IFLNK = syscall.S_IFLNK
	S_IFIFO = syscall.S_IFIFO

	// TODO - get this from a canonical place.
	PAGESIZE = 4096

	CUSE_INIT = 4096

	O_ANYWRITE = uint32(os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC)
)

const (
	_DEFAULT_BACKGROUND_TASKS = 12
)

type Status int32

const (
	OK      = Status(0)
	EACCES  = Status(syscall.EACCES)
	EBUSY   = Status(syscall.EBUSY)
	EINVAL  = Status(syscall.EINVAL)
	EIO     = Status(syscall.EIO)
	ENOENT  = Status(syscall.ENOENT)
	ENOSYS  = Status(syscall.ENOSYS)
	ENODATA = Status(syscall.ENODATA)
	ENOTDIR = Status(syscall.ENOTDIR)
	EPERM   = Status(syscall.EPERM)
	ERANGE  = Status(syscall.ERANGE)
	EXDEV   = Status(syscall.EXDEV)
)

type NotifyCode int

const (
	NOTIFY_POLL        = -1
	NOTIFY_INVAL_INODE = -2
	NOTIFY_INVAL_ENTRY = -3
	NOTIFY_CODE_MAX    = -4
)

type Attr struct {
	Ino       uint64
	Size      uint64
	Blocks    uint64
	Atime     uint64
	Mtime     uint64
	Ctime     uint64
	Atimensec uint32
	Mtimensec uint32
	Ctimensec uint32
	Mode      uint32
	Nlink     uint32
	Owner
	Rdev    uint32
	Blksize uint32
	Padding uint32
}

type Owner struct {
	Uid uint32
	Gid uint32
}

type Context struct {
	Owner
	Pid uint32
}

type Kstatfs struct {
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Bsize   uint32
	NameLen uint32
	Frsize  uint32
	Padding uint32
	Spare   [6]uint32
}

type FileLock struct {
	Start uint64
	End   uint64
	Typ   uint32
	Pid   uint32
}

type EntryOut struct {
	NodeId         uint64
	Generation     uint64
	EntryValid     uint64
	AttrValid      uint64
	EntryValidNsec uint32
	AttrValidNsec  uint32
	Attr
}

type ForgetIn struct {
	Nlookup uint64
}

const (
	// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
	FUSE_GETATTR_FH = (1 << 0)
)

type GetAttrIn struct {
	Flags uint32
	Dummy uint32
	Fh    uint64
}

type AttrOut struct {
	AttrValid     uint64
	AttrValidNsec uint32
	Dummy         uint32
	Attr
}

type MknodIn struct {
	Mode    uint32
	Rdev    uint32
	Umask   uint32
	Padding uint32
}

type MkdirIn struct {
	Mode  uint32
	Umask uint32
}

type RenameIn struct {
	Newdir uint64
}

type LinkIn struct {
	Oldnodeid uint64
}

const ( // SetAttrIn.Valid
	FATTR_MODE      = (1 << 0)
	FATTR_UID       = (1 << 1)
	FATTR_GID       = (1 << 2)
	FATTR_SIZE      = (1 << 3)
	FATTR_ATIME     = (1 << 4)
	FATTR_MTIME     = (1 << 5)
	FATTR_FH        = (1 << 6)
	FATTR_ATIME_NOW = (1 << 7)
	FATTR_MTIME_NOW = (1 << 8)
	FATTR_LOCKOWNER = (1 << 9)
)

type SetAttrIn struct {
	Valid     uint32
	Padding   uint32
	Fh        uint64
	Size      uint64
	LockOwner uint64
	Atime     uint64
	Mtime     uint64
	Unused2   uint64
	Atimensec uint32
	Mtimensec uint32
	Unused3   uint32
	Mode      uint32
	Unused4   uint32
	Owner
	Unused5 uint32
}

type OpenIn struct {
	Flags  uint32
	Unused uint32
}

type CreateIn struct {
	Flags   uint32
	Mode    uint32
	Umask   uint32
	Padding uint32
}

const (
	// OpenOut.Flags
	FOPEN_DIRECT_IO   = (1 << 0)
	FOPEN_KEEP_CACHE  = (1 << 1)
	FOPEN_NONSEEKABLE = (1 << 2)
)

type OpenOut struct {
	Fh        uint64
	OpenFlags uint32
	Padding   uint32
}

type CreateOut struct {
	EntryOut
	OpenOut
}

const RELEASE_FLUSH = (1 << 0)

type ReleaseIn struct {
	Fh           uint64
	Flags        uint32
	ReleaseFlags uint32
	LockOwner    uint64
}

type FlushIn struct {
	Fh        uint64
	Unused    uint32
	Padding   uint32
	LockOwner uint64
}

const (
	READ_LOCKOWNER = (1 << 1)
)

type ReadIn struct {
	Fh        uint64
	Offset    uint64
	Size      uint32
	ReadFlags uint32
	LockOwner uint64
	Flags     uint32
	Padding   uint32
}

const (
	WRITE_CACHE     = (1 << 0)
	WRITE_LOCKOWNER = (1 << 1)
)

type WriteIn struct {
	Fh         uint64
	Offset     uint64
	Size       uint32
	WriteFlags uint32
	LockOwner  uint64
	Flags      uint32
	Padding    uint32
}

type WriteOut struct {
	Size    uint32
	Padding uint32
}

type StatfsOut struct {
	Kstatfs
}

type FsyncIn struct {
	Fh         uint64
	FsyncFlags uint32
	Padding    uint32
}

type SetXAttrIn struct {
	Size  uint32
	Flags uint32
}

type GetXAttrIn struct {
	Size    uint32
	Padding uint32
}

type GetXAttrOut struct {
	Size    uint32
	Padding uint32
}

type LkIn struct {
	Fh      uint64
	Owner   uint64
	Lk      FileLock
	LkFlags uint32
	Padding uint32
}

type LkOut struct {
	Lk FileLock
}

// For AccessIn.Mask.
const (
	X_OK = 1
	W_OK = 2
	R_OK = 4
	F_OK = 0
)

type AccessIn struct {
	Mask    uint32
	Padding uint32
}

// To be set in InitIn/InitOut.Flags.
const (
	CAP_ASYNC_READ     = (1 << 0)
	CAP_POSIX_LOCKS    = (1 << 1)
	CAP_FILE_OPS       = (1 << 2)
	CAP_ATOMIC_O_TRUNC = (1 << 3)
	CAP_EXPORT_SUPPORT = (1 << 4)
	CAP_BIG_WRITES     = (1 << 5)
	CAP_DONT_MASK      = (1 << 6)
	CAP_SPLICE_WRITE   = (1 << 7)
	CAP_SPLICE_MOVE    = (1 << 8)
	CAP_SPLICE_READ    = (1 << 9)
)

type InitIn struct {
	Major        uint32
	Minor        uint32
	MaxReadAhead uint32
	Flags        uint32
}

type InitOut struct {
	Major               uint32
	Minor               uint32
	MaxReadAhead        uint32
	Flags               uint32
	MaxBackground       uint16
	CongestionThreshold uint16
	MaxWrite            uint32
}

type CuseInitIn struct {
	Major  uint32
	Minor  uint32
	Unused uint32
	Flags  uint32
}

type CuseInitOut struct {
	Major    uint32
	Minor    uint32
	Unused   uint32
	Flags    uint32
	MaxRead  uint32
	MaxWrite uint32
	DevMajor uint32
	DevMinor uint32
	Spare    [10]uint32
}

type InterruptIn struct {
	Unique uint64
}

type BmapIn struct {
	Block     uint64
	Blocksize uint32
	Padding   uint32
}

type BmapOut struct {
	Block uint64
}

const (
	FUSE_IOCTL_COMPAT       = (1 << 0)
	FUSE_IOCTL_UNRESTRICTED = (1 << 1)
	FUSE_IOCTL_RETRY        = (1 << 2)
)

type IoctlIn struct {
	Fh      uint64
	Flags   uint32
	Cmd     uint32
	Arg     uint64
	InSize  uint32
	OutSize uint32
}

type IoctlOut struct {
	Result  int32
	Flags   uint32
	InIovs  uint32
	OutIovs uint32
}

type PollIn struct {
	Fh      uint64
	Kh      uint64
	Flags   uint32
	Padding uint32
}

type PollOut struct {
	Revents uint32
	Padding uint32
}

type NotifyPollWakeupOut struct {
	Kh uint64
}

type InHeader struct {
	Length uint32
	opcode
	Unique uint64
	NodeId uint64
	Context
	Padding uint32
}

type OutHeader struct {
	Length uint32
	Status Status
	Unique uint64
}

type Dirent struct {
	Ino     uint64
	Off     uint64
	NameLen uint32
	Typ     uint32
}

type NotifyInvalInodeOut struct {
	Ino    uint64
	Off    int64
	Length int64
}

type NotifyInvalEntryOut struct {
	Parent  uint64
	NameLen uint32
	Padding uint32
}
<commit_msg>Add EBADF to error codes.<commit_after>package fuse

import (
	"os"
	"syscall"
)

const (
	FUSE_ROOT_ID = 1

	FUSE_UNKNOWN_INO = 0xffffffff

	CUSE_UNRESTRICTED_IOCTL = (1 << 0)

	FUSE_LK_FLOCK = (1 << 0)

	FUSE_IOCTL_MAX_IOV = 256

	FUSE_POLL_SCHEDULE_NOTIFY = (1 << 0)

	CUSE_INIT_INFO_MAX = 4096

	S_IFDIR = syscall.S_IFDIR
	S_IFREG = syscall.S_IFREG
	S_IFLNK = syscall.S_IFLNK
	S_IFIFO = syscall.S_IFIFO

	// TODO - get this from a canonical place.
	PAGESIZE = 4096

	CUSE_INIT = 4096

	O_ANYWRITE = uint32(os.O_WRONLY | os.O_RDWR | os.O_APPEND | os.O_CREATE | os.O_TRUNC)
)

const (
	_DEFAULT_BACKGROUND_TASKS = 12
)

type Status int32

const (
	OK      = Status(0)
	EACCES  = Status(syscall.EACCES)
	EBUSY   = Status(syscall.EBUSY)
	EINVAL  = Status(syscall.EINVAL)
	EIO     = Status(syscall.EIO)
	ENOENT  = Status(syscall.ENOENT)
	ENOSYS  = Status(syscall.ENOSYS)
	ENODATA = Status(syscall.ENODATA)
	ENOTDIR = Status(syscall.ENOTDIR)
	EPERM   = Status(syscall.EPERM)
	ERANGE  = Status(syscall.ERANGE)
	EXDEV   = Status(syscall.EXDEV)
	EBADF   = Status(syscall.EXDEV)
)

type NotifyCode int

const (
	NOTIFY_POLL        = -1
	NOTIFY_INVAL_INODE = -2
	NOTIFY_INVAL_ENTRY = -3
	NOTIFY_CODE_MAX    = -4
)

type Attr struct {
	Ino       uint64
	Size      uint64
	Blocks    uint64
	Atime     uint64
	Mtime     uint64
	Ctime     uint64
	Atimensec uint32
	Mtimensec uint32
	Ctimensec uint32
	Mode      uint32
	Nlink     uint32
	Owner
	Rdev    uint32
	Blksize uint32
	Padding uint32
}

type Owner struct {
	Uid uint32
	Gid uint32
}

type Context struct {
	Owner
	Pid uint32
}

type Kstatfs struct {
	Blocks  uint64
	Bfree   uint64
	Bavail  uint64
	Files   uint64
	Ffree   uint64
	Bsize   uint32
	NameLen uint32
	Frsize  uint32
	Padding uint32
	Spare   [6]uint32
}

type FileLock struct {
	Start uint64
	End   uint64
	Typ   uint32
	Pid   uint32
}

type EntryOut struct {
	NodeId         uint64
	Generation     uint64
	EntryValid     uint64
	AttrValid      uint64
	EntryValidNsec uint32
	AttrValidNsec  uint32
	Attr
}

type ForgetIn struct {
	Nlookup uint64
}

const (
	// Mask for GetAttrIn.Flags. If set, GetAttrIn has a file handle set.
	FUSE_GETATTR_FH = (1 << 0)
)

type GetAttrIn struct {
	Flags uint32
	Dummy uint32
	Fh    uint64
}

type AttrOut struct {
	AttrValid     uint64
	AttrValidNsec uint32
	Dummy         uint32
	Attr
}

type MknodIn struct {
	Mode    uint32
	Rdev    uint32
	Umask   uint32
	Padding uint32
}

type MkdirIn struct {
	Mode  uint32
	Umask uint32
}

type RenameIn struct {
	Newdir uint64
}

type LinkIn struct {
	Oldnodeid uint64
}

const ( // SetAttrIn.Valid
	FATTR_MODE      = (1 << 0)
	FATTR_UID       = (1 << 1)
	FATTR_GID       = (1 << 2)
	FATTR_SIZE      = (1 << 3)
	FATTR_ATIME     = (1 << 4)
	FATTR_MTIME     = (1 << 5)
	FATTR_FH        = (1 << 6)
	FATTR_ATIME_NOW = (1 << 7)
	FATTR_MTIME_NOW = (1 << 8)
	FATTR_LOCKOWNER = (1 << 9)
)

type SetAttrIn struct {
	Valid     uint32
	Padding   uint32
	Fh        uint64
	Size      uint64
	LockOwner uint64
	Atime     uint64
	Mtime     uint64
	Unused2   uint64
	Atimensec uint32
	Mtimensec uint32
	Unused3   uint32
	Mode      uint32
	Unused4   uint32
	Owner
	Unused5 uint32
}

type OpenIn struct {
	Flags  uint32
	Unused uint32
}

type CreateIn struct {
	Flags   uint32
	Mode    uint32
	Umask   uint32
	Padding uint32
}

const (
	// OpenOut.Flags
	FOPEN_DIRECT_IO   = (1 << 0)
	FOPEN_KEEP_CACHE  = (1 << 1)
	FOPEN_NONSEEKABLE = (1 << 2)
)

type OpenOut struct {
	Fh        uint64
	OpenFlags uint32
	Padding   uint32
}

type CreateOut struct {
	EntryOut
	OpenOut
}

const RELEASE_FLUSH = (1 << 0)

type ReleaseIn struct {
	Fh           uint64
	Flags        uint32
	ReleaseFlags uint32
	LockOwner    uint64
}

type FlushIn struct {
	Fh        uint64
	Unused    uint32
	Padding   uint32
	LockOwner uint64
}

const (
	READ_LOCKOWNER = (1 << 1)
)

type ReadIn struct {
	Fh        uint64
	Offset    uint64
	Size      uint32
	ReadFlags uint32
	LockOwner uint64
	Flags     uint32
	Padding   uint32
}

const (
	WRITE_CACHE     = (1 << 0)
	WRITE_LOCKOWNER = (1 << 1)
)

type WriteIn struct {
	Fh         uint64
	Offset     uint64
	Size       uint32
	WriteFlags uint32
	LockOwner  uint64
	Flags      uint32
	Padding    uint32
}

type WriteOut struct {
	Size    uint32
	Padding uint32
}

type StatfsOut struct {
	Kstatfs
}

type FsyncIn struct {
	Fh         uint64
	FsyncFlags uint32
	Padding    uint32
}

type SetXAttrIn struct {
	Size  uint32
	Flags uint32
}

type GetXAttrIn struct {
	Size    uint32
	Padding uint32
}

type GetXAttrOut struct {
	Size    uint32
	Padding uint32
}

type LkIn struct {
	Fh      uint64
	Owner   uint64
	Lk      FileLock
	LkFlags uint32
	Padding uint32
}

type LkOut struct {
	Lk FileLock
}

// For AccessIn.Mask.
const (
	X_OK = 1
	W_OK = 2
	R_OK = 4
	F_OK = 0
)

type AccessIn struct {
	Mask    uint32
	Padding uint32
}

// To be set in InitIn/InitOut.Flags.
const (
	CAP_ASYNC_READ     = (1 << 0)
	CAP_POSIX_LOCKS    = (1 << 1)
	CAP_FILE_OPS       = (1 << 2)
	CAP_ATOMIC_O_TRUNC = (1 << 3)
	CAP_EXPORT_SUPPORT = (1 << 4)
	CAP_BIG_WRITES     = (1 << 5)
	CAP_DONT_MASK      = (1 << 6)
	CAP_SPLICE_WRITE   = (1 << 7)
	CAP_SPLICE_MOVE    = (1 << 8)
	CAP_SPLICE_READ    = (1 << 9)
)

type InitIn struct {
	Major        uint32
	Minor        uint32
	MaxReadAhead uint32
	Flags        uint32
}

type InitOut struct {
	Major               uint32
	Minor               uint32
	MaxReadAhead        uint32
	Flags               uint32
	MaxBackground       uint16
	CongestionThreshold uint16
	MaxWrite            uint32
}

type CuseInitIn struct {
	Major  uint32
	Minor  uint32
	Unused uint32
	Flags  uint32
}

type CuseInitOut struct {
	Major    uint32
	Minor    uint32
	Unused   uint32
	Flags    uint32
	MaxRead  uint32
	MaxWrite uint32
	DevMajor uint32
	DevMinor uint32
	Spare    [10]uint32
}

type InterruptIn struct {
	Unique uint64
}

type BmapIn struct {
	Block     uint64
	Blocksize uint32
	Padding   uint32
}

type BmapOut struct {
	Block uint64
}

const (
	FUSE_IOCTL_COMPAT       = (1 << 0)
	FUSE_IOCTL_UNRESTRICTED = (1 << 1)
	FUSE_IOCTL_RETRY        = (1 << 2)
)

type IoctlIn struct {
	Fh      uint64
	Flags   uint32
	Cmd     uint32
	Arg     uint64
	InSize  uint32
	OutSize uint32
}

type IoctlOut struct {
	Result  int32
	Flags   uint32
	InIovs  uint32
	OutIovs uint32
}

type PollIn struct {
	Fh      uint64
	Kh      uint64
	Flags   uint32
	Padding uint32
}

type PollOut struct {
	Revents uint32
	Padding uint32
}

type NotifyPollWakeupOut struct {
	Kh uint64
}

type InHeader struct {
	Length uint32
	opcode
	Unique uint64
	NodeId uint64
	Context
	Padding uint32
}

type OutHeader struct {
	Length uint32
	Status Status
	Unique uint64
}

type Dirent struct {
	Ino     uint64
	Off     uint64
	NameLen uint32
	Typ     uint32
}

type NotifyInvalInodeOut struct {
	Ino    uint64
	Off    int64
	Length int64
}

type NotifyInvalEntryOut struct {
	Parent  uint64
	NameLen uint32
	Padding uint32
}
<|endoftext|>


<commit_before>package http

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"mime/multipart"
)

// Request represents an HTTP request received by a server or to be sent by a client.
type Request struct {
	*http.Request
}

// CreateRequest a new Request from a classic Request.
func CreateRequest(r *http.Request) *Request {
	return &Request{r}
}

// NewRequest returns a new Request given a method, URL, and optional body.
func NewRequest(method, url string, body io.Reader) (*Request, error) {
	r, err := http.NewRequest(method, url, body)
	return CreateRequest(r), err
}

func (req *Request) debug(str string, values ...interface{}) {
	log.Printf("[%v]: %v\n", req.Request.RequestURI, fmt.Sprintf(str, values...))
}

// GetFileReader get the multiform body and returns it as a Reader.
func (req *Request) GetFileReader(key string) (io.Reader, error) {
	if debugMode {
		req.debug("Trying to get file from the key \"%v\"", key)
	}
	fileMultiPart, _, err := req.FormFile(key)
	if err != nil {
		return nil, err
	}
	return fileMultiPart, nil
}

// ForEachFileReader calls the function f with every io.Reader contained in the provided form key.
// After every call to f, the file is close.
func (req *Request) ForEachFileReader(key string, f func(int, io.Reader) error) error {
	if err := req.ParseMultipartForm(32 << 2); err != nil {
		return err
	}
	if req.MultipartForm != nil && req.MultipartForm.File[key] != nil {
		fileHeaders := req.MultipartForm.File[key]
		for index, fileheader := range fileHeaders {
			file, err := fileheader.Open()
			if err != nil {
				return err
			}
			if err := f(index, file); err != nil {
				return err
			}
			if err := file.Close(); err != nil {
				return err
			}
		}
	}
	return nil
}

// ForEachFileHeader calls the function f with every multipart.FileHeader contained in the provided form key.
// Opening and closing the file is the responsibility of the user.
func (req *Request) ForEachFileHeader(key string, f func(int, multipart.FileHeader) error) error {
	if err := req.ParseMultipartForm(32 << 2); err != nil {
		return err
	}
	if req.MultipartForm != nil && req.MultipartForm.File[key] != nil {
		fileHeaders := req.MultipartForm.File[key]
		for index, fileheader := range fileHeaders {
			if err := f(index, fileheader); err != nil {
				return err
			}
		}
	}
	return nil
}

// UploadAndGetFile upload the file, create a new file to the given path (for example "/tmp/").
func (req *Request) UploadAndGetFile(key, pathFile string) (*os.File, error) {
	if debugMode {
		req.debug("Trying to get file from the key \"%v\"", key)
	}
	fileMultiPart, fileHeader, err := req.FormFile(key)
	if err != nil {
		return nil, err
	}
	file, err := os.Create(fmt.Sprintf("%v%v", pathFile, fileHeader.Filename))
	if err != nil {
		return nil, err
	}
	if _, err := io.Copy(file, fileMultiPart); err != nil {
		return nil, err
	}
	return file, nil
}

// UploadAndGetAbsolutePath is the same as UploadAndGetFile but returns the absolute path of the file.
func (req *Request) UploadAndGetAbsolutePath(key, pathFile string) (string, error) {
	file, err := req.UploadAndGetFile(key, pathFile)
	if err != nil {
		return "", err
	}
	defer file.Close()
	absName, err := filepath.Abs(file.Name())
	if err != nil {
		return "", err
	}
	if debugMode {
		req.debug("Got file \"%v\"", absName)
	}
	return absName, nil
}

// UploadFileName uploads the file from the request and save it in the given fileName.
func (req *Request) UploadFileName(key, fileName string) (*os.File, error) {
	if debugMode {
		req.debug("Trying to get file from the key \"%v\"", key)
	}
	fileMultiPart, _, err := req.FormFile(key)
	if err != nil {
		return nil, err
	}
	file, err := os.Create(fileName)
	if err != nil {
		return nil, err
	}
	if _, err := io.Copy(file, fileMultiPart); err != nil {
		return nil, err
	}
	return file, nil
}

func (req *Request) getBody() ([]byte, error) {
	defer req.Body.Close()
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return nil, err
	}
	if debugMode {
		req.debug("Body: \"%v\"", string(body))
	}
	return body, err
}

// GetAndReturnJSONObject returns the JSON object from the body.
func (req *Request) GetAndReturnJSONObject(object interface{}) (interface{}, error) {
	body, err := req.getBody()
	if err != nil {
		return nil, err
	}
	return object, json.Unmarshal(body, &object)
}

// GetJSONObject just call json.Unmarshal to the body and put it in the object.
func (req *Request) GetJSONObject(object interface{}) error {
	body, err := req.getBody()
	if err != nil {
		return err
	}
	return json.Unmarshal(body, &object)
}

// URLParam returns an URL param.
// It is the same as calling request.Url.Query().Get(":key").
func (req *Request) URLParam(key string) string {
	return req.Request.URL.Query().Get(":" + key)
}
<commit_msg>Removed useless methods on Requests<commit_after>package http

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"mime/multipart"
	"net/http"
)

// Request represents an HTTP request received by a server or to be sent by a client.
type Request struct {
	*http.Request
}

// CreateRequest a new Request from a classic Request.
func CreateRequest(r *http.Request) *Request {
	return &Request{r}
}

// NewRequest returns a new Request given a method, URL, and optional body.
func NewRequest(method, url string, body io.Reader) (*Request, error) {
	r, err := http.NewRequest(method, url, body)
	return CreateRequest(r), err
}

func (req *Request) debug(str string, values ...interface{}) {
	log.Printf("[%v]: %v\n", req.Request.RequestURI, fmt.Sprintf(str, values...))
}

// GetFileReader get the multiform body and returns it as a Reader.
func (req *Request) GetFileReader(key string) (io.Reader, error) {
	if debugMode {
		req.debug("Trying to get file from the key \"%v\"", key)
	}
	fileMultiPart, _, err := req.FormFile(key)
	if err != nil {
		return nil, err
	}
	return fileMultiPart, nil
}

// ForEachFileReader calls the function f with every io.Reader contained in the provided form key.
// After every call to f, the file is close.
func (req *Request) ForEachFileReader(key string, f func(int, io.Reader) error) error {
	if err := req.ParseMultipartForm(32 << 2); err != nil {
		return err
	}
	if req.MultipartForm != nil && req.MultipartForm.File[key] != nil {
		fileHeaders := req.MultipartForm.File[key]
		for index, fileheader := range fileHeaders {
			file, err := fileheader.Open()
			if err != nil {
				return err
			}
			if err := f(index, file); err != nil {
				return err
			}
			if err := file.Close(); err != nil {
				return err
			}
		}
	}
	return nil
}

// ForEachFileHeader calls the function f with every multipart.FileHeader contained in the provided form key.
// Opening and closing the file is the responsibility of the user.
func (req *Request) ForEachFileHeader(key string, f func(int, *multipart.FileHeader) error) error {
	if err := req.ParseMultipartForm(32 << 2); err != nil {
		return err
	}
	if req.MultipartForm != nil && req.MultipartForm.File[key] != nil {
		fileHeaders := req.MultipartForm.File[key]
		for index, fileheader := range fileHeaders {
			if err := f(index, fileheader); err != nil {
				return err
			}
		}
	}
	return nil
}

func (req *Request) getBody() ([]byte, error) {
	defer req.Body.Close()
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return nil, err
	}
	if debugMode {
		req.debug("Body: \"%v\"", string(body))
	}
	return body, err
}

// GetAndReturnJSONObject returns the JSON object from the body.
func (req *Request) GetAndReturnJSONObject(object interface{}) (interface{}, error) {
	body, err := req.getBody()
	if err != nil {
		return nil, err
	}
	return object, json.Unmarshal(body, &object)
}

// GetJSONObject just call json.Unmarshal to the body and put it in the object.
func (req *Request) GetJSONObject(object interface{}) error {
	body, err := req.getBody()
	if err != nil {
		return err
	}
	return json.Unmarshal(body, &object)
}

// URLParam returns an URL param.
// It is the same as calling request.Url.Query().Get(":key").
func (req *Request) URLParam(key string) string {
	return req.Request.URL.Query().Get(":" + key)
}
<|endoftext|>


<commit_before>package httpzip

import (
	"compress/flate"
	"compress/gzip"
	"io"
	"net/http"
)

// NewRequestHandler return handler, which transparently decodes http requests
// which are using either gzip or deflate algorithm. Request should have
// Content-Encoding header set to the appropriate value. If content encoding is
// recognised, request body will be transparently uncompressed in the passed
// handler h and Content-Encoding header removed. No decoding errors are
// handled by the wrapper and they're all available through the regular request
// body read call.
//
// If content encoding is outside of the supported types, the request will be
// passed unaltered.
func NewRequestHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// New reader handling uncompression
		var nr io.ReadCloser

		switch r.Header.Get("Content-Encoding") {
		case "gzip":
			nr = newErrReader(gzip.NewReader(r.Body))
		case "deflate":
			nr = flate.NewReader(r.Body)
		}

		if nr != nil {
			r.Body = nr
			r.Header.Del("Content-Encoding")
		}

		// Pass to the wrapped handler
		h.ServeHTTP(w, r)
	})
}

// errReader reports error (if any) with the first call to Read
type errReader struct {
	io.ReadCloser
	err error
}

func newErrReader(r io.ReadCloser, err error) *errReader {
	return &errReader{r, err}
}

func (r *errReader) Read(p []byte) (int, error) {
	if r.err != nil {
		return 0, r.err
	}
	return r.ReadCloser.Read(p)
}
<commit_msg>Fix panic on calling Close after gzip header error<commit_after>package httpzip

import (
	"compress/flate"
	"compress/gzip"
	"io"
	"io/ioutil"
	"net/http"
)

// NewRequestHandler return handler, which transparently decodes http requests
// which are using either gzip or deflate algorithm. Request should have
// Content-Encoding header set to the appropriate value. If content encoding is
// recognised, request body will be transparently uncompressed in the passed
// handler h and Content-Encoding header removed. No decoding errors are
// handled by the wrapper and they're all available through the regular request
// body read call.
//
// If content encoding is outside of the supported types, the request will be
// passed unaltered.
func NewRequestHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// New reader handling uncompression
		var nr io.ReadCloser

		switch r.Header.Get("Content-Encoding") {
		case "gzip":
			if r, err := gzip.NewReader(r.Body); err == nil {
				nr = r
			} else {
				nr = ioutil.NopCloser(&errReader{err})
			}
		case "deflate":
			nr = flate.NewReader(r.Body)
		}

		if nr != nil {
			r.Body = nr
			r.Header.Del("Content-Encoding")
		}

		// Pass to the wrapped handler
		h.ServeHTTP(w, r)
	})
}

// errReader reports error on every Read
type errReader struct {
	err error
}

func (r *errReader) Read(p []byte) (int, error) {
	return 0, r.err
}
<|endoftext|>


<commit_before>package parser

import (
	"fmt"
	"os"
	"path"
	"strings"
)

func normalizePath(path string) string {
	return strings.Replace(path, "\\", "/", -1)
}

func getPkgPath(fname string) (string, error) {
	if !path.IsAbs(fname) {
		pwd, err := os.Getwd()
		if err != nil {
			return "", err
		}
		fname = path.Join(pwd, fname)
	}

	fname = normalizePath(fname)

	for _, p := range strings.Split(os.Getenv("GOPATH"), ";") {
		prefix := path.Join(normalizePath(p), "src") + "/"
		if rel := strings.TrimPrefix(fname, prefix); rel != fname {
			return path.Dir(rel), nil
		}
	}

	return "", fmt.Errorf("file '%v' is not in GOPATH", fname)
}
<commit_msg>fix parser for windows<commit_after>package parser

import (
	"fmt"
	"os"
	"path"
	"strings"
)

func normalizePath(path string) string {
	return strings.Replace(path, "\\", "/", -1)
}

func getPkgPath(fname string, isDir bool) (string, error) {
	if !path.IsAbs(fname) {
		pwd, err := os.Getwd()
		if err != nil {
			return "", err
		}
		fname = path.Join(pwd, fname)
	}

	fname = normalizePath(fname)

	for _, p := range strings.Split(os.Getenv("GOPATH"), ";") {
		prefix := path.Join(normalizePath(p), "src") + "/"
		if rel := strings.TrimPrefix(fname, prefix); rel != fname {
			if !isDir {
				return path.Dir(rel), nil
			} else {
				return path.Clean(rel), nil
			}
		}
	}

	return "", fmt.Errorf("file '%v' is not in GOPATH", fname)
}
<|endoftext|>


<commit_before>package job

import (
	"testing"

	"github.com/coreos/fleet/unit"
)

func newUnitIgnoreErrors(str string) *unit.Unit {
	u, _ := unit.NewUnit(str)
	return u
}

func TestNewJob(t *testing.T) {
	j1 := NewJob("pong.service", *newUnitIgnoreErrors("Echo"))

	if j1.Name != "pong.service" {
		t.Error("job.Job.Name != 'pong.service'")
	}
}

func TestJobWithPeers(t *testing.T) {
	j := NewJob("echo.service", *newUnitIgnoreErrors(``))
	peers := j.Peers()

	if len(peers) != 0 {
		t.Fatalf("Unexpected number of peers %d, expected 0", len(peers))
	}
}

func TestJobWithoutPeers(t *testing.T) {
	contents := `[X-Fleet]
X-ConditionMachineOf="foo.service" "bar.service"
`
	j := NewJob("echo.service", *newUnitIgnoreErrors(contents))
	peers := j.Peers()

	if len(peers) != 2 {
		t.Fatalf("Unexpected number of peers %d, expected 2", len(peers))
	}

	if peers[0] != "foo.service" {
		t.Errorf("Expected first peer to be foo.service, got %s", peers[0])
	}

	if peers[1] != "bar.service" {
		t.Errorf("Expected second peer to be bar.service, got %s", peers[1])
	}
}

func TestJobConflicts(t *testing.T) {
	contents := `[Unit]
Description=Testing

[X-Fleet]
X-Conflicts=*bar*
`
	j := NewJob("echo.service", *newUnitIgnoreErrors(contents))
	conflicts := j.Conflicts()

	if len(conflicts) != 1 {
		t.Errorf("Expected 1 conflict, received %v", conflicts)
	}

	if conflicts[0] != "*bar*" {
		t.Errorf("Expected first conflict to be '*bar*', received %s", conflicts[1])
	}
}

func TestJobConflictsNotProvided(t *testing.T) {
	j := NewJob("echo.socket", *newUnitIgnoreErrors(""))
	conflicts := j.Conflicts()

	if len(conflicts) > 0 {
		t.Fatalf("Expected no conflicts, received %v", conflicts)
	}
}

func TestJobResourceReservations(t *testing.T) {
	contents := `[Unit]
Description=Testing

[X-Fleet]
X-MemoryReservation=1024
X-CoresReservation=150
X-DiskReservation=524288
`
	j := NewJob("echo.service", *newUnitIgnoreErrors(contents))
	res := j.Resources()

	if res.Cores != 150 {
		t.Errorf("Expected 150 cores reservation, received %d", res.Cores)
	}

	if res.Memory != 1024 {
		t.Errorf("Expected 1024 memory reservation, received %d", res.Memory)
	}

	if res.Disk != 524288 {
		t.Errorf("Expected 524288 disk reservation, received %d", res.Disk)
	}
}

func TestParseRequirements(t *testing.T) {
	contents := `
[X-Fleet]
X-Foo=Bar
Ping=Pong
X-Key=Value
`
	j := NewJob("foo.service", *newUnitIgnoreErrors(contents))
	reqs := j.Requirements()
	if len(reqs) != 2 {
		t.Fatalf("Incorrect number of requirements; got %d, expected 2", len(reqs))
	}

	if len(reqs["Foo"]) != 1 || reqs["Foo"][0] != "Bar" {
		t.Fatalf("Incorrect value %q of requirement 'Foo'", reqs["Foo"])
	}

	if len(reqs["Key"]) != 1 || reqs["Key"][0] != "Value" {
		t.Fatalf("Incorrect value %q of requirement 'Key'", reqs["Key"])
	}
}

func TestParseRequirementsMultipleValuesForKeyStack(t *testing.T) {
	contents := `
[X-Fleet]
X-Foo=Bar
X-Foo=Baz
X-Ping=Pong
X-Ping=Pang
`
	j := NewJob("foo.service", *newUnitIgnoreErrors(contents))
	reqs := j.Requirements()
	if len(reqs) != 2 {
		t.Fatalf("Incorrect number of requirements; got %d, expected 2: %v", len(reqs), reqs)
	}

	if len(reqs["Foo"]) != 2 || reqs["Foo"][0] != "Bar" || reqs["Foo"][1] != "Baz" {
		t.Fatalf("Incorrect value %v of requirement 'Foo'", reqs["Foo"])
	}

	if len(reqs["Ping"]) != 2 || reqs["Ping"][0] != "Pong" || reqs["Ping"][1] != "Pang" {
		t.Fatalf("Incorrect value %v of requirement 'Ping'", reqs["Ping"])
	}
}

func TestParseRequirementsInstanceUnit(t *testing.T) {
	contents := `
[X-Fleet]
X-Foo=%n
X-Bar=%N
X-Baz=%p
X-Qux=%i
X-Zzz=something
`
	// Ensure the correct values are replaced for a non-instance unit
	j := NewJob("test.service", *newUnitIgnoreErrors(contents))
	reqs := j.Requirements()
	for field, want := range map[string]string{
		"Foo": "test.service",
		"Bar": "test",
		"Baz": "test",
		"Qux": "",
		"Zzz": "something",
	} {
		got := reqs[field]
		if len(got) != 1 || got[0] != want {
			t.Errorf("Requirement %q unexpectedly altered for non-instance unit: want %q, got %q", field, want, got)
		}
	}

	// Now ensure that they are substituted appropriately for an instance unit
	j = NewJob("ssh@2.service", *newUnitIgnoreErrors(contents))
	reqs = j.Requirements()
	for field, want := range map[string]string{
		"Foo": "ssh@2.service",
		"Bar": "ssh@2",
		"Baz": "ssh",
		"Qux": "2",
		"Zzz": "something",
	} {
		got := reqs[field]
		if len(got) != 1 || got[0] != want {
			t.Errorf("Bad instance unit requirement substitution for %q: want %q, got %q", field, want, got)
		}
	}

}

func TestParseRequirementsMissingSection(t *testing.T) {
	contents := `
[Unit]
Description=Timmy
`
	j := NewJob("foo.service", *newUnitIgnoreErrors(contents))
	reqs := j.Requirements()
	if len(reqs) != 0 {
		t.Fatalf("Incorrect number of requirements; got %d, expected 0", len(reqs))
	}
}

func TestJobConditionMachineID(t *testing.T) {
	tests := []struct {
		unit string
		outS string
		outB bool
	}{
		// Simplest case
		{
			`[X-Fleet]
X-ConditionMachineID=123
`,
			"123",
			true,
		},

		// First value wins
		// TODO(bcwaldon): maybe the last one should win?
		{
			`[X-Fleet]
X-ConditionMachineID="123" "456"
`,
			"123",
			true,
		},

		// No value provided
		{
			`[X-Fleet]`,
			"",
			false,
		},

		// Ensure we fall back to the legacy boot ID option
		{
			`[X-Fleet]
X-ConditionMachineBootID=123
`,
			"123",
			true,
		},

		// Fall back to legacy option only if non-boot ID is absent
		{
			`[X-Fleet]
X-ConditionMachineBootID=123
X-ConditionMachineID=456
`,
			"456",
			true,
		},
	}

	for _, tt := range tests {
		j := NewJob("echo.service", *newUnitIgnoreErrors(tt.unit))
		outS, outB := j.RequiredTarget()

		if outS != tt.outS {
			t.Errorf("Expected target requirement %s, got %s", tt.outS, outS)
		}

		if outB != tt.outB {
			t.Errorf("Expected target requirement ok-val %t, got %t", tt.outB, outB)
		}
	}
}

func TestOneshotJob(t *testing.T) {
	ej := NewJob("foo.service", *newUnitIgnoreErrors(""))
	if ej.IsOneshot() {
		t.Error("IsOneshot() on job without Service section returned true unexpectedly")
	}

	j := NewJob("bar.service", *newUnitIgnoreErrors(`
[Service]
ExecStart=/bin/false`))
	if j.IsOneshot() {
		t.Error("IsOneshot() on Service job with no Type returned true unexpectedly")
	}

	sj := NewJob("bar.service", *newUnitIgnoreErrors(`
[Service]
Type=simple`))
	if sj.IsOneshot() {
		t.Error("IsOneshot() on simple job returned true unexpectedly")
	}

	bj := NewJob("bar.service", *newUnitIgnoreErrors(`
[Service]
Type=oneshot`))
	if !bj.IsOneshot() {
		t.Error("IsOneshot() on oneshot job returned false unexpectedly")
	}
}

func TestInstanceUnitPrintf(t *testing.T) {
	u := unit.NewUnitNameInfo("foo@bar.waldo")
	if u == nil {
		t.Fatal("NewNamedUnit returned nil - aborting")
	}
	for _, tt := range []struct {
		in   string
		want string
	}{
		{"%n", "foo@bar.waldo"},
		{"%N", "foo@bar"},
		{"%p", "foo"},
		{"%i", "bar"},
	} {
		got := unitPrintf(tt.in, *u)
		if got != tt.want {
			t.Errorf("Replacement of %q failed: got %q, want %q", tt.in, got, tt.want)
		}
	}
}
<commit_msg>chore(job): centralize NewUnit invocations in job_test<commit_after>package job

import (
	"testing"

	"github.com/coreos/fleet/unit"
)

func newUnit(t *testing.T, str string) *unit.Unit {
	u, err := unit.NewUnit(str)
	if err != nil {
		t.Fatalf("Unexpected error creating unit from %q: %v", str, err)
	}
	return u
}

func TestNewJob(t *testing.T) {
	j1 := NewJob("pong.service", *newUnit(t, "Echo"))

	if j1.Name != "pong.service" {
		t.Error("job.Job.Name != 'pong.service'")
	}
}

func TestJobWithPeers(t *testing.T) {
	j := NewJob("echo.service", *newUnit(t, ``))
	peers := j.Peers()

	if len(peers) != 0 {
		t.Fatalf("Unexpected number of peers %d, expected 0", len(peers))
	}
}

func TestJobWithoutPeers(t *testing.T) {
	contents := `[X-Fleet]
X-ConditionMachineOf="foo.service" "bar.service"
`
	j := NewJob("echo.service", *newUnit(t, contents))
	peers := j.Peers()

	if len(peers) != 2 {
		t.Fatalf("Unexpected number of peers %d, expected 2", len(peers))
	}

	if peers[0] != "foo.service" {
		t.Errorf("Expected first peer to be foo.service, got %s", peers[0])
	}

	if peers[1] != "bar.service" {
		t.Errorf("Expected second peer to be bar.service, got %s", peers[1])
	}
}

func TestJobConflicts(t *testing.T) {
	contents := `[Unit]
Description=Testing

[X-Fleet]
X-Conflicts=*bar*
`
	j := NewJob("echo.service", *newUnit(t, contents))
	conflicts := j.Conflicts()

	if len(conflicts) != 1 {
		t.Errorf("Expected 1 conflict, received %v", conflicts)
	}

	if conflicts[0] != "*bar*" {
		t.Errorf("Expected first conflict to be '*bar*', received %s", conflicts[1])
	}
}

func TestJobConflictsNotProvided(t *testing.T) {
	j := NewJob("echo.socket", *newUnit(t, ""))
	conflicts := j.Conflicts()

	if len(conflicts) > 0 {
		t.Fatalf("Expected no conflicts, received %v", conflicts)
	}
}

func TestJobResourceReservations(t *testing.T) {
	contents := `[Unit]
Description=Testing

[X-Fleet]
X-MemoryReservation=1024
X-CoresReservation=150
X-DiskReservation=524288
`
	j := NewJob("echo.service", *newUnit(t, contents))
	res := j.Resources()

	if res.Cores != 150 {
		t.Errorf("Expected 150 cores reservation, received %d", res.Cores)
	}

	if res.Memory != 1024 {
		t.Errorf("Expected 1024 memory reservation, received %d", res.Memory)
	}

	if res.Disk != 524288 {
		t.Errorf("Expected 524288 disk reservation, received %d", res.Disk)
	}
}

func TestParseRequirements(t *testing.T) {
	contents := `
[X-Fleet]
X-Foo=Bar
Ping=Pong
X-Key=Value
`
	j := NewJob("foo.service", *newUnit(t, contents))
	reqs := j.Requirements()
	if len(reqs) != 2 {
		t.Fatalf("Incorrect number of requirements; got %d, expected 2", len(reqs))
	}

	if len(reqs["Foo"]) != 1 || reqs["Foo"][0] != "Bar" {
		t.Fatalf("Incorrect value %q of requirement 'Foo'", reqs["Foo"])
	}

	if len(reqs["Key"]) != 1 || reqs["Key"][0] != "Value" {
		t.Fatalf("Incorrect value %q of requirement 'Key'", reqs["Key"])
	}
}

func TestParseRequirementsMultipleValuesForKeyStack(t *testing.T) {
	contents := `
[X-Fleet]
X-Foo=Bar
X-Foo=Baz
X-Ping=Pong
X-Ping=Pang
`
	j := NewJob("foo.service", *newUnit(t, contents))
	reqs := j.Requirements()
	if len(reqs) != 2 {
		t.Fatalf("Incorrect number of requirements; got %d, expected 2: %v", len(reqs), reqs)
	}

	if len(reqs["Foo"]) != 2 || reqs["Foo"][0] != "Bar" || reqs["Foo"][1] != "Baz" {
		t.Fatalf("Incorrect value %v of requirement 'Foo'", reqs["Foo"])
	}

	if len(reqs["Ping"]) != 2 || reqs["Ping"][0] != "Pong" || reqs["Ping"][1] != "Pang" {
		t.Fatalf("Incorrect value %v of requirement 'Ping'", reqs["Ping"])
	}
}

func TestParseRequirementsInstanceUnit(t *testing.T) {
	contents := `
[X-Fleet]
X-Foo=%n
X-Bar=%N
X-Baz=%p
X-Qux=%i
X-Zzz=something
`
	// Ensure the correct values are replaced for a non-instance unit
	j := NewJob("test.service", *newUnit(t, contents))
	reqs := j.Requirements()
	for field, want := range map[string]string{
		"Foo": "test.service",
		"Bar": "test",
		"Baz": "test",
		"Qux": "",
		"Zzz": "something",
	} {
		got := reqs[field]
		if len(got) != 1 || got[0] != want {
			t.Errorf("Requirement %q unexpectedly altered for non-instance unit: want %q, got %q", field, want, got)
		}
	}

	// Now ensure that they are substituted appropriately for an instance unit
	j = NewJob("ssh@2.service", *newUnit(t, contents))
	reqs = j.Requirements()
	for field, want := range map[string]string{
		"Foo": "ssh@2.service",
		"Bar": "ssh@2",
		"Baz": "ssh",
		"Qux": "2",
		"Zzz": "something",
	} {
		got := reqs[field]
		if len(got) != 1 || got[0] != want {
			t.Errorf("Bad instance unit requirement substitution for %q: want %q, got %q", field, want, got)
		}
	}

}

func TestParseRequirementsMissingSection(t *testing.T) {
	contents := `
[Unit]
Description=Timmy
`
	j := NewJob("foo.service", *newUnit(t, contents))
	reqs := j.Requirements()
	if len(reqs) != 0 {
		t.Fatalf("Incorrect number of requirements; got %d, expected 0", len(reqs))
	}
}

func TestJobConditionMachineID(t *testing.T) {
	tests := []struct {
		unit string
		outS string
		outB bool
	}{
		// Simplest case
		{
			`[X-Fleet]
X-ConditionMachineID=123
`,
			"123",
			true,
		},

		// First value wins
		// TODO(bcwaldon): maybe the last one should win?
		{
			`[X-Fleet]
X-ConditionMachineID="123" "456"
`,
			"123",
			true,
		},

		// No value provided
		{
			`[X-Fleet]`,
			"",
			false,
		},

		// Ensure we fall back to the legacy boot ID option
		{
			`[X-Fleet]
X-ConditionMachineBootID=123
`,
			"123",
			true,
		},

		// Fall back to legacy option only if non-boot ID is absent
		{
			`[X-Fleet]
X-ConditionMachineBootID=123
X-ConditionMachineID=456
`,
			"456",
			true,
		},
	}

	for _, tt := range tests {
		j := NewJob("echo.service", *newUnit(t, tt.unit))
		outS, outB := j.RequiredTarget()

		if outS != tt.outS {
			t.Errorf("Expected target requirement %s, got %s", tt.outS, outS)
		}

		if outB != tt.outB {
			t.Errorf("Expected target requirement ok-val %t, got %t", tt.outB, outB)
		}
	}
}

func TestOneshotJob(t *testing.T) {
	ej := NewJob("foo.service", *newUnit(t, ""))
	if ej.IsOneshot() {
		t.Error("IsOneshot() on job without Service section returned true unexpectedly")
	}

	j := NewJob("bar.service", *newUnit(t, `
[Service]
ExecStart=/bin/false`))
	if j.IsOneshot() {
		t.Error("IsOneshot() on Service job with no Type returned true unexpectedly")
	}

	sj := NewJob("bar.service", *newUnit(t, `
[Service]
Type=simple`))
	if sj.IsOneshot() {
		t.Error("IsOneshot() on simple job returned true unexpectedly")
	}

	bj := NewJob("bar.service", *newUnit(t, `
[Service]
Type=oneshot`))
	if !bj.IsOneshot() {
		t.Error("IsOneshot() on oneshot job returned false unexpectedly")
	}
}

func TestInstanceUnitPrintf(t *testing.T) {
	u := unit.NewUnitNameInfo("foo@bar.waldo")
	if u == nil {
		t.Fatal("NewNamedUnit returned nil - aborting")
	}
	for _, tt := range []struct {
		in   string
		want string
	}{
		{"%n", "foo@bar.waldo"},
		{"%N", "foo@bar"},
		{"%p", "foo"},
		{"%i", "bar"},
	} {
		got := unitPrintf(tt.in, *u)
		if got != tt.want {
			t.Errorf("Replacement of %q failed: got %q, want %q", tt.in, got, tt.want)
		}
	}
}
<|endoftext|>