<commit_before>package linker

import (
	"fmt"
	"log"
	"strings"
	// "path/filepath"
)

import (
	"butler/null"
	proto "code.google.com/p/goprotobuf/proto"
	tp "tritium/proto"
)

type FuncMap map[string]int

type LinkingContext struct {
	objMap        map[string]int
	funList       []FuncMap
	textType      int
	types         []string
	files         []string
	Errors        []string
	ProjectFolder string
	ScriptsFolder string
	*tp.Transform
}

type LocalDef map[string]int

func NewObjectLinkingContext(pkg *tp.Package, objs []*tp.ScriptObject, projectPath, scriptPath string) *LinkingContext {
	// Setup object lookup map!
	objScriptLookup := make(map[string]int, len(objs))
	for index, obj := range objs {
		objScriptLookup[null.GetString(obj.Name)] = index
	}
	ctx := NewLinkingContext(pkg)
	ctx.objMap = objScriptLookup
	ctx.Objects = objs
	ctx.ProjectFolder = projectPath
	ctx.ScriptsFolder = scriptPath
	return ctx
}

func NewLinkingContext(pkg *tp.Package) *LinkingContext {
	// Setup the function map!
	functionLookup := make([]FuncMap, len(pkg.Types))
	types := make([]string, len(pkg.Types))

	for typeId, typeObj := range pkg.Types {
		funcMap := make(FuncMap)
		types[typeId] = null.GetString(typeObj.Name)
		//println("Type:",null.GetString(typeObj.Name))
		//println("Implements:", null.GetInt32(typeObj.Implements))
		implements := functionLookup[null.GetInt32(typeObj.Implements)]
		for index, fun := range pkg.Functions {
			stub := fun.Stub(pkg)

			funScopeId := null.GetInt32(fun.ScopeTypeId)
			inherited := false
			if implements != nil {
				_, inherited = implements[stub]
			}
			if (funScopeId == int32(typeId)) || inherited {
				//println(null.GetString(typeObj.Name), ":", stub)
				funcMap[stub] = index
			}
		}
		functionLookup[typeId] = funcMap
	}

	// Setup the main context object
	ctx := &LinkingContext{
		funList: functionLookup,
		types:   types,
		Errors:  make([]string, 0),
		Transform: &tp.Transform{
			Pkg: pkg,
		},
	}

	// Find Text type int -- need its ID to deal with Text literals during processing
	ctx.textType = pkg.GetTypeId("Text")

	// println("TYPES")
	// for i, t := range types {
	// 	println(i, ":", t)
	// }
	// println()

	// println("FUNCTIONS")
	// for t, fm := range functionLookup {
	// 	println("TYPE", t)
	// 	for n, f:= range fm {
	// 		println(n, ":", f)
	// 	}
	// 	println()
	// }
	// println()

	return ctx
}

func (ctx *LinkingContext) Link() {
	ctx.link(0, ctx.Pkg.GetTypeId("Text"))
}

func (ctx *LinkingContext) link(objId, scopeType int) {
	obj := ctx.Objects[objId]
	//println("link object", objId)
	//println(obj.String())
	if null.GetBool(obj.Linked) == false {
		//println("Linking", null.GetString(obj.Name))
		obj.ScopeTypeId = proto.Int(scopeType)
		obj.Linked = proto.Bool(true)
		path := obj.GetName()
		ctx.files = append(ctx.files, null.GetString(obj.Name))
		ctx.ProcessInstruction(obj.Root, scopeType, path)
		ctx.files = ctx.files[:(len(ctx.files) - 1)]
	} else {
		if scopeType != int(null.GetInt32(obj.ScopeTypeId)) {
			ctx.error("script", "Imported a script in two different scopes! Not processing second import.")
		}
	}
}

func (ctx *LinkingContext) ProcessInstruction(ins *tp.Instruction, scopeType int, path string) (returnType int) {
	localScope := make(LocalDef, 0)
	return ctx.ProcessInstructionWithLocalScope(ins, scopeType, localScope, "", path)
}

func (ctx *LinkingContext) ProcessInstructionWithLocalScope(ins *tp.Instruction, scopeType int, localScope LocalDef, caller string, path string) (returnType int) {
	returnType = -1
	ins.IsValid = proto.Bool(true)
	switch *ins.Type {
	case tp.Instruction_IMPORT:
		// set its import_id and blank the value field
		// importValue := filepath.Join(ctx.ProjectFolder, null.GetString(ins.Value))
		//println("import: ", importValue)
		//println(null.GetInt32(ins.LineNumber))
		importId, ok := ctx.objMap[null.GetString(ins.Value)]
		if ok != true {
			ctx.error(ins, "Invalid import `%s`", ins.String())
		}
		// Make sure this object is linked with the right scopeType
		ctx.link(importId, scopeType)
		//println("befor", ins.String())
		ins.ObjectId = proto.Int(importId)
		ins.Value = nil
		//println("after", ins.String())
	case tp.Instruction_LOCAL_VAR:
		name := null.GetString(ins.Value)
		if name == "1" || name == "2" || name == "3" || name == "4" || name == "5" || name == "6" || name == "7" {
			if len(ins.Arguments) > 0 {
				// We are going to assign something to this variable
				returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path)
				if returnType != ctx.textType {
					ctx.error(ins, "Numeric local vars can ONLY be Text")
				}
			}
			if ins.Children != nil {
				for _, child := range ins.Children {
					ctx.ProcessInstructionWithLocalScope(child, ctx.textType, localScope, caller, path)
				}
			}
			returnType = ctx.textType
		} else { // Not numeric.
			typeId, found := localScope[name]
			if found {
				returnType = typeId
				if len(ins.Arguments) > 0 {
					ctx.error(ins, "The local variable \"%%%s\" has been assigned before and cannot be reassigned!", name)
				} else {
					if ins.Children != nil {
						for _, child := range ins.Children {
							returnType = ctx.ProcessInstructionWithLocalScope(child, typeId, localScope, caller, path)
						}
					}
				}

			} else {
				if len(ins.Arguments) > 0 {
					// We are going to assign something to this variable
					// But first, check for possible mutation and prevent it for now.
					if ins.Children != nil {
						ctx.error(ins, "May not open a scope during initialization of local variable \"%%%s\".", name)
					}
					returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path)
					localScope[name] = returnType
				} else {
					println(ins.String())
					ctx.error(ins, "I've never seen the variable \"%%%s\" before! Please assign a value before usage.", name)
				}
			}
		}

	case tp.Instruction_FUNCTION_CALL:
		stub := null.GetString(ins.Value)
		if stub == "yield" {
			ins.YieldTypeId = proto.Int32(int32(scopeType))
		}
		// process the args
		if ins.Arguments != nil {
			for _, arg := range ins.Arguments {
				argReturn := ctx.ProcessInstructionWithLocalScope(arg, scopeType, localScope, caller, path)
				if argReturn == -1 {
					ctx.error(ins, "Invalid argument object %q", arg.String())
					return
				}
				stub = stub + "," + ctx.types[argReturn]
			}
		}
		// look up the function wrt the current context type + function name
		funcId, ok := ctx.funList[scopeType][stub]
		if ok != true {
			message := "Available functions...\n"
			for funcName, _ := range ctx.funList[scopeType] {
				message = message + funcName + "\n"
			}
			log.Printf("%s\n", message)

			location := ""
			if len(path) > 0 {
				location = path
			} else {
				location = "Package " + ctx.Pkg.GetName()
			}
			readableCalleeStub := strings.Replace(stub, ",", "(", 1)
			if strings.Index(readableCalleeStub, "(") != -1 {
				readableCalleeStub = readableCalleeStub + ")"
			}
			readableCallerStub := strings.Replace(caller, ",", "(", 1)
			if strings.Index(readableCallerStub, "(") != -1 {
				readableCallerStub = readableCallerStub + ")"
      }
			ctx.error(ins, "%s:%d: could not find function %s.%s (called from %s.%s)", location, ins.GetLineNumber(), ctx.types[scopeType], readableCalleeStub, ctx.types[scopeType], readableCallerStub)

		} else {
			ins.FunctionId = proto.Int32(int32(funcId))
			fun := ctx.Pkg.Functions[funcId]
			returnType = int(null.GetInt32(fun.ReturnTypeId))
			opensScopeType := int(null.GetInt32(fun.OpensTypeId))
			if opensScopeType == 0 {
				// If we're a Base scope, don't mess with texas!
				opensScopeType = scopeType
			}
			// If it inherits:
			inheritedOpensScopeType := ctx.Pkg.FindDescendantType(int32(opensScopeType))
			if inheritedOpensScopeType != -1 {
				opensScopeType = inheritedOpensScopeType
			}

			// Copy the local scope
			parentScope := localScope
			localScope = make(LocalDef, len(parentScope))
			for s, t := range parentScope {
				localScope[s] = t
			}

			if ins.Children != nil {
				for _, child := range ins.Children {
					ctx.ProcessInstructionWithLocalScope(child, opensScopeType, localScope, stub, path) // thread the name of the caller through the linkages
				}
			}
		}
	case tp.Instruction_TEXT:
		returnType = ctx.textType
	case tp.Instruction_BLOCK:
		if ins.Children != nil {
			for _, child := range ins.Children {
				returnType = ctx.ProcessInstructionWithLocalScope(child, scopeType, localScope, caller, path)
			}
		}
	}
	return
}

func (ctx *LinkingContext) HasErrors() bool {
	return (len(ctx.Errors) > 0)
}

func (ctx *LinkingContext) error(obj interface{}, format string, data ...interface{}) {
	message := fmt.Sprintf(format, data...)
	ctx.Errors = append(ctx.Errors, message)
	ins, ok := obj.(*tp.Instruction)
	if ok {
		ins.IsValid = proto.Bool(false)
	}
	log.Printf("%s\n", message)
}
<commit_msg>Adding circular import detection to the linker.<commit_after>package linker

import (
	"fmt"
	"log"
	"strings"
	// "path/filepath"
)

import (
	"butler/null"
	proto "code.google.com/p/goprotobuf/proto"
	tp "tritium/proto"
)

type FuncMap map[string]int

type LinkingContext struct {
	objMap        map[string]int
	funList       []FuncMap
	textType      int
	types         []string
	files         []string
	Errors        []string
	ProjectFolder string
	ScriptsFolder string
	*tp.Transform
	Visiting      map[string]bool
}

type LocalDef map[string]int

func NewObjectLinkingContext(pkg *tp.Package, objs []*tp.ScriptObject, projectPath, scriptPath string) *LinkingContext {
	// Setup object lookup map!
	objScriptLookup := make(map[string]int, len(objs))
	for index, obj := range objs {
		objScriptLookup[null.GetString(obj.Name)] = index
	}
	ctx := NewLinkingContext(pkg)
	ctx.objMap = objScriptLookup
	ctx.Objects = objs
	ctx.ProjectFolder = projectPath
	ctx.ScriptsFolder = scriptPath
	ctx.Visiting = make(map[string]bool, 0)
	return ctx
}

func NewLinkingContext(pkg *tp.Package) *LinkingContext {
	// Setup the function map!
	functionLookup := make([]FuncMap, len(pkg.Types))
	types := make([]string, len(pkg.Types))

	for typeId, typeObj := range pkg.Types {
		funcMap := make(FuncMap)
		types[typeId] = null.GetString(typeObj.Name)
		//println("Type:",null.GetString(typeObj.Name))
		//println("Implements:", null.GetInt32(typeObj.Implements))
		implements := functionLookup[null.GetInt32(typeObj.Implements)]
		for index, fun := range pkg.Functions {
			stub := fun.Stub(pkg)

			funScopeId := null.GetInt32(fun.ScopeTypeId)
			inherited := false
			if implements != nil {
				_, inherited = implements[stub]
			}
			if (funScopeId == int32(typeId)) || inherited {
				//println(null.GetString(typeObj.Name), ":", stub)
				funcMap[stub] = index
			}
		}
		functionLookup[typeId] = funcMap
	}

	// Setup the main context object
	ctx := &LinkingContext{
		funList: functionLookup,
		types:   types,
		Errors:  make([]string, 0),
		Transform: &tp.Transform{
			Pkg: pkg,
		},
	}

	// Find Text type int -- need its ID to deal with Text literals during processing
	ctx.textType = pkg.GetTypeId("Text")

	// println("TYPES")
	// for i, t := range types {
	// 	println(i, ":", t)
	// }
	// println()

	// println("FUNCTIONS")
	// for t, fm := range functionLookup {
	// 	println("TYPE", t)
	// 	for n, f:= range fm {
	// 		println(n, ":", f)
	// 	}
	// 	println()
	// }
	// println()

	return ctx
}

func (ctx *LinkingContext) Link() {
	ctx.link(0, ctx.Pkg.GetTypeId("Text"))
}

func (ctx *LinkingContext) link(objId, scopeType int) {
	obj := ctx.Objects[objId]
	//println("link object", objId)
	//println(obj.String())
	if null.GetBool(obj.Linked) == false {
		//println("Linking", null.GetString(obj.Name))
		obj.ScopeTypeId = proto.Int(scopeType)
		obj.Linked = proto.Bool(true)
		path := obj.GetName()
		ctx.files = append(ctx.files, null.GetString(obj.Name))
		ctx.ProcessInstruction(obj.Root, scopeType, path)
		ctx.files = ctx.files[:(len(ctx.files) - 1)]
	} else {
		if scopeType != int(null.GetInt32(obj.ScopeTypeId)) {
			ctx.error("script", "Imported a script in two different scopes! Not processing second import.")
		}
	}
}

func (ctx *LinkingContext) ProcessInstruction(ins *tp.Instruction, scopeType int, path string) (returnType int) {
	localScope := make(LocalDef, 0)
	return ctx.ProcessInstructionWithLocalScope(ins, scopeType, localScope, "", path)
}

func (ctx *LinkingContext) ProcessInstructionWithLocalScope(ins *tp.Instruction, scopeType int, localScope LocalDef, caller string, path string) (returnType int) {
	returnType = -1
	ins.IsValid = proto.Bool(true)
	switch *ins.Type {
	case tp.Instruction_IMPORT:
		importLocation := ins.GetValue()

		// keep track of which files we're inside of, to detect circular imports
		val, present := ctx.Visiting[importLocation]
		if present && val {
			ctx.error(ins, "Circular import detected: %s", importLocation)
			panic(fmt.Sprintf("Circular import detected: %s", importLocation))
		}
		ctx.Visiting[importLocation] = true

		// set its import_id and blank the value field
		// importValue := filepath.Join(ctx.ProjectFolder, null.GetString(ins.Value))
		//println("import: ", importValue)
		//println(null.GetInt32(ins.LineNumber))
		importId, ok := ctx.objMap[null.GetString(ins.Value)]
		if ok != true {
			ctx.error(ins, "Invalid import `%s`", ins.String())
		}
		// Make sure this object is linked with the right scopeType
		ctx.link(importId, scopeType)
		// unset this after visiting an import
		ctx.Visiting[importLocation] = false
		//println("befor", ins.String())
		ins.ObjectId = proto.Int(importId)
		ins.Value = nil
		//println("after", ins.String())
	case tp.Instruction_LOCAL_VAR:
		name := null.GetString(ins.Value)
		if name == "1" || name == "2" || name == "3" || name == "4" || name == "5" || name == "6" || name == "7" {
			if len(ins.Arguments) > 0 {
				// We are going to assign something to this variable
				returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path)
				if returnType != ctx.textType {
					ctx.error(ins, "Numeric local vars can ONLY be Text")
				}
			}
			if ins.Children != nil {
				for _, child := range ins.Children {
					ctx.ProcessInstructionWithLocalScope(child, ctx.textType, localScope, caller, path)
				}
			}
			returnType = ctx.textType
		} else { // Not numeric.
			typeId, found := localScope[name]
			if found {
				returnType = typeId
				if len(ins.Arguments) > 0 {
					ctx.error(ins, "The local variable \"%%%s\" has been assigned before and cannot be reassigned!", name)
				} else {
					if ins.Children != nil {
						for _, child := range ins.Children {
							returnType = ctx.ProcessInstructionWithLocalScope(child, typeId, localScope, caller, path)
						}
					}
				}

			} else {
				if len(ins.Arguments) > 0 {
					// We are going to assign something to this variable
					// But first, check for possible mutation and prevent it for now.
					if ins.Children != nil {
						ctx.error(ins, "May not open a scope during initialization of local variable \"%%%s\".", name)
					}
					returnType = ctx.ProcessInstructionWithLocalScope(ins.Arguments[0], scopeType, localScope, caller, path)
					localScope[name] = returnType
				} else {
					println(ins.String())
					ctx.error(ins, "I've never seen the variable \"%%%s\" before! Please assign a value before usage.", name)
				}
			}
		}

	case tp.Instruction_FUNCTION_CALL:
		stub := null.GetString(ins.Value)
		if stub == "yield" {
			ins.YieldTypeId = proto.Int32(int32(scopeType))
		}
		// process the args
		if ins.Arguments != nil {
			for _, arg := range ins.Arguments {
				argReturn := ctx.ProcessInstructionWithLocalScope(arg, scopeType, localScope, caller, path)
				if argReturn == -1 {
					ctx.error(ins, "Invalid argument object %q", arg.String())
					return
				}
				stub = stub + "," + ctx.types[argReturn]
			}
		}
		// look up the function wrt the current context type + function name
		funcId, ok := ctx.funList[scopeType][stub]
		if ok != true {
			message := "Available functions...\n"
			for funcName, _ := range ctx.funList[scopeType] {
				message = message + funcName + "\n"
			}
			log.Printf("%s\n", message)

			location := ""
			if len(path) > 0 {
				location = path
			} else {
				location = "Package " + ctx.Pkg.GetName()
			}
			readableCalleeStub := strings.Replace(stub, ",", "(", 1)
			if strings.Index(readableCalleeStub, "(") != -1 {
				readableCalleeStub = readableCalleeStub + ")"
			}
			readableCallerStub := strings.Replace(caller, ",", "(", 1)
			if strings.Index(readableCallerStub, "(") != -1 {
				readableCallerStub = readableCallerStub + ")"
      }
			ctx.error(ins, "%s:%d: could not find function %s.%s (called from %s.%s)", location, ins.GetLineNumber(), ctx.types[scopeType], readableCalleeStub, ctx.types[scopeType], readableCallerStub)

		} else {
			ins.FunctionId = proto.Int32(int32(funcId))
			fun := ctx.Pkg.Functions[funcId]
			returnType = int(null.GetInt32(fun.ReturnTypeId))
			opensScopeType := int(null.GetInt32(fun.OpensTypeId))
			if opensScopeType == 0 {
				// If we're a Base scope, don't mess with texas!
				opensScopeType = scopeType
			}
			// If it inherits:
			inheritedOpensScopeType := ctx.Pkg.FindDescendantType(int32(opensScopeType))
			if inheritedOpensScopeType != -1 {
				opensScopeType = inheritedOpensScopeType
			}

			// Copy the local scope
			parentScope := localScope
			localScope = make(LocalDef, len(parentScope))
			for s, t := range parentScope {
				localScope[s] = t
			}

			if ins.Children != nil {
				for _, child := range ins.Children {
					ctx.ProcessInstructionWithLocalScope(child, opensScopeType, localScope, stub, path) // thread the name of the caller through the linkages
				}
			}
		}
	case tp.Instruction_TEXT:
		returnType = ctx.textType
	case tp.Instruction_BLOCK:
		if ins.Children != nil {
			for _, child := range ins.Children {
				returnType = ctx.ProcessInstructionWithLocalScope(child, scopeType, localScope, caller, path)
			}
		}
	}
	return
}

func (ctx *LinkingContext) HasErrors() bool {
	return (len(ctx.Errors) > 0)
}

func (ctx *LinkingContext) error(obj interface{}, format string, data ...interface{}) {
	message := fmt.Sprintf(format, data...)
	ctx.Errors = append(ctx.Errors, message)
	ins, ok := obj.(*tp.Instruction)
	if ok {
		ins.IsValid = proto.Bool(false)
	}
	log.Printf("%s\n", message)
}
<|endoftext|>


<commit_before>// Copyright 2015 CloudAwan LLC
//
// 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 deploy

import (
	"github.com/astaxie/beego"
	"github.com/cloudawan/cloudone_gui/controllers/identity"
	"github.com/cloudawan/cloudone_gui/controllers/utility/configuration"
	"github.com/cloudawan/cloudone_gui/controllers/utility/guimessagedisplay"
	"github.com/cloudawan/cloudone_utility/restclient"
	"sort"
	"strconv"
	"strings"
)

type CreateController struct {
	beego.Controller
}

type DeployCreateInput struct {
	ImageInformationName string
	Version              string
	Description          string
	ReplicaAmount        int
	PortSlice            []DeployContainerPort
	EnvironmentSlice     []ReplicationControllerContainerEnvironment
	ResourceMap          map[string]interface{}
	ExtraJsonMap         map[string]interface{}
}

type DeployContainerPort struct {
	Name          string
	ContainerPort int
	NodePort      int
}

type ReplicationControllerContainerPort struct {
	Name          string
	ContainerPort int
}

type ReplicationControllerContainerEnvironment struct {
	Name  string
	Value string
}

type ImageRecord struct {
	ImageInformation string
	Version          string
	Path             string
	VersionInfo      map[string]string
	Environment      map[string]string
	Description      string
	CreatedTime      string
}

type ByImageRecord []ImageRecord

func (b ByImageRecord) Len() int           { return len(b) }
func (b ByImageRecord) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b ByImageRecord) Less(i, j int) bool { return b[i].Version > b[j].Version } // Use > to list from latest to oldest

type Region struct {
	Name           string
	LocationTagged bool
	ZoneSlice      []Zone
}

type Zone struct {
	Name           string
	LocationTagged bool
	NodeSlice      []Node
}

type Node struct {
	Name     string
	Address  string
	Capacity Capacity
}

type Capacity struct {
	Cpu    string
	Memory string
}

func (c *CreateController) Get() {
	c.TplName = "deploy/deploy/create.html"
	guimessage := guimessagedisplay.GetGUIMessage(c)

	// Authorization for web page display
	c.Data["layoutMenu"] = c.GetSession("layoutMenu")

	cloudoneProtocol := beego.AppConfig.String("cloudoneProtocol")
	cloudoneHost := beego.AppConfig.String("cloudoneHost")
	cloudonePort := beego.AppConfig.String("cloudonePort")

	name := c.GetString("name")

	url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
		"/api/v1/imagerecords/" + name

	imageRecordSlice := make([]ImageRecord, 0)

	tokenHeaderMap, _ := c.GetSession("tokenHeaderMap").(map[string]string)

	_, err := restclient.RequestGetWithStructure(url, &imageRecordSlice, tokenHeaderMap)

	if identity.IsTokenInvalidAndRedirect(c, c.Ctx, err) {
		return
	}

	if err != nil {
		// Error
		guimessage.AddDanger(err.Error())
	} else {
		kubeapiHost, kubeapiPort, err := configuration.GetAvailableKubeapiHostAndPort()
		if err != nil {
			// Error
			guimessage.AddDanger(err.Error())
			guimessage.OutputMessage(c.Data)
			return
		}

		url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
			"/api/v1/nodes/topology?kubeapihost=" + kubeapiHost + "&kubeapiport=" + strconv.Itoa(kubeapiPort)

		regionSlice := make([]Region, 0)

		_, err = restclient.RequestGetWithStructure(url, &regionSlice, tokenHeaderMap)

		if identity.IsTokenInvalidAndRedirect(c, c.Ctx, err) {
			return
		}

		if err != nil {
			// Error
			guimessage.AddDanger(err.Error())
		} else {
			filteredRegionSlice := make([]Region, 0)
			for _, region := range regionSlice {
				if region.LocationTagged {
					filteredRegionSlice = append(filteredRegionSlice, region)
				}
			}

			c.Data["regionSlice"] = filteredRegionSlice

			sort.Sort(ByImageRecord(imageRecordSlice))

			c.Data["imageInformationName"] = name
			c.Data["imageRecordSlice"] = imageRecordSlice
		}
	}

	guimessage.OutputMessage(c.Data)
}

func (c *CreateController) Post() {
	guimessage := guimessagedisplay.GetGUIMessage(c)

	cloudoneProtocol := beego.AppConfig.String("cloudoneProtocol")
	cloudoneHost := beego.AppConfig.String("cloudoneHost")
	cloudonePort := beego.AppConfig.String("cloudonePort")
	kubeapiHost, kubeapiPort, err := configuration.GetAvailableKubeapiHostAndPort()
	if err != nil {
		// Error
		guimessage.AddDanger(err.Error())
		guimessage.RedirectMessage(c)
		c.Ctx.Redirect(302, "/gui/deploy/deploy/list")
		return
	}

	namespaces, _ := c.GetSession("namespace").(string)

	imageInformationName := c.GetString("imageInformationName")
	version := c.GetString("version")
	description := c.GetString("description")
	replicaAmount, _ := c.GetInt("replicaAmount")

	region := c.GetString("region")
	zone := c.GetString("zone")

	if region == "Any" {
		region = ""
	}
	if zone == "Any" {
		zone = ""
	}

	resourceCPURequest, resourceCPURequestError := c.GetFloat("resourceCPURequest")
	resourceCPULimit, resourceCPULimitError := c.GetFloat("resourceCPULimit")
	resourceMemoryRequest, resourceMemoryRequestError := c.GetInt("resourceMemoryRequest")
	resourceMemoryLimit, resourceMemoryLimitError := c.GetInt("resourceMemoryLimit")

	portName := "generated"

	indexContainerPortMap := make(map[string]int)

	keySlice := make([]string, 0)
	inputMap := c.Input()
	if inputMap != nil {
		for key, _ := range inputMap {
			// Only collect environment belonging to this version
			if strings.HasPrefix(key, version) {
				keySlice = append(keySlice, key)
			}

			// Collect dynamically generated containerPort
			if strings.HasPrefix(key, "containerPort") {
				containerPort, _ := c.GetInt(key)
				index := key[len("containerPort"):]
				indexContainerPortMap[index] = containerPort
			}
		}
	}

	environmentSlice := make([]ReplicationControllerContainerEnvironment, 0)
	length := len(version) + 1 // + 1 for _
	for _, key := range keySlice {
		value := c.GetString(key)
		if len(value) > 0 {
			environmentSlice = append(environmentSlice,
				ReplicationControllerContainerEnvironment{key[length:], value})
		}
	}

	deployContainerPortSlice := make([]DeployContainerPort, 0)
	i := 0
	for index, containerPort := range indexContainerPortMap {
		nodePort := -1
		if c.GetString("useNodePort"+index) == "on" {
			if c.GetString("autoGeneratedNodePort"+index) == "on" {
				nodePort = 0
			} else {
				// If fail to parse, nodePort will be set to 0 that means auto-generated
				nodePort, _ = c.GetInt("nodePort" + index)
			}
		}
		deployContainerPortSlice = append(deployContainerPortSlice, DeployContainerPort{portName + strconv.Itoa(i), containerPort, nodePort})
		i++
	}

	// Resource reservation
	resourceMap := make(map[string]interface{})
	if resourceCPURequestError == nil || resourceMemoryRequestError == nil {
		resourceMap["requests"] = make(map[string]interface{})
		if resourceCPURequestError == nil {
			resourceMap["requests"].(map[string]interface{})["cpu"] = resourceCPURequest
		}
		if resourceMemoryRequestError == nil {
			resourceMap["requests"].(map[string]interface{})["memory"] = strconv.Itoa(resourceMemoryRequest) + "Mi"
		}
	}

	if resourceCPULimitError == nil || resourceMemoryLimitError == nil {
		resourceMap["limits"] = make(map[string]interface{})
		if resourceCPULimitError == nil {
			resourceMap["limits"].(map[string]interface{})["cpu"] = resourceCPULimit
		}
		if resourceMemoryLimitError == nil {
			resourceMap["limits"].(map[string]interface{})["memory"] = strconv.Itoa(resourceMemoryLimit) + "Mi"
		}
	}

	extraJsonMap := make(map[string]interface{})
	if len(region) > 0 {
		extraJsonMap["spec"] = make(map[string]interface{})
		extraJsonMap["spec"].(map[string]interface{})["template"] = make(map[string]interface{})
		extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"] = make(map[string]interface{})
		extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["nodeSelector"] = make(map[string]interface{})

		extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["nodeSelector"].(map[string]interface{})["region"] = region
		if len(zone) > 0 {
			extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["nodeSelector"].(map[string]interface{})["zone"] = zone
		}
	} else {
		extraJsonMap = nil
	}

	deployCreateInput := DeployCreateInput{
		imageInformationName,
		version,
		description,
		replicaAmount,
		deployContainerPortSlice,
		environmentSlice,
		resourceMap,
		extraJsonMap,
	}

	url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
		"/api/v1/deploys/create/" + namespaces + "?kubeapihost=" + kubeapiHost + "&kubeapiport=" + strconv.Itoa(kubeapiPort)

	tokenHeaderMap, _ := c.GetSession("tokenHeaderMap").(map[string]string)

	_, err = restclient.RequestPostWithStructure(url, deployCreateInput, nil, tokenHeaderMap)

	if identity.IsTokenInvalidAndRedirect(c, c.Ctx, err) {
		return
	}

	if err != nil {
		// Error
		guimessage.AddDanger(err.Error())
	} else {
		guimessage.AddSuccess("Create deploy " + imageInformationName + " version " + version + " success")
	}

	c.Ctx.Redirect(302, "/gui/deploy/deploy/list")

	guimessage.RedirectMessage(c)
}
<commit_msg>Add request and limit check<commit_after>// Copyright 2015 CloudAwan LLC
//
// 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 deploy

import (
	"github.com/astaxie/beego"
	"github.com/cloudawan/cloudone_gui/controllers/identity"
	"github.com/cloudawan/cloudone_gui/controllers/utility/configuration"
	"github.com/cloudawan/cloudone_gui/controllers/utility/guimessagedisplay"
	"github.com/cloudawan/cloudone_utility/restclient"
	"sort"
	"strconv"
	"strings"
)

type CreateController struct {
	beego.Controller
}

type DeployCreateInput struct {
	ImageInformationName string
	Version              string
	Description          string
	ReplicaAmount        int
	PortSlice            []DeployContainerPort
	EnvironmentSlice     []ReplicationControllerContainerEnvironment
	ResourceMap          map[string]interface{}
	ExtraJsonMap         map[string]interface{}
}

type DeployContainerPort struct {
	Name          string
	ContainerPort int
	NodePort      int
}

type ReplicationControllerContainerPort struct {
	Name          string
	ContainerPort int
}

type ReplicationControllerContainerEnvironment struct {
	Name  string
	Value string
}

type ImageRecord struct {
	ImageInformation string
	Version          string
	Path             string
	VersionInfo      map[string]string
	Environment      map[string]string
	Description      string
	CreatedTime      string
}

type ByImageRecord []ImageRecord

func (b ByImageRecord) Len() int           { return len(b) }
func (b ByImageRecord) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b ByImageRecord) Less(i, j int) bool { return b[i].Version > b[j].Version } // Use > to list from latest to oldest

type Region struct {
	Name           string
	LocationTagged bool
	ZoneSlice      []Zone
}

type Zone struct {
	Name           string
	LocationTagged bool
	NodeSlice      []Node
}

type Node struct {
	Name     string
	Address  string
	Capacity Capacity
}

type Capacity struct {
	Cpu    string
	Memory string
}

func (c *CreateController) Get() {
	c.TplName = "deploy/deploy/create.html"
	guimessage := guimessagedisplay.GetGUIMessage(c)

	// Authorization for web page display
	c.Data["layoutMenu"] = c.GetSession("layoutMenu")

	cloudoneProtocol := beego.AppConfig.String("cloudoneProtocol")
	cloudoneHost := beego.AppConfig.String("cloudoneHost")
	cloudonePort := beego.AppConfig.String("cloudonePort")

	name := c.GetString("name")

	url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
		"/api/v1/imagerecords/" + name

	imageRecordSlice := make([]ImageRecord, 0)

	tokenHeaderMap, _ := c.GetSession("tokenHeaderMap").(map[string]string)

	_, err := restclient.RequestGetWithStructure(url, &imageRecordSlice, tokenHeaderMap)

	if identity.IsTokenInvalidAndRedirect(c, c.Ctx, err) {
		return
	}

	if err != nil {
		// Error
		guimessage.AddDanger(err.Error())
	} else {
		kubeapiHost, kubeapiPort, err := configuration.GetAvailableKubeapiHostAndPort()
		if err != nil {
			// Error
			guimessage.AddDanger(err.Error())
			guimessage.OutputMessage(c.Data)
			return
		}

		url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
			"/api/v1/nodes/topology?kubeapihost=" + kubeapiHost + "&kubeapiport=" + strconv.Itoa(kubeapiPort)

		regionSlice := make([]Region, 0)

		_, err = restclient.RequestGetWithStructure(url, &regionSlice, tokenHeaderMap)

		if identity.IsTokenInvalidAndRedirect(c, c.Ctx, err) {
			return
		}

		if err != nil {
			// Error
			guimessage.AddDanger(err.Error())
		} else {
			filteredRegionSlice := make([]Region, 0)
			for _, region := range regionSlice {
				if region.LocationTagged {
					filteredRegionSlice = append(filteredRegionSlice, region)
				}
			}

			c.Data["regionSlice"] = filteredRegionSlice

			sort.Sort(ByImageRecord(imageRecordSlice))

			c.Data["imageInformationName"] = name
			c.Data["imageRecordSlice"] = imageRecordSlice
		}
	}

	guimessage.OutputMessage(c.Data)
}

func (c *CreateController) Post() {
	guimessage := guimessagedisplay.GetGUIMessage(c)

	cloudoneProtocol := beego.AppConfig.String("cloudoneProtocol")
	cloudoneHost := beego.AppConfig.String("cloudoneHost")
	cloudonePort := beego.AppConfig.String("cloudonePort")
	kubeapiHost, kubeapiPort, err := configuration.GetAvailableKubeapiHostAndPort()
	if err != nil {
		// Error
		guimessage.AddDanger(err.Error())
		guimessage.RedirectMessage(c)
		c.Ctx.Redirect(302, "/gui/deploy/deploy/list")
		return
	}

	namespaces, _ := c.GetSession("namespace").(string)

	imageInformationName := c.GetString("imageInformationName")
	version := c.GetString("version")
	description := c.GetString("description")
	replicaAmount, _ := c.GetInt("replicaAmount")

	region := c.GetString("region")
	zone := c.GetString("zone")

	if region == "Any" {
		region = ""
	}
	if zone == "Any" {
		zone = ""
	}

	resourceCPURequest, resourceCPURequestError := c.GetFloat("resourceCPURequest")
	resourceCPULimit, resourceCPULimitError := c.GetFloat("resourceCPULimit")
	resourceMemoryRequest, resourceMemoryRequestError := c.GetInt("resourceMemoryRequest")
	resourceMemoryLimit, resourceMemoryLimitError := c.GetInt("resourceMemoryLimit")

	// Limit must be bigger than request
	if resourceCPURequestError == nil && resourceCPULimitError == nil {
		if resourceCPURequest > resourceCPULimit {
			// Error
			guimessage.AddDanger("CPU request must be smaller or equal to CPU limit")
			guimessage.RedirectMessage(c)
			c.Ctx.Redirect(302, "/gui/deploy/deploy/list")
			return
		}
	}

	if resourceMemoryRequestError == nil && resourceMemoryLimitError == nil {
		if resourceMemoryRequest > resourceMemoryLimit {
			// Error
			guimessage.AddDanger("Memory request must be smaller or equal to Memory limit")
			guimessage.RedirectMessage(c)
			c.Ctx.Redirect(302, "/gui/deploy/deploy/list")
			return
		}
	}

	portName := "generated"

	indexContainerPortMap := make(map[string]int)

	keySlice := make([]string, 0)
	inputMap := c.Input()
	if inputMap != nil {
		for key, _ := range inputMap {
			// Only collect environment belonging to this version
			if strings.HasPrefix(key, version) {
				keySlice = append(keySlice, key)
			}

			// Collect dynamically generated containerPort
			if strings.HasPrefix(key, "containerPort") {
				containerPort, _ := c.GetInt(key)
				index := key[len("containerPort"):]
				indexContainerPortMap[index] = containerPort
			}
		}
	}

	environmentSlice := make([]ReplicationControllerContainerEnvironment, 0)
	length := len(version) + 1 // + 1 for _
	for _, key := range keySlice {
		value := c.GetString(key)
		if len(value) > 0 {
			environmentSlice = append(environmentSlice,
				ReplicationControllerContainerEnvironment{key[length:], value})
		}
	}

	deployContainerPortSlice := make([]DeployContainerPort, 0)
	i := 0
	for index, containerPort := range indexContainerPortMap {
		nodePort := -1
		if c.GetString("useNodePort"+index) == "on" {
			if c.GetString("autoGeneratedNodePort"+index) == "on" {
				nodePort = 0
			} else {
				// If fail to parse, nodePort will be set to 0 that means auto-generated
				nodePort, _ = c.GetInt("nodePort" + index)
			}
		}
		deployContainerPortSlice = append(deployContainerPortSlice, DeployContainerPort{portName + strconv.Itoa(i), containerPort, nodePort})
		i++
	}

	// Resource reservation
	resourceMap := make(map[string]interface{})
	if resourceCPURequestError == nil || resourceMemoryRequestError == nil {
		resourceMap["requests"] = make(map[string]interface{})
		if resourceCPURequestError == nil {
			resourceMap["requests"].(map[string]interface{})["cpu"] = resourceCPURequest
		}
		if resourceMemoryRequestError == nil {
			resourceMap["requests"].(map[string]interface{})["memory"] = strconv.Itoa(resourceMemoryRequest) + "Mi"
		}
	}

	if resourceCPULimitError == nil || resourceMemoryLimitError == nil {
		resourceMap["limits"] = make(map[string]interface{})
		if resourceCPULimitError == nil {
			resourceMap["limits"].(map[string]interface{})["cpu"] = resourceCPULimit
		}
		if resourceMemoryLimitError == nil {
			resourceMap["limits"].(map[string]interface{})["memory"] = strconv.Itoa(resourceMemoryLimit) + "Mi"
		}
	}

	extraJsonMap := make(map[string]interface{})
	if len(region) > 0 {
		extraJsonMap["spec"] = make(map[string]interface{})
		extraJsonMap["spec"].(map[string]interface{})["template"] = make(map[string]interface{})
		extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"] = make(map[string]interface{})
		extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["nodeSelector"] = make(map[string]interface{})

		extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["nodeSelector"].(map[string]interface{})["region"] = region
		if len(zone) > 0 {
			extraJsonMap["spec"].(map[string]interface{})["template"].(map[string]interface{})["spec"].(map[string]interface{})["nodeSelector"].(map[string]interface{})["zone"] = zone
		}
	} else {
		extraJsonMap = nil
	}

	deployCreateInput := DeployCreateInput{
		imageInformationName,
		version,
		description,
		replicaAmount,
		deployContainerPortSlice,
		environmentSlice,
		resourceMap,
		extraJsonMap,
	}

	url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
		"/api/v1/deploys/create/" + namespaces + "?kubeapihost=" + kubeapiHost + "&kubeapiport=" + strconv.Itoa(kubeapiPort)

	tokenHeaderMap, _ := c.GetSession("tokenHeaderMap").(map[string]string)

	_, err = restclient.RequestPostWithStructure(url, deployCreateInput, nil, tokenHeaderMap)

	if identity.IsTokenInvalidAndRedirect(c, c.Ctx, err) {
		return
	}

	if err != nil {
		// Error
		guimessage.AddDanger(err.Error())
	} else {
		guimessage.AddSuccess("Create deploy " + imageInformationName + " version " + version + " success")
	}

	c.Ctx.Redirect(302, "/gui/deploy/deploy/list")

	guimessage.RedirectMessage(c)
}
<|endoftext|>


<commit_before>package cps

import (
	"testing"

	//cps "github.com/akamai/AkamaiOPEN-edgegrid-golang/cps-v2"
	"github.com/stretchr/testify/assert"
)

func TestSHAConversion(t *testing.T) {
	assert.Equal(t, "dosty", "everts")
	assert.Equal(t, SHA256, SHA("SHA-256"))
}
<commit_msg>Travis test changes cps-v2<commit_after>package cps

import (
	"testing"

	//cps "github.com/akamai/AkamaiOPEN-edgegrid-golang/cps-v2"
	"github.com/stretchr/testify/assert"
)

func TestSHAConversion(t *testing.T) {
	assert.NotEqual(t, "dosty", "everts")
	assert.Equal(t, SHA256, SHA("SHA-256"))
}
<|endoftext|>


<commit_before>package logical

import (
	"bytes"
	"encoding/json"
	"fmt"
	"time"
)

// This logic was pulled from the http package so that it can be used for
// encoding wrapped responses as well. It simply translates the logical request
// to an http response, with the values we want and omitting the values we
// don't.
func SanitizeResponse(input *Response) *HTTPResponse {
	logicalResp := &HTTPResponse{
		Data:     input.Data,
		Warnings: input.Warnings(),
	}

	if input.Secret != nil {
		logicalResp.LeaseID = input.Secret.LeaseID
		logicalResp.Renewable = input.Secret.Renewable
		logicalResp.LeaseDuration = int(input.Secret.TTL.Seconds())
	}

	// If we have authentication information, then
	// set up the result structure.
	if input.Auth != nil {
		logicalResp.Auth = &HTTPAuth{
			ClientToken:   input.Auth.ClientToken,
			Accessor:      input.Auth.Accessor,
			Policies:      input.Auth.Policies,
			Metadata:      input.Auth.Metadata,
			LeaseDuration: int(input.Auth.TTL.Seconds()),
			Renewable:     input.Auth.Renewable,
		}
	}

	return logicalResp
}

type HTTPResponse struct {
	RequestID     string                 `json:"request_id"`
	LeaseID       string                 `json:"lease_id"`
	Renewable     bool                   `json:"renewable"`
	LeaseDuration int                    `json:"lease_duration"`
	Data          map[string]interface{} `json:"data"`
	WrapInfo      *HTTPWrapInfo          `json:"wrap_info"`
	Warnings      []string               `json:"warnings"`
	Auth          *HTTPAuth              `json:"auth"`
}

type HTTPAuth struct {
	ClientToken   string            `json:"client_token"`
	Accessor      string            `json:"accessor"`
	Policies      []string          `json:"policies"`
	Metadata      map[string]string `json:"metadata"`
	LeaseDuration int               `json:"lease_duration"`
	Renewable     bool              `json:"renewable"`
}

type HTTPWrapInfo struct {
	Token           string    `json:"token"`
	TTL             int       `json:"ttl"`
	CreationTime    time.Time `json:"creation_time"`
	WrappedAccessor string    `json:"wrapped_accessor,omitempty"`
}

type HTTPSysInjector struct {
	Response *HTTPResponse
}

func (h HTTPSysInjector) MarshalJSON() ([]byte, error) {
	j, err := json.Marshal(h.Response)
	if err != nil {
		return nil, err
	}

	// Fast path no data or empty data
	if h.Response.Data == nil || len(h.Response.Data) == 0 {
		return j, nil
	}

	// Marshaling a response will always be a JSON object, meaning it will
	// always start with '{', so we hijack this to prepend necessary values

	// Make a guess at the capacity, and write the object opener
	buf := bytes.NewBuffer(make([]byte, 0, len(j)+len(h.Response.Data)*100))
	buf.WriteRune('{')

	for k, v := range h.Response.Data {
		// Marshal each key/value individually
		mk, err := json.Marshal(k)
		if err != nil {
			return nil, err
		}
		mv, err := json.Marshal(v)
		if err != nil {
			return nil, err
		}
		// Write into the final buffer. We'll never have a valid response
		// without any fields so we can unconditionally add a comma after each.
		buf.WriteString(fmt.Sprintf("%s: %s, ", mk, mv))
	}

	// Add the rest, without the first '{'
	buf.Write(j[1:])

	return buf.Bytes(), nil
}
<commit_msg>Use a better value for capacity<commit_after>package logical

import (
	"bytes"
	"encoding/json"
	"fmt"
	"time"
)

// This logic was pulled from the http package so that it can be used for
// encoding wrapped responses as well. It simply translates the logical request
// to an http response, with the values we want and omitting the values we
// don't.
func SanitizeResponse(input *Response) *HTTPResponse {
	logicalResp := &HTTPResponse{
		Data:     input.Data,
		Warnings: input.Warnings(),
	}

	if input.Secret != nil {
		logicalResp.LeaseID = input.Secret.LeaseID
		logicalResp.Renewable = input.Secret.Renewable
		logicalResp.LeaseDuration = int(input.Secret.TTL.Seconds())
	}

	// If we have authentication information, then
	// set up the result structure.
	if input.Auth != nil {
		logicalResp.Auth = &HTTPAuth{
			ClientToken:   input.Auth.ClientToken,
			Accessor:      input.Auth.Accessor,
			Policies:      input.Auth.Policies,
			Metadata:      input.Auth.Metadata,
			LeaseDuration: int(input.Auth.TTL.Seconds()),
			Renewable:     input.Auth.Renewable,
		}
	}

	return logicalResp
}

type HTTPResponse struct {
	RequestID     string                 `json:"request_id"`
	LeaseID       string                 `json:"lease_id"`
	Renewable     bool                   `json:"renewable"`
	LeaseDuration int                    `json:"lease_duration"`
	Data          map[string]interface{} `json:"data"`
	WrapInfo      *HTTPWrapInfo          `json:"wrap_info"`
	Warnings      []string               `json:"warnings"`
	Auth          *HTTPAuth              `json:"auth"`
}

type HTTPAuth struct {
	ClientToken   string            `json:"client_token"`
	Accessor      string            `json:"accessor"`
	Policies      []string          `json:"policies"`
	Metadata      map[string]string `json:"metadata"`
	LeaseDuration int               `json:"lease_duration"`
	Renewable     bool              `json:"renewable"`
}

type HTTPWrapInfo struct {
	Token           string    `json:"token"`
	TTL             int       `json:"ttl"`
	CreationTime    time.Time `json:"creation_time"`
	WrappedAccessor string    `json:"wrapped_accessor,omitempty"`
}

type HTTPSysInjector struct {
	Response *HTTPResponse
}

func (h HTTPSysInjector) MarshalJSON() ([]byte, error) {
	j, err := json.Marshal(h.Response)
	if err != nil {
		return nil, err
	}

	// Fast path no data or empty data
	if h.Response.Data == nil || len(h.Response.Data) == 0 {
		return j, nil
	}

	// Marshaling a response will always be a JSON object, meaning it will
	// always start with '{', so we hijack this to prepend necessary values

	// Make a guess at the capacity, and write the object opener
	buf := bytes.NewBuffer(make([]byte, 0, len(j)*2))
	buf.WriteRune('{')

	for k, v := range h.Response.Data {
		// Marshal each key/value individually
		mk, err := json.Marshal(k)
		if err != nil {
			return nil, err
		}
		mv, err := json.Marshal(v)
		if err != nil {
			return nil, err
		}
		// Write into the final buffer. We'll never have a valid response
		// without any fields so we can unconditionally add a comma after each.
		buf.WriteString(fmt.Sprintf("%s: %s, ", mk, mv))
	}

	// Add the rest, without the first '{'
	buf.Write(j[1:])

	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package supervisor

import (
	"fmt"
	"io"
	"os"
	"syscall"

	"github.com/golang/glog"
	"github.com/hyperhq/runv/hypervisor"
	"github.com/hyperhq/runv/hypervisor/types"
	"github.com/opencontainers/runtime-spec/specs-go"
)

type Process struct {
	Id     string
	Stdin  string
	Stdout string
	Stderr string
	Spec   *specs.Process
	ProcId int

	// inerId is Id or container id + "-init"
	// pass to hypervisor package and HyperPod.Processes
	inerId      string
	ownerCont   *Container
	init        bool
	stdio       *hypervisor.TtyIO
	stdinCloser io.Closer
}

func (p *Process) setupIO() error {
	glog.Infof("process setupIO: stdin %s, stdout %s, stderr %s", p.Stdin, p.Stdout, p.Stderr)

	// use a new go routine to avoid deadlock when stdin is fifo
	go func() {
		if stdinCloser, err := os.OpenFile(p.Stdin, syscall.O_WRONLY, 0); err == nil {
			p.stdinCloser = stdinCloser
		}
	}()

	stdin, err := os.OpenFile(p.Stdin, syscall.O_RDONLY, 0)
	if err != nil {
		return err
	}
	stdout, err := os.OpenFile(p.Stdout, syscall.O_RDWR, 0)
	if err != nil {
		return err
	}
	stderr, err := os.OpenFile(p.Stderr, syscall.O_RDWR, 0)
	if err != nil {
		return err
	}

	p.stdio = &hypervisor.TtyIO{
		Stdin:    stdin,
		Stdout:   stdout,
		Stderr:   stderr,
		Callback: make(chan *types.VmResponse, 1),
	}
	glog.Infof("process setupIO() success")

	return nil
}

func (p *Process) ttyResize(container string, width, height int) error {
	return p.ownerCont.ownerPod.vm.Tty(container, p.inerId, height, width)
}

func (p *Process) closeStdin() error {
	var err error
	if p.stdinCloser != nil {
		err = p.stdinCloser.Close()
		p.stdinCloser = nil
	}
	return err
}

func (p *Process) signal(sig int) error {
	if p.init {
		// TODO: change vm.KillContainer()
		return p.ownerCont.ownerPod.vm.KillContainer(p.ownerCont.Id, syscall.Signal(sig))
	} else {
		// TODO support it
		return fmt.Errorf("Kill to non-init process of container is unsupported")
	}
}

func (p *Process) reap() {
	p.closeStdin()
}
<commit_msg>Docker sets "execId" to containerId + "-init" when working from the command line with docker run. This led to runv being unable to find the referred TTY context when setWindowSize messages were received.<commit_after>package supervisor

import (
	"fmt"
	"io"
	"os"
	"syscall"

	"github.com/golang/glog"
	"github.com/hyperhq/runv/hypervisor"
	"github.com/hyperhq/runv/hypervisor/types"
	"github.com/opencontainers/runtime-spec/specs-go"
)

type Process struct {
	Id     string
	Stdin  string
	Stdout string
	Stderr string
	Spec   *specs.Process
	ProcId int

	// inerId is Id or container id + "-init"
	// pass to hypervisor package and HyperPod.Processes
	inerId      string
	ownerCont   *Container
	init        bool
	stdio       *hypervisor.TtyIO
	stdinCloser io.Closer
}

func (p *Process) setupIO() error {
	glog.Infof("process setupIO: stdin %s, stdout %s, stderr %s", p.Stdin, p.Stdout, p.Stderr)

	// use a new go routine to avoid deadlock when stdin is fifo
	go func() {
		if stdinCloser, err := os.OpenFile(p.Stdin, syscall.O_WRONLY, 0); err == nil {
			p.stdinCloser = stdinCloser
		}
	}()

	stdin, err := os.OpenFile(p.Stdin, syscall.O_RDONLY, 0)
	if err != nil {
		return err
	}
	stdout, err := os.OpenFile(p.Stdout, syscall.O_RDWR, 0)
	if err != nil {
		return err
	}
	stderr, err := os.OpenFile(p.Stderr, syscall.O_RDWR, 0)
	if err != nil {
		return err
	}

	p.stdio = &hypervisor.TtyIO{
		Stdin:    stdin,
		Stdout:   stdout,
		Stderr:   stderr,
		Callback: make(chan *types.VmResponse, 1),
	}
	glog.Infof("process setupIO() success")

	return nil
}

func (p *Process) ttyResize(container string, width, height int) error {
	// If working on the primary process, do not pass execId (it won't be recognized)
	if p.inerId == fmt.Sprintf("%s-init", container) {
		return p.ownerCont.ownerPod.vm.Tty(container, "", height, width)
	}
	return p.ownerCont.ownerPod.vm.Tty(container, p.inerId, height, width)
}

func (p *Process) closeStdin() error {
	var err error
	if p.stdinCloser != nil {
		err = p.stdinCloser.Close()
		p.stdinCloser = nil
	}
	return err
}

func (p *Process) signal(sig int) error {
	if p.init {
		// TODO: change vm.KillContainer()
		return p.ownerCont.ownerPod.vm.KillContainer(p.ownerCont.Id, syscall.Signal(sig))
	} else {
		// TODO support it
		return fmt.Errorf("Kill to non-init process of container is unsupported")
	}
}

func (p *Process) reap() {
	p.closeStdin()
}
<|endoftext|>


<commit_before>package mattermostTransport

import (
	"github.com/mattermost/mattermost-server/model"
	"github.com/pawelszydlo/papa-bot/events"
)

// connect will establish a connection to the server.
func (transport *MattermostTransport) connect() {
	// Create the client.
	transport.client = model.NewAPIv4Client(transport.server)

	// Check server connection
	if props, response := transport.client.GetOldClientConfig(""); response.Error != nil {
		transport.log.Fatalf("Couldn't connect to Mattermost at %s.", transport.server)
	} else {
		transport.log.Infof("Connected to %s, running version %s.", transport.server, props["Version"])
	}

	// Login.
	if user, response := transport.client.Login(transport.user, transport.password); response.Error != nil {
		transport.log.Fatalf("Login failed as %s.", transport.user)
	} else {
		transport.mmUser = user
		transport.log.Infof("Logged in as %s (%s).", user.Username, user.Id)
	}
	transport.sendEvent(events.EventConnected, "", true, "", transport.botName, transport.mmUser.Id, "")
}

// Run will execute the main loop.
func (transport *MattermostTransport) Run() {
	transport.connect()
	transport.updateInfo()
	transport.updateStatus()

	// Register bot event listeners.
	transport.eventDispatcher.RegisterListener(events.EventBotWorking, transport.typingListener)

	// Register transport event handlers.
	transport.registerAllEventHandlers()

	// Start websocket for communication.
	webClient, err := model.NewWebSocketClient4(transport.websocket, transport.client.AuthToken)
	if err != nil {
		transport.log.Fatalf("Failed to connect to the web socket at %s: %s", transport.websocket, err)
	} else {
		transport.webSocketClient = webClient
	}

	transport.webSocketClient.Listen()

	// Main loop.
	for {
		select {
		case event, ok := <-transport.webSocketClient.EventChannel:
			if ok {
				// Are there any handlers registered for this event?
				if handlers, exists := transport.eventHandlers[event.Event]; exists {
					for _, handler := range handlers {
						handler(event)
					}
				} else { // No handler for this type of event.
					// transport.log.Debugf("No handler for event: %s", event.Event)
				}
			} else {
				break
			}
		}
	}

	transport.log.Infof("Mattermost transport exiting...")
}
<commit_msg>Mattermost keepalive<commit_after>package mattermostTransport

import (
	"github.com/mattermost/mattermost-server/model"
	"github.com/pawelszydlo/papa-bot/events"
)

// connect will establish a connection to the server.
func (transport *MattermostTransport) connect() {
	// Create the client.
	transport.client = model.NewAPIv4Client(transport.server)

	// Check server connection
	if props, response := transport.client.GetOldClientConfig(""); response.Error != nil {
		transport.log.Fatalf("Couldn't connect to Mattermost at %s.", transport.server)
	} else {
		transport.log.Infof("Connected to %s, running version %s.", transport.server, props["Version"])
	}

	// Login.
	if user, response := transport.client.Login(transport.user, transport.password); response.Error != nil {
		transport.log.Fatalf("Login failed as %s.", transport.user)
	} else {
		transport.mmUser = user
		transport.log.Infof("Logged in as %s (%s).", user.Username, user.Id)
	}
	transport.sendEvent(events.EventConnected, "", true, "", transport.botName, transport.mmUser.Id, "")
}

// create a websocket connection and set it for the client.
func (transport *MattermostTransport) connectWebsocket() {
	// Start websocket for communication.
	webClient, err := model.NewWebSocketClient4(transport.websocket, transport.client.AuthToken)
	if err != nil {
		transport.log.Fatalf("Failed to connect to the web socket at %s: %s", transport.websocket, err)
	} else {
		transport.webSocketClient = webClient
	}
	transport.webSocketClient.Listen()
}

// Run will execute the main loop.
func (transport *MattermostTransport) Run() {
	transport.connect()
	transport.updateInfo()
	transport.updateStatus()

	// Register bot event listeners.
	transport.eventDispatcher.RegisterListener(events.EventBotWorking, transport.typingListener)

	// Register transport event handlers.
	transport.registerAllEventHandlers()

	// Connect websocket for actual message transfer.
	transport.connectWebsocket()

	// Main loop.
	for {
		select {
		case timeout := <-transport.webSocketClient.PingTimeoutChannel:
			if timeout {
				transport.log.Errorf(
					"Mattermost disconected: %s. Reconnecting...", transport.webSocketClient.ListenError)
				transport.connectWebsocket()
			}
		case event, ok := <-transport.webSocketClient.EventChannel:
			if ok {
				// Are there any handlers registered for this event?
				if handlers, exists := transport.eventHandlers[event.Event]; exists {
					for _, handler := range handlers {
						handler(event)
					}
				} else { // No handler for this type of event.
					// transport.log.Debugf("No handler for event: %s", event.Event)
				}
			} else {
				break
			}
		}
	}

	transport.log.Infof("Mattermost transport exiting...")
}
<|endoftext|>


<commit_before>package lnwire

// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
)

// MaxMessagePayload is the maximum bytes a message can be regardless of other
// individual limits imposed by messages themselves.
const MaxMessagePayload = 65535 // 65KB

// MessageType is the unique 2 byte big-endian integer that indicates the type
// of message on the wire. All messages have a very simple header which
// consists simply of 2-byte message type. We omit a length field, and checksum
// as the Lighting Protocol is intended to be encapsulated within a
// confidential+authenticated cryptographic messaging protocol.
type MessageType uint16

// The currently defined message types within this current version of the
// Lightning protocol.
const (
	MsgInit                      MessageType = 16
	MsgError                                 = 17
	MsgPing                                  = 18
	MsgPong                                  = 19
	MsgSingleFundingRequest                  = 32
	MsgSingleFundingResponse                 = 33
	MsgSingleFundingComplete                 = 34
	MsgSingleFundingSignComplete             = 35
	MsgFundingLocked                         = 36
	MsgShutdown                              = 39
	MsgClosingSigned                         = 40
	MsgUpdateAddHTLC                         = 128
	MsgUpdateFufillHTLC                      = 130
	MsgUpdateFailHTLC                        = 131
	MsgCommitSig                             = 132
	MsgRevokeAndAck                          = 133
	MsgUpdateFailMalformedHTLC               = 135
	MsgUpdateFee                             = 137
	MsgChannelAnnouncement                   = 256
	MsgNodeAnnouncement                      = 257
	MsgChannelUpdate                         = 258
	MsgAnnounceSignatures                    = 259
)

// String return the string representation of message type.
func (t MessageType) String() string {
	switch t {
	case MsgInit:
		return "Init"
	case MsgSingleFundingRequest:
		return "SingleFundingRequest"
	case MsgSingleFundingResponse:
		return "SingleFundingResponse"
	case MsgSingleFundingComplete:
		return "SingleFundingComplete"
	case MsgSingleFundingSignComplete:
		return "SingleFundingSignComplete"
	case MsgFundingLocked:
		return "FundingLocked"
	case MsgShutdown:
		return "Shutdown"
	case MsgClosingSigned:
		return "ClosingSigned"
	case MsgUpdateAddHTLC:
		return "UpdateAddHTLC"
	case MsgUpdateFailHTLC:
		return "UpdateFailHTLC"
	case MsgUpdateFufillHTLC:
		return "UpdateFufillHTLC"
	case MsgCommitSig:
		return "CommitSig"
	case MsgRevokeAndAck:
		return "RevokeAndAck"
	case MsgUpdateFailMalformedHTLC:
		return "UpdateFailMalformedHTLC"
	case MsgError:
		return "Error"
	case MsgChannelAnnouncement:
		return "ChannelAnnouncement"
	case MsgChannelUpdate:
		return "ChannelUpdate"
	case MsgNodeAnnouncement:
		return "NodeAnnouncement"
	case MsgPing:
		return "Ping"
	case MsgAnnounceSignatures:
		return "AnnounceSignatures"
	case MsgPong:
		return "Pong"
	default:
		return "<unknown>"
	}
}

// UnknownMessage is an implementation of the error interface that allows the
// creation of an error in response to an unknown message.
type UnknownMessage struct {
	messageType MessageType
}

// Error returns a human readable string describing the error.
//
// This is part of the error interface.
func (u *UnknownMessage) Error() string {
	return fmt.Sprintf("unable to parse message of unknown type: %v",
		u.messageType)
}

// Serializable is an interface which defines a lightning wire serializable
// object.
type Serializable interface {
	// Decode reads the bytes stream and converts it to the object.
	Decode(io.Reader, uint32) error

	// Encode converts object to the bytes stream and write it in th writer.
	Encode(io.Writer, uint32) error
}

// Message is an interface that defines a lightning wire protocol message. The
// interface is general in order to allow implementing types full control over
// the representation of its data.
type Message interface {
	Serializable
	MsgType() MessageType
	MaxPayloadLength(uint32) uint32
}

// makeEmptyMessage creates a new empty message of the proper concrete type
// based on the passed message type.
func makeEmptyMessage(msgType MessageType) (Message, error) {
	var msg Message

	switch msgType {
	case MsgInit:
		msg = &Init{}
	case MsgSingleFundingRequest:
		msg = &SingleFundingRequest{}
	case MsgSingleFundingResponse:
		msg = &SingleFundingResponse{}
	case MsgSingleFundingComplete:
		msg = &SingleFundingComplete{}
	case MsgSingleFundingSignComplete:
		msg = &SingleFundingSignComplete{}
	case MsgFundingLocked:
		msg = &FundingLocked{}
	case MsgShutdown:
		msg = &Shutdown{}
	case MsgClosingSigned:
		msg = &ClosingSigned{}
	case MsgUpdateAddHTLC:
		msg = &UpdateAddHTLC{}
	case MsgUpdateFailHTLC:
		msg = &UpdateFailHTLC{}
	case MsgUpdateFufillHTLC:
		msg = &UpdateFufillHTLC{}
	case MsgCommitSig:
		msg = &CommitSig{}
	case MsgRevokeAndAck:
		msg = &RevokeAndAck{}
	case MsgUpdateFee:
		msg = &UpdateFee{}
	case MsgUpdateFailMalformedHTLC:
		msg = &UpdateFailMalformedHTLC{}
	case MsgError:
		msg = &Error{}
	case MsgChannelAnnouncement:
		msg = &ChannelAnnouncement{}
	case MsgChannelUpdate:
		msg = &ChannelUpdate{}
	case MsgNodeAnnouncement:
		msg = &NodeAnnouncement{}
	case MsgPing:
		msg = &Ping{}
	case MsgAnnounceSignatures:
		msg = &AnnounceSignatures{}
	case MsgPong:
		msg = &Pong{}
	default:
		return nil, fmt.Errorf("unknown message type [%d]", msgType)
	}

	return msg, nil
}

// WriteMessage writes a lightning Message to w including the necessary header
// information and returns the number of bytes written.
func WriteMessage(w io.Writer, msg Message, pver uint32) (int, error) {
	totalBytes := 0

	// Encode the message payload itself into a temporary buffer.
	// TODO(roasbeef): create buffer pool
	var bw bytes.Buffer
	if err := msg.Encode(&bw, pver); err != nil {
		return totalBytes, err
	}
	payload := bw.Bytes()
	lenp := len(payload)

	// Enforce maximum overall message payload.
	if lenp > MaxMessagePayload {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload is %d bytes",
			lenp, MaxMessagePayload)
	}

	// Enforce maximum message payload on the message type.
	mpl := msg.MaxPayloadLength(pver)
	if uint32(lenp) > mpl {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload of "+
			"type %x is %d bytes", lenp, msg.MsgType(), mpl)
	}

	// With the initial sanity checks complete, we'll now write out the
	// message type itself.
	var mType [2]byte
	binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType()))
	n, err := w.Write(mType[:])
	totalBytes += n
	if err != nil {
		return totalBytes, err
	}

	// With the message type written, we'll now write out the raw payload
	// itself.
	n, err = w.Write(payload)
	totalBytes += n

	return totalBytes, err
}

// ReadMessage reads, validates, and parses the next Lightning message from r
// for the provided protocol version.
func ReadMessage(r io.Reader, pver uint32) (Message, error) {
	// First, we'll read out the first two bytes of the message so we can
	// create the proper empty message.
	var mType [2]byte
	if _, err := io.ReadFull(r, mType[:]); err != nil {
		return nil, err
	}

	msgType := MessageType(binary.BigEndian.Uint16(mType[:]))

	// Now that we know the target message type, we can create the proper
	// empty message type and decode the message into it.
	msg, err := makeEmptyMessage(msgType)
	if err != nil {
		return nil, err
	}
	if err := msg.Decode(r, pver); err != nil {
		return nil, err
	}

	return msg, nil
}
<commit_msg>lnwire: update MessageType definition to include new funding messages<commit_after>package lnwire

// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
)

// MaxMessagePayload is the maximum bytes a message can be regardless of other
// individual limits imposed by messages themselves.
const MaxMessagePayload = 65535 // 65KB

// MessageType is the unique 2 byte big-endian integer that indicates the type
// of message on the wire. All messages have a very simple header which
// consists simply of 2-byte message type. We omit a length field, and checksum
// as the Lighting Protocol is intended to be encapsulated within a
// confidential+authenticated cryptographic messaging protocol.
type MessageType uint16

// The currently defined message types within this current version of the
// Lightning protocol.
const (
	MsgInit                    MessageType = 16
	MsgError                               = 17
	MsgPing                                = 18
	MsgPong                                = 19
	MsgOpenChannel                         = 32
	MsgAcceptChannel                       = 33
	MsgFundingCreated                      = 34
	MsgFundingSigned                       = 35
	MsgFundingLocked                       = 36
	MsgShutdown                            = 39
	MsgClosingSigned                       = 40
	MsgUpdateAddHTLC                       = 128
	MsgUpdateFufillHTLC                    = 130
	MsgUpdateFailHTLC                      = 131
	MsgCommitSig                           = 132
	MsgRevokeAndAck                        = 133
	MsgUpdateFailMalformedHTLC             = 135
	MsgUpdateFee                           = 137
	MsgChannelAnnouncement                 = 256
	MsgNodeAnnouncement                    = 257
	MsgChannelUpdate                       = 258
	MsgAnnounceSignatures                  = 259
)

// String return the string representation of message type.
func (t MessageType) String() string {
	switch t {
	case MsgInit:
		return "Init"
	case MsgOpenChannel:
		return "MsgOpenChannel"
	case MsgAcceptChannel:
		return "MsgAcceptChannel"
	case MsgFundingCreated:
		return "MsgFundingCreated"
	case MsgFundingSigned:
		return "MsgFundingSigned"
	case MsgFundingLocked:
		return "FundingLocked"
	case MsgShutdown:
		return "Shutdown"
	case MsgClosingSigned:
		return "ClosingSigned"
	case MsgUpdateAddHTLC:
		return "UpdateAddHTLC"
	case MsgUpdateFailHTLC:
		return "UpdateFailHTLC"
	case MsgUpdateFufillHTLC:
		return "UpdateFufillHTLC"
	case MsgCommitSig:
		return "CommitSig"
	case MsgRevokeAndAck:
		return "RevokeAndAck"
	case MsgUpdateFailMalformedHTLC:
		return "UpdateFailMalformedHTLC"
	case MsgError:
		return "Error"
	case MsgChannelAnnouncement:
		return "ChannelAnnouncement"
	case MsgChannelUpdate:
		return "ChannelUpdate"
	case MsgNodeAnnouncement:
		return "NodeAnnouncement"
	case MsgPing:
		return "Ping"
	case MsgAnnounceSignatures:
		return "AnnounceSignatures"
	case MsgPong:
		return "Pong"
	default:
		return "<unknown>"
	}
}

// UnknownMessage is an implementation of the error interface that allows the
// creation of an error in response to an unknown message.
type UnknownMessage struct {
	messageType MessageType
}

// Error returns a human readable string describing the error.
//
// This is part of the error interface.
func (u *UnknownMessage) Error() string {
	return fmt.Sprintf("unable to parse message of unknown type: %v",
		u.messageType)
}

// Serializable is an interface which defines a lightning wire serializable
// object.
type Serializable interface {
	// Decode reads the bytes stream and converts it to the object.
	Decode(io.Reader, uint32) error

	// Encode converts object to the bytes stream and write it into the
	// writer.
	Encode(io.Writer, uint32) error
}

// Message is an interface that defines a lightning wire protocol message. The
// interface is general in order to allow implementing types full control over
// the representation of its data.
type Message interface {
	Serializable
	MsgType() MessageType
	MaxPayloadLength(uint32) uint32
}

// makeEmptyMessage creates a new empty message of the proper concrete type
// based on the passed message type.
func makeEmptyMessage(msgType MessageType) (Message, error) {
	var msg Message

	switch msgType {
	case MsgInit:
		msg = &Init{}
	case MsgOpenChannel:
		msg = &OpenChannel{}
	case MsgAcceptChannel:
		msg = &AcceptChannel{}
	case MsgFundingCreated:
		msg = &FundingCreated{}
	case MsgFundingSigned:
		msg = &FundingSigned{}
	case MsgFundingLocked:
		msg = &FundingLocked{}
	case MsgShutdown:
		msg = &Shutdown{}
	case MsgClosingSigned:
		msg = &ClosingSigned{}
	case MsgUpdateAddHTLC:
		msg = &UpdateAddHTLC{}
	case MsgUpdateFailHTLC:
		msg = &UpdateFailHTLC{}
	case MsgUpdateFufillHTLC:
		msg = &UpdateFufillHTLC{}
	case MsgCommitSig:
		msg = &CommitSig{}
	case MsgRevokeAndAck:
		msg = &RevokeAndAck{}
	case MsgUpdateFee:
		msg = &UpdateFee{}
	case MsgUpdateFailMalformedHTLC:
		msg = &UpdateFailMalformedHTLC{}
	case MsgError:
		msg = &Error{}
	case MsgChannelAnnouncement:
		msg = &ChannelAnnouncement{}
	case MsgChannelUpdate:
		msg = &ChannelUpdate{}
	case MsgNodeAnnouncement:
		msg = &NodeAnnouncement{}
	case MsgPing:
		msg = &Ping{}
	case MsgAnnounceSignatures:
		msg = &AnnounceSignatures{}
	case MsgPong:
		msg = &Pong{}
	default:
		return nil, fmt.Errorf("unknown message type [%d]", msgType)
	}

	return msg, nil
}

// WriteMessage writes a lightning Message to w including the necessary header
// information and returns the number of bytes written.
func WriteMessage(w io.Writer, msg Message, pver uint32) (int, error) {
	totalBytes := 0

	// Encode the message payload itself into a temporary buffer.
	// TODO(roasbeef): create buffer pool
	var bw bytes.Buffer
	if err := msg.Encode(&bw, pver); err != nil {
		return totalBytes, err
	}
	payload := bw.Bytes()
	lenp := len(payload)

	// Enforce maximum overall message payload.
	if lenp > MaxMessagePayload {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload is %d bytes",
			lenp, MaxMessagePayload)
	}

	// Enforce maximum message payload on the message type.
	mpl := msg.MaxPayloadLength(pver)
	if uint32(lenp) > mpl {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload of "+
			"type %x is %d bytes", lenp, msg.MsgType(), mpl)
	}

	// With the initial sanity checks complete, we'll now write out the
	// message type itself.
	var mType [2]byte
	binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType()))
	n, err := w.Write(mType[:])
	totalBytes += n
	if err != nil {
		return totalBytes, err
	}

	// With the message type written, we'll now write out the raw payload
	// itself.
	n, err = w.Write(payload)
	totalBytes += n

	return totalBytes, err
}

// ReadMessage reads, validates, and parses the next Lightning message from r
// for the provided protocol version.
func ReadMessage(r io.Reader, pver uint32) (Message, error) {
	// First, we'll read out the first two bytes of the message so we can
	// create the proper empty message.
	var mType [2]byte
	if _, err := io.ReadFull(r, mType[:]); err != nil {
		return nil, err
	}

	msgType := MessageType(binary.BigEndian.Uint16(mType[:]))

	// Now that we know the target message type, we can create the proper
	// empty message type and decode the message into it.
	msg, err := makeEmptyMessage(msgType)
	if err != nil {
		return nil, err
	}
	if err := msg.Decode(r, pver); err != nil {
		return nil, err
	}

	return msg, nil
}
<|endoftext|>


<commit_before>package main

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

var (
	GrubPaths = []string{
		// grub2
		"boot/grub2/grub.cfg",
		"boot/grub2.cfg",
		"grub2/grub.cfg",
		"grub2.cfg",
		// grub legacy
		"boot/grub/grub.cfg",
		"boot/grub.cfg",
		"grub/grub.cfg",
		"grub.cfg",
	}
)

// ParseGrubCfg parses the content of a grub.cfg and returns a list of
// BootConfig structures, one for each menuentry, in the same order as they
// appear in grub.cfg. All opened kernel and initrd files are relative to
// basedir.
func ParseGrubCfg(grubcfg string, basedir string) []BootConfig {
	// This parser sucks. It's not even a parser, it just looks for lines
	// starting with menuentry, linux or initrd.
	// TODO use a parser, e.g. https://github.com/alecthomas/participle
	bootconfigs := make([]BootConfig, 0)
	inMenuEntry := false
	var cfg *BootConfig
	for _, line := range strings.Split(grubcfg, "\n") {
		// remove all leading spaces as they are not relevant for the config
		// line
		line = strings.TrimLeft(line, " ")
		sline := strings.Fields(line)
		if len(sline) == 0 {
			continue
		}
		if sline[0] == "menuentry" {
			// if a "menuentry", start a new boot config
			if cfg != nil {
				// save the previous boot config, if any
				if cfg.IsValid() {
					// only consider valid boot configs, i.e. the ones that have
					// both kernel and initramfs
					bootconfigs = append(bootconfigs, *cfg)
				}
			}
			inMenuEntry = true
			cfg = new(BootConfig)
		} else if inMenuEntry {
			// otherwise look for kernel and initramfs configuration
			if len(sline) < 2 {
				// surely not a valid linux or initrd directive, skip it
				continue
			}
			if sline[0] == "linux" || sline[0] == "linux16" {
				kernel := sline[1]
				cmdline := strings.Join(sline[2:], " ")
				fullpath := path.Join(basedir, kernel)
				fd, err := os.Open(fullpath)
				if err != nil {
					debug("error opening kernel file %s: %v", fullpath, err)
				}
				cfg.Kernel = fd
				cfg.KernelName = kernel
				cfg.Cmdline = cmdline
			} else if sline[0] == "initrd" || sline[0] == "initrd16" {
				initrd := sline[1]
				fullpath := path.Join(basedir, initrd)
				fd, err := os.Open(fullpath)
				if err != nil {
					debug("error opening initrd file %s: %v", fullpath, err)
				}
				cfg.Initrd = fd
				cfg.InitrdName = initrd
			}
		}
	}
	// append last kernel config if it wasn't already
	if inMenuEntry && cfg.IsValid() {
		bootconfigs = append(bootconfigs, *cfg)
	}
	return bootconfigs
}
<commit_msg>grub parser supports linuxefi and initrdefi too<commit_after>package main

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

var (
	GrubPaths = []string{
		// grub2
		"boot/grub2/grub.cfg",
		"boot/grub2.cfg",
		"grub2/grub.cfg",
		"grub2.cfg",
		// grub legacy
		"boot/grub/grub.cfg",
		"boot/grub.cfg",
		"grub/grub.cfg",
		"grub.cfg",
	}
)

// ParseGrubCfg parses the content of a grub.cfg and returns a list of
// BootConfig structures, one for each menuentry, in the same order as they
// appear in grub.cfg. All opened kernel and initrd files are relative to
// basedir.
func ParseGrubCfg(grubcfg string, basedir string) []BootConfig {
	// This parser sucks. It's not even a parser, it just looks for lines
	// starting with menuentry, linux or initrd.
	// TODO use a parser, e.g. https://github.com/alecthomas/participle
	bootconfigs := make([]BootConfig, 0)
	inMenuEntry := false
	var cfg *BootConfig
	for _, line := range strings.Split(grubcfg, "\n") {
		// remove all leading spaces as they are not relevant for the config
		// line
		line = strings.TrimLeft(line, " ")
		sline := strings.Fields(line)
		if len(sline) == 0 {
			continue
		}
		if sline[0] == "menuentry" {
			// if a "menuentry", start a new boot config
			if cfg != nil {
				// save the previous boot config, if any
				if cfg.IsValid() {
					// only consider valid boot configs, i.e. the ones that have
					// both kernel and initramfs
					bootconfigs = append(bootconfigs, *cfg)
				}
			}
			inMenuEntry = true
			cfg = new(BootConfig)
		} else if inMenuEntry {
			// otherwise look for kernel and initramfs configuration
			if len(sline) < 2 {
				// surely not a valid linux or initrd directive, skip it
				continue
			}
			if sline[0] == "linux" || sline[0] == "linux16" || sline[0] == "linuxefi" {
				kernel := sline[1]
				cmdline := strings.Join(sline[2:], " ")
				fullpath := path.Join(basedir, kernel)
				fd, err := os.Open(fullpath)
				if err != nil {
					debug("error opening kernel file %s: %v", fullpath, err)
				}
				cfg.Kernel = fd
				cfg.KernelName = kernel
				cfg.Cmdline = cmdline
			} else if sline[0] == "initrd" || sline[0] == "initrd16" || sline[0] == "initrdefi" {
				initrd := sline[1]
				fullpath := path.Join(basedir, initrd)
				fd, err := os.Open(fullpath)
				if err != nil {
					debug("error opening initrd file %s: %v", fullpath, err)
				}
				cfg.Initrd = fd
				cfg.InitrdName = initrd
			}
		}
	}
	// append last kernel config if it wasn't already
	if inMenuEntry && cfg.IsValid() {
		bootconfigs = append(bootconfigs, *cfg)
	}
	return bootconfigs
}
<|endoftext|>


<commit_before>// This file is build-tag protected because it involves loading an external
// library (xmlpath)
package libxml2_test

import (
	"bytes"
	"encoding/xml"
	"log"
	"net/http"
	"testing"

	"github.com/go-xmlpath/xmlpath"
	"github.com/lestrrat/go-libxml2"
)

func BenchmarkXmlpath_Xmlpath(b *testing.B) {
	res, err := http.Get("http://mattn.kaoriya.net/index.xml")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	root, err := xmlpath.Parse(res.Body)
	if err != nil {
		log.Fatal(err)
	}
	for i := 0; i < b.N; i++ {
		p, err := xmlpath.Compile(`//loc`)
		if err != nil {
			log.Fatal(err)
		}
		it := p.Iter(root)
		for it.Next() {
			_ = it.Node()
		}
	}
}

func BenchmarkXmlpath_Libxml2(b *testing.B) {
	res, err := http.Get("http://mattn.kaoriya.net/index.xml")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	doc, err := libxml2.ParseReader(res.Body)
	if err != nil {
		log.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		nodes, _ := doc.FindNodes(`//loc`)
		for _, n := range nodes {
			_ = n
		}
	}
}

type Foo struct {
	XMLName xml.Name `xml:"https://github.com/lestrrat/go-libxml2/foo foo:foo"`
	Field1  string
}

func BenchmarkDOM_EncodingXml(b *testing.B) {
	var buf bytes.Buffer
	f := Foo{
		Field1: "Hello, World!",
	}
	for i := 0; i < b.N; i++ {
		buf.Reset()
		enc := xml.NewEncoder(&buf)
		enc.Encode(f)
	}
}

func BenchmarkDOM_Libxml2(b *testing.B) {
	var buf bytes.Buffer
	const nsuri = `https://github.com/lestrrat/go-libxml2/foo`
	f := Foo{
		Field1: "Hello, World!",
	}
	for i := 0; i < b.N; i++ {
		d := libxml2.CreateDocument()
		defer d.Free()

		root, err := d.CreateElementNS(nsuri, "foo:foo")
		if err != nil {
			panic(err)
		}
		d.SetDocumentElement(root)

		f1xml, err := d.CreateElement("Field1")
		if err != nil {
			panic(err)
		}
		root.AddChild(f1xml)

		f1xml.AppendText(f.Field1)
		buf.Reset()
		buf.WriteString(d.Dump(false))
	}
}
<commit_msg>fix path<commit_after>// This file is build-tag protected because it involves loading an external
// library (xmlpath)
package libxml2_test

import (
	"bytes"
	"encoding/xml"
	"log"
	"net/http"
	"testing"

	"github.com/lestrrat/go-libxml2"
	"gopkg.in/xmlpath.v1"
)

func BenchmarkXmlpath_Xmlpath(b *testing.B) {
	res, err := http.Get("http://mattn.kaoriya.net/index.xml")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	root, err := xmlpath.Parse(res.Body)
	if err != nil {
		log.Fatal(err)
	}
	for i := 0; i < b.N; i++ {
		p, err := xmlpath.Compile(`//loc`)
		if err != nil {
			log.Fatal(err)
		}
		it := p.Iter(root)
		for it.Next() {
			_ = it.Node()
		}
	}
}

func BenchmarkXmlpath_Libxml2(b *testing.B) {
	res, err := http.Get("http://mattn.kaoriya.net/index.xml")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	doc, err := libxml2.ParseReader(res.Body)
	if err != nil {
		log.Fatal(err)
	}

	for i := 0; i < b.N; i++ {
		nodes, _ := doc.FindNodes(`//loc`)
		for _, n := range nodes {
			_ = n
		}
	}
}

type Foo struct {
	XMLName xml.Name `xml:"https://github.com/lestrrat/go-libxml2/foo foo:foo"`
	Field1  string
}

func BenchmarkDOM_EncodingXml(b *testing.B) {
	var buf bytes.Buffer
	f := Foo{
		Field1: "Hello, World!",
	}
	for i := 0; i < b.N; i++ {
		buf.Reset()
		enc := xml.NewEncoder(&buf)
		enc.Encode(f)
	}
}

func BenchmarkDOM_Libxml2(b *testing.B) {
	var buf bytes.Buffer
	const nsuri = `https://github.com/lestrrat/go-libxml2/foo`
	f := Foo{
		Field1: "Hello, World!",
	}
	for i := 0; i < b.N; i++ {
		d := libxml2.CreateDocument()
		defer d.Free()

		root, err := d.CreateElementNS(nsuri, "foo:foo")
		if err != nil {
			panic(err)
		}
		d.SetDocumentElement(root)

		f1xml, err := d.CreateElement("Field1")
		if err != nil {
			panic(err)
		}
		root.AddChild(f1xml)

		f1xml.AppendText(f.Field1)
		buf.Reset()
		buf.WriteString(d.Dump(false))
	}
}
<|endoftext|>


<commit_before>package addon

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strings"

	"github.com/ponzu-cms/ponzu/system/db"
	"github.com/ponzu-cms/ponzu/system/item"
)

var (
	// Types is a record of addons, like content types, of addon_reverse_dns:interface{}
	Types = make(map[string]func() interface{})
)

const (
	// StatusEnabled defines string status for Addon enabled state
	StatusEnabled = "enabled"
	// StatusDisabled defines string status for Addon disabled state
	StatusDisabled = "disabled"
)

// Meta contains the basic information about the addon
type Meta struct {
	PonzuAddonName       string `json:"addon_name"`
	PonzuAddonAuthor     string `json:"addon_author"`
	PonzuAddonAuthorURL  string `json:"addon_author_url"`
	PonzuAddonVersion    string `json:"addon_version"`
	PonzuAddonReverseDNS string `json:"addon_reverse_dns"`
	PonzuAddonStatus     string `json:"addon_status"`
}

// Addon contains information about a provided addon to the system
type Addon struct {
	item.Item
	Meta
}

// New constructs a new addon to be registered. Meta is a addon.Meta and fn is a
// closure returning a pointer to your own addon type
func New(m Meta, fn func() interface{}) Addon {
	// get or create the reverse DNS identifier
	if m.PonzuAddonReverseDNS == "" {
		revDNS, err := reverseDNS(m)
		if err != nil {
			panic(err)
		}

		m.PonzuAddonReverseDNS = revDNS
	}

	Types[m.PonzuAddonReverseDNS] = fn

	a := Addon{Meta: m}

	err := register(a)
	if err != nil {
		panic(err)
	}

	return a
}

// register sets up the system to use the Addon by:
// 1. Validating the Addon struct
// 2. Checking that the Addon parent type was added to Types (via its New())
// 3. Saving it to the __addons bucket in DB with id/key = addon_reverse_dns
func register(a Addon) error {
	if a.PonzuAddonName == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonName")
	}
	if a.PonzuAddonAuthor == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonAuthor")
	}
	if a.PonzuAddonAuthorURL == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonAuthorURL")
	}
	if a.PonzuAddonVersion == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonVersion")
	}

	if _, ok := Types[a.PonzuAddonReverseDNS]; !ok {
		return fmt.Errorf(`Addon "%s" has no record in the addons.Types map`, a.PonzuAddonName)
	}

	// check if addon is already registered in db as addon_reverse_dns
	if db.AddonExists(a.PonzuAddonReverseDNS) {
		return nil
	}

	// convert a.Item into usable data, Item{} => []byte(json) => map[string]interface{}
	kv := make(map[string]interface{})

	data, err := json.Marshal(a.Item)
	if err != nil {
		return err
	}

	err = json.Unmarshal(data, &kv)
	if err != nil {
		return err
	}

	// save new addon to db
	vals := make(url.Values)
	for k, v := range kv {
		vals.Set(k, v.(string))
	}

	vals.Set("addon_name", a.PonzuAddonName)
	vals.Set("addon_author", a.PonzuAddonAuthor)
	vals.Set("addon_author_url", a.PonzuAddonAuthorURL)
	vals.Set("addon_version", a.PonzuAddonVersion)
	vals.Set("addon_reverse_dns", a.PonzuAddonReverseDNS)
	vals.Set("addon_status", StatusDisabled)

	// db.SetAddon is like SetContent, but rather than the key being an int64 ID,
	// we need it to be a string based on the addon_reverse_dns
	err = db.SetAddon(vals)
	if err != nil {
		return err
	}

	return nil
}

// Deregister removes an addon from the system. `key` is the addon_reverse_dns
func Deregister(key string) error {
	err := db.DeleteAddon(key)
	if err != nil {
		return err
	}

	delete(Types, key)
	return nil
}

// Enable sets the addon status to `enabled`. `key` is the addon_reverse_dns
func Enable(key string) error {
	err := setStatus(key, StatusEnabled)
	if err != nil {
		return err
	}

	return nil
}

// Disable sets the addon status to `disabled`. `key` is the addon_reverse_dns
func Disable(key string) error {
	err := setStatus(key, StatusDisabled)
	if err != nil {
		return err
	}

	return nil
}

func setStatus(key, status string) error {
	a, err := db.Addon(key)
	if err != nil {
		return err
	}

	a.Set("addon_status", status)

	err = db.SetAddon(a)
	if err != nil {
		return err
	}

	return nil
}

func reverseDNS(meta Meta) (string, error) {
	u, err := url.Parse(meta.PonzuAddonAuthorURL)
	if err != nil {
		return "", nil
	}

	if u.Host == "" {
		return "", fmt.Errorf(`Error parsing Addon Author URL: %s. Ensure URL is formatted as "scheme://hostname/path?query" (path & query optional)`, meta.PonzuAddonAuthorURL)
	}

	name := strings.Replace(meta.PonzuAddonName, " ", "", -1)

	// reverse the host name parts, split on '.', ex. bosssauce.it => it.bosssauce
	parts := strings.Split(u.Host, ".")
	strap := make([]string, len(parts), len(parts))
	for i := len(parts) - 1; i >= 0; i-- {
		strap = append(strap, parts[i])
	}

	return strings.Join(append(strap, name), "."), nil
}
<commit_msg>changing Values set to convert value to string<commit_after>package addon

import (
	"encoding/json"
	"fmt"
	"net/url"
	"strings"

	"github.com/ponzu-cms/ponzu/system/db"
	"github.com/ponzu-cms/ponzu/system/item"
)

var (
	// Types is a record of addons, like content types, of addon_reverse_dns:interface{}
	Types = make(map[string]func() interface{})
)

const (
	// StatusEnabled defines string status for Addon enabled state
	StatusEnabled = "enabled"
	// StatusDisabled defines string status for Addon disabled state
	StatusDisabled = "disabled"
)

// Meta contains the basic information about the addon
type Meta struct {
	PonzuAddonName       string `json:"addon_name"`
	PonzuAddonAuthor     string `json:"addon_author"`
	PonzuAddonAuthorURL  string `json:"addon_author_url"`
	PonzuAddonVersion    string `json:"addon_version"`
	PonzuAddonReverseDNS string `json:"addon_reverse_dns"`
	PonzuAddonStatus     string `json:"addon_status"`
}

// Addon contains information about a provided addon to the system
type Addon struct {
	item.Item
	Meta
}

// New constructs a new addon to be registered. Meta is a addon.Meta and fn is a
// closure returning a pointer to your own addon type
func New(m Meta, fn func() interface{}) Addon {
	// get or create the reverse DNS identifier
	if m.PonzuAddonReverseDNS == "" {
		revDNS, err := reverseDNS(m)
		if err != nil {
			panic(err)
		}

		m.PonzuAddonReverseDNS = revDNS
	}

	Types[m.PonzuAddonReverseDNS] = fn

	a := Addon{Meta: m}

	err := register(a)
	if err != nil {
		panic(err)
	}

	return a
}

// register sets up the system to use the Addon by:
// 1. Validating the Addon struct
// 2. Checking that the Addon parent type was added to Types (via its New())
// 3. Saving it to the __addons bucket in DB with id/key = addon_reverse_dns
func register(a Addon) error {
	if a.PonzuAddonName == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonName")
	}
	if a.PonzuAddonAuthor == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonAuthor")
	}
	if a.PonzuAddonAuthorURL == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonAuthorURL")
	}
	if a.PonzuAddonVersion == "" {
		return fmt.Errorf(`Addon must have valid Meta struct embedded: missing %s field.`, "PonzuAddonVersion")
	}

	if _, ok := Types[a.PonzuAddonReverseDNS]; !ok {
		return fmt.Errorf(`Addon "%s" has no record in the addons.Types map`, a.PonzuAddonName)
	}

	// check if addon is already registered in db as addon_reverse_dns
	if db.AddonExists(a.PonzuAddonReverseDNS) {
		return nil
	}

	// convert a.Item into usable data, Item{} => []byte(json) => map[string]interface{}
	kv := make(map[string]interface{})

	data, err := json.Marshal(a.Item)
	if err != nil {
		return err
	}

	err = json.Unmarshal(data, &kv)
	if err != nil {
		return err
	}

	// save new addon to db
	vals := make(url.Values)
	for k, v := range kv {
		vals.Set(k, fmt.Sprintf("%v", v))
	}

	vals.Set("addon_name", a.PonzuAddonName)
	vals.Set("addon_author", a.PonzuAddonAuthor)
	vals.Set("addon_author_url", a.PonzuAddonAuthorURL)
	vals.Set("addon_version", a.PonzuAddonVersion)
	vals.Set("addon_reverse_dns", a.PonzuAddonReverseDNS)
	vals.Set("addon_status", StatusDisabled)

	// db.SetAddon is like SetContent, but rather than the key being an int64 ID,
	// we need it to be a string based on the addon_reverse_dns
	err = db.SetAddon(vals)
	if err != nil {
		return err
	}

	return nil
}

// Deregister removes an addon from the system. `key` is the addon_reverse_dns
func Deregister(key string) error {
	err := db.DeleteAddon(key)
	if err != nil {
		return err
	}

	delete(Types, key)
	return nil
}

// Enable sets the addon status to `enabled`. `key` is the addon_reverse_dns
func Enable(key string) error {
	err := setStatus(key, StatusEnabled)
	if err != nil {
		return err
	}

	return nil
}

// Disable sets the addon status to `disabled`. `key` is the addon_reverse_dns
func Disable(key string) error {
	err := setStatus(key, StatusDisabled)
	if err != nil {
		return err
	}

	return nil
}

func setStatus(key, status string) error {
	a, err := db.Addon(key)
	if err != nil {
		return err
	}

	a.Set("addon_status", status)

	err = db.SetAddon(a)
	if err != nil {
		return err
	}

	return nil
}

func reverseDNS(meta Meta) (string, error) {
	u, err := url.Parse(meta.PonzuAddonAuthorURL)
	if err != nil {
		return "", nil
	}

	if u.Host == "" {
		return "", fmt.Errorf(`Error parsing Addon Author URL: %s. Ensure URL is formatted as "scheme://hostname/path?query" (path & query optional)`, meta.PonzuAddonAuthorURL)
	}

	name := strings.Replace(meta.PonzuAddonName, " ", "", -1)

	// reverse the host name parts, split on '.', ex. bosssauce.it => it.bosssauce
	parts := strings.Split(u.Host, ".")
	strap := make([]string, len(parts), len(parts))
	for i := len(parts) - 1; i >= 0; i-- {
		strap = append(strap, parts[i])
	}

	return strings.Join(append(strap, name), "."), nil
}
<|endoftext|>