<commit_before>package main

import "fmt"
import "os"
import "net/http"
import "io/ioutil"
import "log"

import "github.com/moovweb/gokogiri"
import "github.com/moovweb/gokogiri/xml"
import "github.com/moovweb/gokogiri/xpath"
import "github.com/codegangsta/cli"

func load(url string, fromFile bool) *xml.XmlDocument{
	var data []byte
	if fromFile{
		file, _ := os.Open(url)
		data, _ = ioutil.ReadAll(file)
	} else {
		resp, err := http.Get(url)
		if err != nil {
			log.Fatal(err)
		}
		data, _ = ioutil.ReadAll(resp.Body)
	}
	doc, _ := gokogiri.ParseXml(data)
	return(doc)
}

func multiple(vrouter string, vrf_name string, count bool) {
	url := "http://" + vrouter + ":8085" + "/Snh_PageReq?x=begin:-1,end:-1,table:" + vrf_name + ".uc.route.0,"

	var doc = load(url, false)
	defer doc.Free()
	xps := xpath.Compile("//route_list/list/RouteUcSandeshData/path_list/list/PathSandeshData/nh/NhSandeshData/mc_list/../../../../../../src_ip/text()")
	ss, _ := doc.Root().Search(xps)
	if count {
		fmt.Printf("%d\n", len(ss))
	} else {
		for _, s := range ss {
			fmt.Printf("%s\n", s)
		}
	}
}

type Page struct {
	VrouterUrl string;
	Table string;
}

type File struct {
	Path string;
}

type LoadAble interface {
	Load(descCol DescCol) Collection;
}

// Parse data to XML
func fromDataToCollection(data []byte, descCol DescCol) Collection {
	doc, _ := gokogiri.ParseXml(data)
	ss, _ := doc.Search(descCol.BaseXpath)
	col := Collection{node: ss[0], descCol: descCol}
	col.Init()
	return col
}

func (file File) Load(descCol DescCol) Collection {
	f, _ := os.Open(file.Path)
	data, _ := ioutil.ReadAll(f)
	return fromDataToCollection(data, descCol)
}

func (page Page) Load(descCol DescCol) Collection {
	url := "http://" + page.VrouterUrl + ":8085/Snh_PageReq?x=begin:-1,end:-1,table:" + page.Table + ","
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	data, _ := ioutil.ReadAll(resp.Body)
	return fromDataToCollection(data, descCol)
}

type Collection struct {
	descCol DescCol;
	doc *xml.XmlDocument;
	node xml.Node;
	elements []Element;
}

type DescCol struct {
	BaseXpath string;
	ShortDetailXpath string;
	LongDetailXpath []string;
	DescElt DescElement;
}

type DescElement struct {
	ShortDetailXpath string;
	LongDetailFunc (func (Element));
}

type Element struct {
	node xml.Node;
	desc DescElement;
}

func (col *Collection) Init() {
	ss, _ := col.node.Search("*")
	col.elements = make([]Element, len(ss))
	for i, s := range ss {
		col.elements[i] = Element{node: s, desc: col.descCol.DescElt}
	}
}

func (e Element) Short() {
	s, _ := e.node.Search(e.desc.ShortDetailXpath)
	fmt.Printf("%s\n", s[0])
}

func (e Element) Long() {
	e.desc.LongDetailFunc(e)
}

func test() {
	col := BuildRouteFile("tmp.out").Load(DescRoute())
	col.Init()
	for _, e := range col.elements {
		e.Long()
	}
}

func (col Collection) Short() {
	for _, e := range col.elements {
		e.Short()
	}
}
func (col Collection) Long() {
	for _, e := range col.elements {
		e.Long()
	}
}

func BuildItfPage(vrouter string) Page {
	return Page{Table: "db.interface.0", VrouterUrl: vrouter}
}
func BuildVrfPage(vrouter string) Page {
	return Page{Table: "db.vrf.0", VrouterUrl: vrouter}
}
func BuildRoutePage(vrouter string, vrfName string) Page {
	return Page{Table: vrfName + ".uc.route.0,", VrouterUrl: vrouter}
}
func BuildRouteFile(path string) File {
	return File{Path: path}
}

func DescItf() DescCol {
	return DescCol{
		BaseXpath: "__ItfResp_list/ItfResp/itf_list/list",
		ShortDetailXpath: "ItfSandeshData/name/text()",
		DescElt: DescElement {
			ShortDetailXpath: "ItfSandeshData/name/text()"},
	}
}

func DescRoute() DescCol {
	return DescCol{
		BaseXpath: "__Inet4UcRouteResp_list/Inet4UcRouteResp/route_list/list",
		ShortDetailXpath: "RouteUcSandeshData/src_ip/text()",
		DescElt: DescElement {
			ShortDetailXpath: "src_ip/text()",
			LongDetailFunc: routeDetail},
	}
}

func DescVrf() DescCol {
	return DescCol{
		BaseXpath: "//vrf_list/list",
		ShortDetailXpath: "//name/text()",
	}
}

func routeGet(c Collection, srcIp string) xml.Node {
 	route, _ := c.node.Search("RouteUcSandeshData/src_ip[text()='" + srcIp + "']/..")
	if len(route) == 0 {
		log.Fatal("Route to " + srcIp + " was not found")
	}
	return route[0]
}

func routeDetail(e Element) {
	srcIp, _ := e.node.Search("src_ip/text()")
	fmt.Printf("%s\n", srcIp[0])
	paths, _ := e.node.Search("path_list/list/PathSandeshData")
	for _, path := range paths {
		nhs, _ := path.Search("nh/NhSandeshData//dip/text()")
		peers, _ := path.Search("peer/text()")
		label, _ := path.Search("label/text()")
		itf, _ := path.Search("nh/NhSandeshData/itf/text()")
		fmt.Printf("  %s %s %s %s\n", nhs, peers, label, itf)
	}
}

func main() {
	var vrouter string;
	var showAsXml bool;
	var count bool;

	app := cli.NewApp()
	app.Name = "contrail-introspect-cli"
	app.Usage = "CLI on contrail introspects"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "format-xml",
			Destination: &showAsXml,
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "itf",
			Aliases:     []string{"a"},
			Usage:     "list interfaces",
			Flags: []cli.Flag{
				 cli.StringFlag{
					 Name: "vrouter",
					 Destination: &vrouter,
				 },
			},
			Action: func(c *cli.Context) {
				if c.NArg() != 1 {
					log.Fatal("Wrong argument number!")
				}
				vrouter := c.Args()[0]
				BuildItfPage(vrouter).Load(DescItf()).Short()
			},
		},
		{
			Name:      "multiple",
			Usage:     "vrouter vrf_name",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "count",
					Destination: &count,
				}},
			Action: func(c *cli.Context) {
				if c.NArg() != 2 {
					log.Fatal("Wrong argument number!")
				}
				vrouter := c.Args()[0]
				vrf_name := c.Args()[1]
				multiple(vrouter, vrf_name, count)
			},
		},
		{
			Name:      "vrf",
			Usage:     "vrf <vrouterUrl>",
			Action: func(c *cli.Context) {
				if c.NArg() != 1 {
					log.Fatal("Wrong argument number!")
				}
				BuildVrfPage(c.Args()[0]).Load(DescVrf()).Short()
			},
		},
		{
			Name:      "route",
			Usage:     "route <vrouterUrl> <vrfName> [<srcIp>]",
			Action: func(c *cli.Context) {
				col := BuildRoutePage(c.Args()[0], c.Args()[1]).Load(DescRoute())
				switch c.NArg() {
				case 2:
					if showAsXml {
						fmt.Printf("%s\n", col.node)
						return
					}
					col.Short()
				case 3:
					route := routeGet(col, c.Args()[2])
					if showAsXml {
						fmt.Printf("%s\n", route)
						return
					}
					routeDetail(Element{node: route})
				}
			},
		},
		{
			Name:      "route-from-file",
			Action: func(c *cli.Context) {
				col := BuildRouteFile(c.Args()[0]).Load(DescRoute())
				switch c.NArg() {
				case 1:
					if showAsXml {
						fmt.Printf("%s\n", col.node)
						return
					}
					col.Short()
				case 2:
					route := routeGet(col, c.Args()[1])
					if showAsXml {
						fmt.Printf("%s\n", route)
						return
					}
					routeDetail(Element{node: route})
				}
			},
		},
	}
	app.Run(os.Args)
}
<commit_msg>Check error<commit_after>package main

import "fmt"
import "os"
import "net/http"
import "io/ioutil"
import "log"

import "github.com/moovweb/gokogiri"
import "github.com/moovweb/gokogiri/xml"
import "github.com/moovweb/gokogiri/xpath"
import "github.com/codegangsta/cli"

func load(url string, fromFile bool) *xml.XmlDocument{
	var data []byte
	if fromFile{
		file, _ := os.Open(url)
		data, _ = ioutil.ReadAll(file)
	} else {
		resp, err := http.Get(url)
		if err != nil {
			log.Fatal(err)
		}
		data, _ = ioutil.ReadAll(resp.Body)
	}
	doc, _ := gokogiri.ParseXml(data)
	return(doc)
}

func multiple(vrouter string, vrf_name string, count bool) {
	url := "http://" + vrouter + ":8085" + "/Snh_PageReq?x=begin:-1,end:-1,table:" + vrf_name + ".uc.route.0,"

	var doc = load(url, false)
	defer doc.Free()
	xps := xpath.Compile("//route_list/list/RouteUcSandeshData/path_list/list/PathSandeshData/nh/NhSandeshData/mc_list/../../../../../../src_ip/text()")
	ss, _ := doc.Root().Search(xps)
	if count {
		fmt.Printf("%d\n", len(ss))
	} else {
		for _, s := range ss {
			fmt.Printf("%s\n", s)
		}
	}
}

type Page struct {
	VrouterUrl string;
	Table string;
}

type File struct {
	Path string;
}

type LoadAble interface {
	Load(descCol DescCol) Collection;
}

// Parse data to XML
func fromDataToCollection(data []byte, descCol DescCol) Collection {
	doc, _ := gokogiri.ParseXml(data)
	ss, _ := doc.Search(descCol.BaseXpath)
	col := Collection{node: ss[0], descCol: descCol}
	col.Init()
	return col
}

func (file File) Load(descCol DescCol) Collection {
	f, _ := os.Open(file.Path)
	data, _ := ioutil.ReadAll(f)
	return fromDataToCollection(data, descCol)
}

func (page Page) Load(descCol DescCol) Collection {
	url := "http://" + page.VrouterUrl + ":8085/Snh_PageReq?x=begin:-1,end:-1,table:" + page.Table + ","
	resp, err := http.Get(url)
	if err != nil {
		log.Fatal(err)
	}
	data, _ := ioutil.ReadAll(resp.Body)
	return fromDataToCollection(data, descCol)
}

type Collection struct {
	descCol DescCol;
	doc *xml.XmlDocument;
	node xml.Node;
	elements []Element;
}

type DescCol struct {
	BaseXpath string;
	ShortDetailXpath string;
	LongDetailXpath []string;
	DescElt DescElement;
}

type DescElement struct {
	ShortDetailXpath string;
	LongDetailFunc (func (Element));
}

type Element struct {
	node xml.Node;
	desc DescElement;
}

func (col *Collection) Init() {
	ss, _ := col.node.Search("*")
	col.elements = make([]Element, len(ss))
	for i, s := range ss {
		col.elements[i] = Element{node: s, desc: col.descCol.DescElt}
	}
}

func (e Element) Short() {
	s, _ := e.node.Search(e.desc.ShortDetailXpath)
	if len(s) != 1 {
		log.Fatal("Xpath '" + e.desc.ShortDetailXpath + "' is not valid")
	}
	fmt.Printf("%s\n", s[0])
}

func (e Element) Long() {
	e.desc.LongDetailFunc(e)
}

func test() {
	col := BuildRouteFile("tmp.out").Load(DescRoute())
	col.Init()
	for _, e := range col.elements {
		e.Long()
	}
}

func (col Collection) Short() {
	for _, e := range col.elements {
		e.Short()
	}
}
func (col Collection) Long() {
	for _, e := range col.elements {
		e.Long()
	}
}

func BuildItfPage(vrouter string) Page {
	return Page{Table: "db.interface.0", VrouterUrl: vrouter}
}
func BuildVrfPage(vrouter string) Page {
	return Page{Table: "db.vrf.0", VrouterUrl: vrouter}
}
func BuildRoutePage(vrouter string, vrfName string) Page {
	return Page{Table: vrfName + ".uc.route.0,", VrouterUrl: vrouter}
}
func BuildRouteFile(path string) File {
	return File{Path: path}
}

func DescItf() DescCol {
	return DescCol{
		BaseXpath: "__ItfResp_list/ItfResp/itf_list/list",
		ShortDetailXpath: "ItfSandeshData/name/text()",
		DescElt: DescElement {
			ShortDetailXpath: "ItfSandeshData/name/text()"},
	}
}

func DescRoute() DescCol {
	return DescCol{
		BaseXpath: "__Inet4UcRouteResp_list/Inet4UcRouteResp/route_list/list",
		ShortDetailXpath: "RouteUcSandeshData/src_ip/text()",
		DescElt: DescElement {
			ShortDetailXpath: "src_ip/text()",
			LongDetailFunc: routeDetail},
	}
}

func DescVrf() DescCol {
	return DescCol{
		BaseXpath: "//vrf_list/list",
		ShortDetailXpath: "//name/text()",
	}
}

func routeGet(c Collection, srcIp string) xml.Node {
 	route, _ := c.node.Search("RouteUcSandeshData/src_ip[text()='" + srcIp + "']/..")
	if len(route) == 0 {
		log.Fatal("Route to " + srcIp + " was not found")
	}
	return route[0]
}

func routeDetail(e Element) {
	srcIp, _ := e.node.Search("src_ip/text()")
	fmt.Printf("%s\n", srcIp[0])
	paths, _ := e.node.Search("path_list/list/PathSandeshData")
	for _, path := range paths {
		nhs, _ := path.Search("nh/NhSandeshData//dip/text()")
		peers, _ := path.Search("peer/text()")
		label, _ := path.Search("label/text()")
		itf, _ := path.Search("nh/NhSandeshData/itf/text()")
		fmt.Printf("  %s %s %s %s\n", nhs, peers, label, itf)
	}
}

func main() {
	var vrouter string;
	var showAsXml bool;
	var count bool;

	app := cli.NewApp()
	app.Name = "contrail-introspect-cli"
	app.Usage = "CLI on contrail introspects"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "format-xml",
			Destination: &showAsXml,
		},
	}
	app.Commands = []cli.Command{
		{
			Name:      "itf",
			Aliases:     []string{"a"},
			Usage:     "list interfaces",
			Flags: []cli.Flag{
				 cli.StringFlag{
					 Name: "vrouter",
					 Destination: &vrouter,
				 },
			},
			Action: func(c *cli.Context) {
				if c.NArg() != 1 {
					log.Fatal("Wrong argument number!")
				}
				vrouter := c.Args()[0]
				BuildItfPage(vrouter).Load(DescItf()).Short()
			},
		},
		{
			Name:      "multiple",
			Usage:     "vrouter vrf_name",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name: "count",
					Destination: &count,
				}},
			Action: func(c *cli.Context) {
				if c.NArg() != 2 {
					log.Fatal("Wrong argument number!")
				}
				vrouter := c.Args()[0]
				vrf_name := c.Args()[1]
				multiple(vrouter, vrf_name, count)
			},
		},
		{
			Name:      "vrf",
			Usage:     "vrf <vrouterUrl>",
			Action: func(c *cli.Context) {
				if c.NArg() != 1 {
					log.Fatal("Wrong argument number!")
				}
				BuildVrfPage(c.Args()[0]).Load(DescVrf()).Short()
			},
		},
		{
			Name:      "route",
			Usage:     "route <vrouterUrl> <vrfName> [<srcIp>]",
			Action: func(c *cli.Context) {
				col := BuildRoutePage(c.Args()[0], c.Args()[1]).Load(DescRoute())
				switch c.NArg() {
				case 2:
					if showAsXml {
						fmt.Printf("%s\n", col.node)
						return
					}
					col.Short()
				case 3:
					route := routeGet(col, c.Args()[2])
					if showAsXml {
						fmt.Printf("%s\n", route)
						return
					}
					routeDetail(Element{node: route})
				}
			},
		},
		{
			Name:      "route-from-file",
			Action: func(c *cli.Context) {
				col := BuildRouteFile(c.Args()[0]).Load(DescRoute())
				switch c.NArg() {
				case 1:
					if showAsXml {
						fmt.Printf("%s\n", col.node)
						return
					}
					col.Short()
				case 2:
					route := routeGet(col, c.Args()[1])
					if showAsXml {
						fmt.Printf("%s\n", route)
						return
					}
					routeDetail(Element{node: route})
				}
			},
		},
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package webapps

import (
	"log"
	"net/http"

	"github.com/ChristianSiegert/go-packages/i18n/languages"
	"github.com/ChristianSiegert/go-packages/sessions"
	"github.com/julienschmidt/httprouter"
)

type WebApp struct {
	// Default language to redirect to when requested language is not supported.
	defaultLanguageCode string

	languages    map[string]*languages.Language
	logger       *log.Logger
	router       *httprouter.Router
	serverHost   string
	serverPort   string
	sessionStore sessions.Store
}

func New(host, port string, logger *log.Logger, sessionStore sessions.Store) *WebApp {
	return &WebApp{
		languages:    make(map[string]*languages.Language, 1),
		logger:       logger,
		router:       httprouter.New(),
		serverHost:   host,
		serverPort:   port,
		sessionStore: sessionStore,
	}
}

func (w *WebApp) AddLanguage(language *languages.Language, isDefault bool) {
	w.languages[language.Code()] = language
	if isDefault {
		w.defaultLanguageCode = language.Code()
	}
}

func (w *WebApp) AddRoute(path string, handle httprouter.Handle, methods ...string) {
	for _, method := range methods {
		handle = w.handleLanguage(handle)
		handle = w.handleSession(handle)
		w.router.Handle(method, path, handle)
	}
}

func (w *WebApp) AddFileDir(urlPath, dirPath string) {
	w.router.ServeFiles(urlPath, http.Dir(dirPath))
}

func (w *WebApp) handleLanguage(handle httprouter.Handle) httprouter.Handle {
	return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		languageCode := params.ByName("lang")

		// If language is not supported, redirect to default language
		language, ok := w.languages[languageCode]
		if !ok {
			if w.defaultLanguageCode == "" {
				panic("webapps: No default language set.")
			}
			http.Redirect(writer, request, "/"+w.defaultLanguageCode, http.StatusSeeOther)
			return
		}

		// Add language to context
		context := languages.NewContext(request.Context(), language)
		request = request.WithContext(context)

		// Execute given handle
		handle(writer, request, params)
	}
}

func (w *WebApp) handleSession(handle httprouter.Handle) httprouter.Handle {
	return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		// Get session for this request
		session, err := w.sessionStore.Get(writer, request)
		if err != nil {
			log.Println("webapps: " + err.Error())
			http.Error(writer, "Interal Server Error", http.StatusInternalServerError)
			return
		}

		// Add session to context
		context := sessions.NewContext(request.Context(), session)
		request = request.WithContext(context)

		// Execute given handle
		handle(writer, request, params)
	}
}

// Start starts the HTTP server.
func (w *WebApp) Start() error {
	serverAddress := w.serverHost + w.serverPort
	return http.ListenAndServe(serverAddress, w.router)
}

// StartWithTls starts the HTTP server with TLS.
func (w *WebApp) StartWithTls(certificatePath, keyPath string) error {
	serverAddress := w.serverHost + w.serverPort
	return http.ListenAndServeTLS(serverAddress, certificatePath, keyPath, w.router)
}
<commit_msg>Prefixed port in WebApp.Start with colon (:).<commit_after>package webapps

import (
	"log"
	"net/http"

	"github.com/ChristianSiegert/go-packages/i18n/languages"
	"github.com/ChristianSiegert/go-packages/sessions"
	"github.com/julienschmidt/httprouter"
)

type WebApp struct {
	// Default language to redirect to when requested language is not supported.
	defaultLanguageCode string

	languages    map[string]*languages.Language
	logger       *log.Logger
	router       *httprouter.Router
	serverHost   string
	serverPort   string
	sessionStore sessions.Store
}

func New(host, port string, logger *log.Logger, sessionStore sessions.Store) *WebApp {
	return &WebApp{
		languages:    make(map[string]*languages.Language, 1),
		logger:       logger,
		router:       httprouter.New(),
		serverHost:   host,
		serverPort:   port,
		sessionStore: sessionStore,
	}
}

func (w *WebApp) AddLanguage(language *languages.Language, isDefault bool) {
	w.languages[language.Code()] = language
	if isDefault {
		w.defaultLanguageCode = language.Code()
	}
}

func (w *WebApp) AddRoute(path string, handle httprouter.Handle, methods ...string) {
	for _, method := range methods {
		handle = w.handleLanguage(handle)
		handle = w.handleSession(handle)
		w.router.Handle(method, path, handle)
	}
}

func (w *WebApp) AddFileDir(urlPath, dirPath string) {
	w.router.ServeFiles(urlPath, http.Dir(dirPath))
}

func (w *WebApp) handleLanguage(handle httprouter.Handle) httprouter.Handle {
	return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		languageCode := params.ByName("lang")

		// If language is not supported, redirect to default language
		language, ok := w.languages[languageCode]
		if !ok {
			if w.defaultLanguageCode == "" {
				panic("webapps: No default language set.")
			}
			http.Redirect(writer, request, "/"+w.defaultLanguageCode, http.StatusSeeOther)
			return
		}

		// Add language to context
		context := languages.NewContext(request.Context(), language)
		request = request.WithContext(context)

		// Execute given handle
		handle(writer, request, params)
	}
}

func (w *WebApp) handleSession(handle httprouter.Handle) httprouter.Handle {
	return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		// Get session for this request
		session, err := w.sessionStore.Get(writer, request)
		if err != nil {
			log.Println("webapps: " + err.Error())
			http.Error(writer, "Interal Server Error", http.StatusInternalServerError)
			return
		}

		// Add session to context
		context := sessions.NewContext(request.Context(), session)
		request = request.WithContext(context)

		// Execute given handle
		handle(writer, request, params)
	}
}

// Start starts the HTTP server.
func (w *WebApp) Start() error {
	serverAddress := w.serverHost + ":" + w.serverPort
	return http.ListenAndServe(serverAddress, w.router)
}

// StartWithTls starts the HTTP server with TLS.
func (w *WebApp) StartWithTls(certificatePath, keyPath string) error {
	serverAddress := w.serverHost + w.serverPort
	return http.ListenAndServeTLS(serverAddress, certificatePath, keyPath, w.router)
}
<|endoftext|>


<commit_before>package main // import "github.com/johnpeterharvey/pinger"

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func main() {
	log.Print("Starting up...")

	interval, settings, err := GetSettings()
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}

	client := &http.Client{}

	for {
		err := DoCall(client, settings)
		if err != nil {
			log.Print(err)
		}
		log.Printf("Sleeping for %d seconds", interval)
		time.Sleep(time.Duration(interval) * time.Second)
	}
}

// GetSettings Read required settings from environment variables
func GetSettings() (int, map[string]string, error) {
	target := os.Getenv("TARGET_URL")
	method := os.Getenv("METHOD")
	interval, err := strconv.Atoi(os.Getenv("INTERVAL"))

	if target == "" || method == "" || err != nil || interval < 0 {
		return -1, map[string]string{}, errors.New("Environment variables were not set, returning error")
	}

	return interval, map[string]string{
			"target": target,
			"method": method},
		nil
}

// DoCall Do an HTTP call out to the server, with the specified properties
func DoCall(client *http.Client, settings map[string]string) error {
	log.Printf("Trying HTTP %s to %s", settings["method"], settings["target"])

	req, err := http.NewRequest(settings["method"], settings["target"], strings.NewReader("{}"))
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to create HTTP request! %s", err))
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Content-Type", "application/json")
	resp, err := client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		return errors.New(fmt.Sprintf("Error! Received error while contacting target! %s", err))
	} else {
		log.Printf("Received response %d\n", resp.StatusCode)
		if resp.StatusCode < 200 || resp.StatusCode >= 300 {
			return errors.New(fmt.Sprintf("Error! Received unexpected status code from target! %d", resp.StatusCode))
		}
	}
	return nil
}
<commit_msg>Use fmt.Errorf instead of creating errors with printf'd strings<commit_after>package main // import "github.com/johnpeterharvey/pinger"

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

func main() {
	log.Print("Starting up...")

	interval, settings, err := GetSettings()
	if err != nil {
		log.Print(err)
		os.Exit(1)
	}

	client := &http.Client{}

	for {
		err := DoCall(client, settings)
		if err != nil {
			log.Print(err)
		}
		log.Printf("Sleeping for %d seconds", interval)
		time.Sleep(time.Duration(interval) * time.Second)
	}
}

// GetSettings Read required settings from environment variables
func GetSettings() (int, map[string]string, error) {
	target := os.Getenv("TARGET_URL")
	method := os.Getenv("METHOD")
	interval, err := strconv.Atoi(os.Getenv("INTERVAL"))

	if target == "" || method == "" || err != nil || interval < 0 {
		return -1, map[string]string{}, errors.New("Environment variables were not set, returning error")
	}

	return interval, map[string]string{
			"target": target,
			"method": method},
		nil
}

// DoCall Do an HTTP call out to the server, with the specified properties
func DoCall(client *http.Client, settings map[string]string) error {
	log.Printf("Trying HTTP %s to %s", settings["method"], settings["target"])

	req, err := http.NewRequest(settings["method"], settings["target"], strings.NewReader("{}"))
	if err != nil {
		return fmt.Errorf("Failed to create HTTP request! %s", err)
	}
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Content-Type", "application/json")
	resp, err := client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		return fmt.Errorf("Error! Received error while contacting target! %s", err)
	}
	log.Printf("Received response %d\n", resp.StatusCode)
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return fmt.Errorf("Error! Received unexpected status code from target! %d", resp.StatusCode)
	}
	return nil
}
<|endoftext|>


<commit_before>// Package pkcs11 provides an interface to the PKCS#11 API.
//
//
package pkcs11

/*
#cgo LDFLAGS: -lltdl
#include <string.h>
#include "pkcs11c"

CK_SLOT_ID_PTR SlotIDIndex(CK_SLOT_ID_PTR *p, int i) { return p[i]; }
CK_MECHANISM_TYPE_PTR MechTypeIndex(CK_MECHANISM_TYPE_PTR *p, int i) { return p[i]; }

// old
CK_TOKEN_INFO_PTR TokenIndex(CK_TOKEN_INFO_PTR *l, int i) { return l[i]; }
*/
import "C"

import (
	"strconv"
	"unsafe"
)

func versionFromC(v C.CK_VERSION) *Version {
	v1 := new(Version)
	v1.Major = byte(v.major)
	v1.Minor = byte(v.minor)
	return v1
}

func stringFromC(p unsafe.Pointer, i int) string {
	return string(C.GoBytes(p, C.int(i)))
}

func infoFromC(pInfo C.CK_INFO_PTR) *Info {
	i := new(Info)
	i.ManufacturerID = stringFromC(unsafe.Pointer(&(pInfo.manufacturerID)), 32)
	i.CryptokiVersion = versionFromC(pInfo.cryptokiVersion)
	i.Flags = uint(pInfo.flags)
	i.LibraryDescription = stringFromC(unsafe.Pointer(&(pInfo.libraryDescription)), 32)
	i.LibraryVersion = versionFromC(pInfo.libraryVersion)
	return i
}

func slotInfoFromC(pSlotInfo C.CK_SLOT_INFO_PTR) *SlotInfo {
	i := new(SlotInfo)
	i.SlotDescription = stringFromC(unsafe.Pointer(&(pSlotInfo.slotDescription)), 64)
	i.ManufacturerID = stringFromC(unsafe.Pointer(&(pSlotInfo.manufacturerID)), 32)
	i.Flags = uint(pSlotInfo.flags)
	i.HardwareVersion = versionFromC(pSlotInfo.hardwareVersion)
	i.FirmwareVersion = versionFromC(pSlotInfo.firmwareVersion)
	return i
}

func tokenInfoFromC(pTokenInfo C.CK_TOKEN_INFO_PTR) *TokenInfo {
	t := new(TokenInfo)
	t.Label = stringFromC(unsafe.Pointer(&(pTokenInfo.label)), 32)
	t.ManufacturerID = stringFromC(unsafe.Pointer(&(pTokenInfo.manufacturerID)), 32)
	t.Model = stringFromC(unsafe.Pointer(&(pTokenInfo.model)), 16)
	t.SerialNumber = stringFromC(unsafe.Pointer(&(pTokenInfo.serialNumber)), 16)
	t.Flags = uint(pTokenInfo.flags)
	t.MaxSessionCount = uint(pTokenInfo.ulMaxSessionCount)
	t.SessionCount = uint(pTokenInfo.ulSessionCount)
	t.MaxRwSessionCount = uint(pTokenInfo.ulMaxRwSessionCount)
	t.RwSessionCount = uint(pTokenInfo.ulRwSessionCount)
	t.MaxPinLen = uint(pTokenInfo.ulMaxPinLen)
	t.MinPinLen = uint(pTokenInfo.ulMinPinLen)
	t.TotalPublicMemory = uint(pTokenInfo.ulTotalPublicMemory)
	t.FreePublicMemory = uint(pTokenInfo.ulFreePublicMemory)
	t.TotalPrivateMemory = uint(pTokenInfo.ulTotalPrivateMemory)
	t.FreePrivateMemory = uint(pTokenInfo.ulFreePrivateMemory)
	t.HardwareVersion = versionFromC(pTokenInfo.hardwareVersion)
	t.FirmwareVersion = versionFromC(pTokenInfo.firmwareVersion)
	t.UTCTime = stringFromC(unsafe.Pointer(&(pTokenInfo.utcTime)), 16)
	return t
}

func mechanismInfoFromC(pMechanismInfo C.CK_MECHANISM_INFO_PTR) *MechanismInfo {
	m := new(MechanismInfo)
	m.MinKeySize = uint(pMechanismInfo.ulMinKeySize)
	m.MaxKeySize =uint(pMechanismInfo.ulMaxKeySize)
	m.Flags = uint(pMechanismInfo.flags)
	return m
}

func sessionInfoFromC(pSessionInfo C.CK_SESSION_INFO_PTR) *SessionInfo {
	s := new(SessionInfo)
	s.SlotID = uint(pSessionInfo.slotID)
	s.State =  uint(pSessionInfo.state)
	s.Flags = uint(pSessionInfo.flags)
	s.DeviceError = uint(pSessionInfo.ulDeviceError)
	return s
}

// Pkcs11Error represents an error from the PKCS#11 library.
type Pkcs11Error struct {
	err string // error text
	rv  int    // return value from pkcs11 api
}

func newPkcs11Error(s string, rv C.CK_RV) *Pkcs11Error {
	return &Pkcs11Error{err: s, rv: int(rv)}
}

func (e *Pkcs11Error) Error() string {
	s := "pkcs11: " + e.err + "(rv: " + strconv.Itoa(e.rv) + ")"
	return s
}

type Pkcs11 struct {
	ctx *C.struct_ctx
}

// New returns a new instance of a pkcs11. The dynamic PKCS#11 library is
// loaded. New returns nil on error.
func New(module string) *Pkcs11 {
	p := new(Pkcs11)
	mod := C.CString(module)
	defer C.free(unsafe.Pointer(mod))
	p.ctx = C.New(mod)
	if p.ctx == nil {
		return nil
	}
	return p
}

// Wraps PKCS#11's C_Initialize.
func (p *Pkcs11) C_Initialize() error {
	e := C.Go_C_Initialize(p.ctx)
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

// Wraps PKCS#11's C_Finalize.
func (p *Pkcs11) C_Finalize() error {
	e := C.Go_C_Finalize(p.ctx)
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

// Destroy unload the module and frees any remaining memory.
func (p *Pkcs11) Destroy() {
	if p == nil {
		return
	}
	C.Destroy(p.ctx)
}

func (p *Pkcs11) C_GetInfo() (*Info, error) {
	var pInfo C.CK_INFO_PTR
	defer C.free(unsafe.Pointer(pInfo))
	e := C.Go_C_GetInfo(p.ctx, &pInfo)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return infoFromC(pInfo), nil
}

func (p *Pkcs11) C_GetSlotList(tokenPresent bool) ([]uint, error) {
	var (
		slotlist C.CK_SLOT_ID_PTR
		pcount   C.CK_ULONG
		e        C.CK_RV
	)
	defer C.free(unsafe.Pointer(slotlist))
	if tokenPresent {
		e = C.Go_C_GetSlotList(p.ctx, C.CK_TRUE, &slotlist, &pcount)
	} else {
		e = C.Go_C_GetSlotList(p.ctx, C.CK_FALSE, &slotlist, &pcount)
	}
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	u := make([]uint, 0)
	for i := uint(0); i < uint(pcount); i++ {
		u = append(u, uint(*(C.SlotIDIndex(&slotlist, C.int(i)))))
	}
	return u, nil
}

func (p *Pkcs11) C_GetSlotInfo(slotID uint) (*SlotInfo, error) {
	var (
		slot C.CK_SLOT_INFO_PTR
	)
	defer C.free(unsafe.Pointer(slot))
	e := C.Go_C_GetSlotInfo(p.ctx, C.CK_SLOT_ID(slotID), &slot)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return slotInfoFromC(slot), nil
}

func (p *Pkcs11) C_GetTokenInfo(slotID uint) (*TokenInfo, error) {
	var (
		token C.CK_TOKEN_INFO_PTR
	)
	defer C.free(unsafe.Pointer(token))
	e := C.Go_C_GetTokenInfo(p.ctx, C.CK_SLOT_ID(slotID), &token)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return tokenInfoFromC(token), nil
}

func (p *Pkcs11) C_GetMechanismList(slotID uint) ([]uint, error) {
	var (
		mechlist C.CK_MECHANISM_TYPE_PTR
		pcount   C.CK_ULONG
	)
	defer C.free(unsafe.Pointer(mechlist))
	e := C.Go_C_GetMechanismList(p.ctx, C.CK_SLOT_ID(slotID), &mechlist, &pcount)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	u := make([]uint, 0)
	for i := uint(0); i < uint(pcount); i++ {
		u = append(u, uint(*(C.MechTypeIndex(&mechlist, C.int(i)))))
	}
	return u, nil
}

func (p *Pkcs11) C_GetMechanismInfo(slotID, mechanismType uint) (*MechanismInfo, error) {
	var (
		mech C.CK_MECHANISM_INFO_PTR
	)
	defer C.free(unsafe.Pointer(mech))
	e := C.Go_C_GetMechanismInfo(p.ctx, C.CK_SLOT_ID(slotID), C.CK_MECHANISM_TYPE(mechanismType), &mech)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return mechanismInfoFromC(mech), nil
}

func (p *Pkcs11) C_InitToken(slotID uint, soPin, label string) error {
	if len(label) > 32 {
		return newPkcs11Error("label must be 32 bytes or less", 1)
	}
	for len(label) < 32 { // stupid loop to make it 32 bytes
		label += " "
	}
	csoPin := C.CString(soPin)
	clabel := C.CString(label)
	defer C.free(unsafe.Pointer(csoPin))
	defer C.free(unsafe.Pointer(clabel))
	e := C.Go_C_InitToken(p.ctx, C.CK_SLOT_ID(slotID), csoPin, C.CK_ULONG(len(soPin)), clabel)
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

// Session handling

// Callback function not supported...?
// pApplication/Notify
func (p *Pkcs11) C_OpenSession(slotID uint, flags uint) (SessionHandle, error) {
	var sh SessionHandle
	e := C.Go_C_OpenSession(p.ctx, C.CK_SLOT_ID(slotID), C.CK_FLAGS(flags), C.CK_SESSION_HANDLE_PTR(unsafe.Pointer(&sh)))
	if e != C.CKR_OK {
		return 0, newPkcs11Error("", e)
	}
	return sh, nil
}

func (p *Pkcs11) C_CloseSession(sh SessionHandle) error {
	e := C.Go_C_CloseSession(p.ctx, C.CK_SESSION_HANDLE(sh))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_InitPIN(sh SessionHandle, pin string) error {
	cPin := C.CString(pin)
	defer C.free(unsafe.Pointer(cPin))
	e := C.Go_C_InitPIN(p.ctx, C.CK_SESSION_HANDLE(sh), cPin, C.CK_ULONG(len(pin)))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_SetPIN(sh SessionHandle, oldPin, newPin string) error {
	coldPin := C.CString(oldPin)
	cnewPin := C.CString(newPin)
	defer C.free(unsafe.Pointer(coldPin))
	defer C.free(unsafe.Pointer(cnewPin))
	e := C.Go_C_SetPIN(p.ctx, C.CK_SESSION_HANDLE(sh), coldPin, C.CK_ULONG(len(oldPin)), cnewPin, C.CK_ULONG(len(newPin)))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_CloseAllSessions(slotID uint) error {
	e := C.Go_C_CloseAllSessions(p.ctx, C.CK_SLOT_ID(slotID))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_GetSessionInfo(sh SessionHandle) (*SessionInfo, error) {
	var (
		session C.CK_SESSION_INFO_PTR
	)
	defer C.free(unsafe.Pointer(session))
	e := C.Go_C_GetSessionInfo(p.ctx, C.CK_SESSION_HANDLE(sh), &session)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return sessionInfoFromC(session), nil
}

// Object handling

func (p *Pkcs11) C_CreateObject() (ObjectHandle, error) {
	return 0, nil
}
<commit_msg>more stuff now objectCreate<commit_after>// Package pkcs11 provides an interface to the PKCS#11 API.
//
//
package pkcs11

/*
#cgo LDFLAGS: -lltdl
#include <string.h>
#include "pkcs11c"

CK_SLOT_ID_PTR SlotIDIndex(CK_SLOT_ID_PTR *p, int i) { return p[i]; }
CK_MECHANISM_TYPE_PTR MechTypeIndex(CK_MECHANISM_TYPE_PTR *p, int i) { return p[i]; }

// old
CK_TOKEN_INFO_PTR TokenIndex(CK_TOKEN_INFO_PTR *l, int i) { return l[i]; }
*/
import "C"

import (
	"strconv"
	"unsafe"
)

func versionFromC(v C.CK_VERSION) *Version {
	v1 := new(Version)
	v1.Major = byte(v.major)
	v1.Minor = byte(v.minor)
	return v1
}

func stringFromC(p unsafe.Pointer, i int) string {
	return string(C.GoBytes(p, C.int(i)))
}

func infoFromC(pInfo C.CK_INFO_PTR) *Info {
	i := new(Info)
	i.ManufacturerID = stringFromC(unsafe.Pointer(&(pInfo.manufacturerID)), 32)
	i.CryptokiVersion = versionFromC(pInfo.cryptokiVersion)
	i.Flags = uint(pInfo.flags)
	i.LibraryDescription = stringFromC(unsafe.Pointer(&(pInfo.libraryDescription)), 32)
	i.LibraryVersion = versionFromC(pInfo.libraryVersion)
	return i
}

func slotInfoFromC(pSlotInfo C.CK_SLOT_INFO_PTR) *SlotInfo {
	i := new(SlotInfo)
	i.SlotDescription = stringFromC(unsafe.Pointer(&(pSlotInfo.slotDescription)), 64)
	i.ManufacturerID = stringFromC(unsafe.Pointer(&(pSlotInfo.manufacturerID)), 32)
	i.Flags = uint(pSlotInfo.flags)
	i.HardwareVersion = versionFromC(pSlotInfo.hardwareVersion)
	i.FirmwareVersion = versionFromC(pSlotInfo.firmwareVersion)
	return i
}

func tokenInfoFromC(pTokenInfo C.CK_TOKEN_INFO_PTR) *TokenInfo {
	t := new(TokenInfo)
	t.Label = stringFromC(unsafe.Pointer(&(pTokenInfo.label)), 32)
	t.ManufacturerID = stringFromC(unsafe.Pointer(&(pTokenInfo.manufacturerID)), 32)
	t.Model = stringFromC(unsafe.Pointer(&(pTokenInfo.model)), 16)
	t.SerialNumber = stringFromC(unsafe.Pointer(&(pTokenInfo.serialNumber)), 16)
	t.Flags = uint(pTokenInfo.flags)
	t.MaxSessionCount = uint(pTokenInfo.ulMaxSessionCount)
	t.SessionCount = uint(pTokenInfo.ulSessionCount)
	t.MaxRwSessionCount = uint(pTokenInfo.ulMaxRwSessionCount)
	t.RwSessionCount = uint(pTokenInfo.ulRwSessionCount)
	t.MaxPinLen = uint(pTokenInfo.ulMaxPinLen)
	t.MinPinLen = uint(pTokenInfo.ulMinPinLen)
	t.TotalPublicMemory = uint(pTokenInfo.ulTotalPublicMemory)
	t.FreePublicMemory = uint(pTokenInfo.ulFreePublicMemory)
	t.TotalPrivateMemory = uint(pTokenInfo.ulTotalPrivateMemory)
	t.FreePrivateMemory = uint(pTokenInfo.ulFreePrivateMemory)
	t.HardwareVersion = versionFromC(pTokenInfo.hardwareVersion)
	t.FirmwareVersion = versionFromC(pTokenInfo.firmwareVersion)
	t.UTCTime = stringFromC(unsafe.Pointer(&(pTokenInfo.utcTime)), 16)
	return t
}

func mechanismInfoFromC(pMechanismInfo C.CK_MECHANISM_INFO_PTR) *MechanismInfo {
	m := new(MechanismInfo)
	m.MinKeySize = uint(pMechanismInfo.ulMinKeySize)
	m.MaxKeySize =uint(pMechanismInfo.ulMaxKeySize)
	m.Flags = uint(pMechanismInfo.flags)
	return m
}

func sessionInfoFromC(pSessionInfo C.CK_SESSION_INFO_PTR) *SessionInfo {
	s := new(SessionInfo)
	s.SlotID = uint(pSessionInfo.slotID)
	s.State =  uint(pSessionInfo.state)
	s.Flags = uint(pSessionInfo.flags)
	s.DeviceError = uint(pSessionInfo.ulDeviceError)
	return s
}

// Pkcs11Error represents an error from the PKCS#11 library.
type Pkcs11Error struct {
	err string // error text
	rv  int    // return value from pkcs11 api
}

func newPkcs11Error(s string, rv C.CK_RV) *Pkcs11Error {
	return &Pkcs11Error{err: s, rv: int(rv)}
}

func (e *Pkcs11Error) Error() string {
	s := "pkcs11: " + e.err + "(rv: " + strconv.Itoa(e.rv) + ")"
	return s
}

type Pkcs11 struct {
	ctx *C.struct_ctx
}

// New returns a new instance of a pkcs11. The dynamic PKCS#11 library is
// loaded. New returns nil on error.
func New(module string) *Pkcs11 {
	p := new(Pkcs11)
	mod := C.CString(module)
	defer C.free(unsafe.Pointer(mod))
	p.ctx = C.New(mod)
	if p.ctx == nil {
		return nil
	}
	return p
}

// Wraps PKCS#11's C_Initialize.
func (p *Pkcs11) C_Initialize() error {
	e := C.Go_C_Initialize(p.ctx)
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

// Wraps PKCS#11's C_Finalize.
func (p *Pkcs11) C_Finalize() error {
	e := C.Go_C_Finalize(p.ctx)
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

// Destroy unload the module and frees any remaining memory.
func (p *Pkcs11) Destroy() {
	if p == nil {
		return
	}
	C.Destroy(p.ctx)
}

func (p *Pkcs11) C_GetInfo() (*Info, error) {
	var pInfo C.CK_INFO_PTR
	defer C.free(unsafe.Pointer(pInfo))
	e := C.Go_C_GetInfo(p.ctx, &pInfo)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return infoFromC(pInfo), nil
}

func (p *Pkcs11) C_GetSlotList(tokenPresent bool) ([]uint, error) {
	var (
		slotlist C.CK_SLOT_ID_PTR
		pcount   C.CK_ULONG
		e        C.CK_RV
	)
	defer C.free(unsafe.Pointer(slotlist))
	if tokenPresent {
		e = C.Go_C_GetSlotList(p.ctx, C.CK_TRUE, &slotlist, &pcount)
	} else {
		e = C.Go_C_GetSlotList(p.ctx, C.CK_FALSE, &slotlist, &pcount)
	}
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	u := make([]uint, 0)
	for i := uint(0); i < uint(pcount); i++ {
		u = append(u, uint(*(C.SlotIDIndex(&slotlist, C.int(i)))))
	}
	return u, nil
}

func (p *Pkcs11) C_GetSlotInfo(slotID uint) (*SlotInfo, error) {
	var (
		slot C.CK_SLOT_INFO_PTR
	)
	defer C.free(unsafe.Pointer(slot))
	e := C.Go_C_GetSlotInfo(p.ctx, C.CK_SLOT_ID(slotID), &slot)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return slotInfoFromC(slot), nil
}

func (p *Pkcs11) C_GetTokenInfo(slotID uint) (*TokenInfo, error) {
	var (
		token C.CK_TOKEN_INFO_PTR
	)
	defer C.free(unsafe.Pointer(token))
	e := C.Go_C_GetTokenInfo(p.ctx, C.CK_SLOT_ID(slotID), &token)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return tokenInfoFromC(token), nil
}

func (p *Pkcs11) C_GetMechanismList(slotID uint) ([]uint, error) {
	var (
		mechlist C.CK_MECHANISM_TYPE_PTR
		pcount   C.CK_ULONG
	)
	defer C.free(unsafe.Pointer(mechlist))
	e := C.Go_C_GetMechanismList(p.ctx, C.CK_SLOT_ID(slotID), &mechlist, &pcount)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	u := make([]uint, 0)
	for i := uint(0); i < uint(pcount); i++ {
		u = append(u, uint(*(C.MechTypeIndex(&mechlist, C.int(i)))))
	}
	return u, nil
}

func (p *Pkcs11) C_GetMechanismInfo(slotID, mechanismType uint) (*MechanismInfo, error) {
	var (
		mech C.CK_MECHANISM_INFO_PTR
	)
	defer C.free(unsafe.Pointer(mech))
	e := C.Go_C_GetMechanismInfo(p.ctx, C.CK_SLOT_ID(slotID), C.CK_MECHANISM_TYPE(mechanismType), &mech)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return mechanismInfoFromC(mech), nil
}

func (p *Pkcs11) C_InitToken(slotID uint, soPin, label string) error {
	if len(label) > 32 {
		return newPkcs11Error("label must be 32 bytes or less", 1)
	}
	for len(label) < 32 { // stupid loop to make it 32 bytes
		label += " "
	}
	csoPin := C.CString(soPin)
	clabel := C.CString(label)
	defer C.free(unsafe.Pointer(csoPin))
	defer C.free(unsafe.Pointer(clabel))
	e := C.Go_C_InitToken(p.ctx, C.CK_SLOT_ID(slotID), csoPin, C.CK_ULONG(len(soPin)), clabel)
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

// Session handling

// Callback function not supported...?
// pApplication/Notify
func (p *Pkcs11) C_OpenSession(slotID uint, flags uint) (SessionHandle, error) {
	var sh SessionHandle
	e := C.Go_C_OpenSession(p.ctx, C.CK_SLOT_ID(slotID), C.CK_FLAGS(flags), C.CK_SESSION_HANDLE_PTR(unsafe.Pointer(&sh)))
	if e != C.CKR_OK {
		return 0, newPkcs11Error("", e)
	}
	return sh, nil
}

func (p *Pkcs11) C_CloseSession(sh SessionHandle) error {
	e := C.Go_C_CloseSession(p.ctx, C.CK_SESSION_HANDLE(sh))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_InitPIN(sh SessionHandle, pin string) error {
	cPin := C.CString(pin)
	defer C.free(unsafe.Pointer(cPin))
	e := C.Go_C_InitPIN(p.ctx, C.CK_SESSION_HANDLE(sh), cPin, C.CK_ULONG(len(pin)))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_SetPIN(sh SessionHandle, oldPin, newPin string) error {
	coldPin := C.CString(oldPin)
	cnewPin := C.CString(newPin)
	defer C.free(unsafe.Pointer(coldPin))
	defer C.free(unsafe.Pointer(cnewPin))
	e := C.Go_C_SetPIN(p.ctx, C.CK_SESSION_HANDLE(sh), coldPin, C.CK_ULONG(len(oldPin)), cnewPin, C.CK_ULONG(len(newPin)))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_CloseAllSessions(slotID uint) error {
	e := C.Go_C_CloseAllSessions(p.ctx, C.CK_SLOT_ID(slotID))
	if e != C.CKR_OK {
		return newPkcs11Error("", e)
	}
	return nil
}

func (p *Pkcs11) C_GetSessionInfo(sh SessionHandle) (*SessionInfo, error) {
	var (
		session C.CK_SESSION_INFO_PTR
	)
	defer C.free(unsafe.Pointer(session))
	e := C.Go_C_GetSessionInfo(p.ctx, C.CK_SESSION_HANDLE(sh), &session)
	if e != C.CKR_OK {
		return nil, newPkcs11Error("", e)
	}
	return sessionInfoFromC(session), nil
}

// Object handling

func (p *Pkcs11) C_CreateObject(sh SessionHandle) (ObjectHandle, error) {
	return 0, nil
}

func (p *Pkcs11) C_DestroyObject() error {
	return nil
}

<|endoftext|>


<commit_before>package cdn

import (
	"bufio"
	"context"
	"crypto/rsa"
	"encoding/base64"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	gocache "github.com/patrickmn/go-cache"
	"github.com/spf13/cast"

	"github.com/ovh/cds/engine/cache"
	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/cdsclient"
	"github.com/ovh/cds/sdk/jws"
	"github.com/ovh/cds/sdk/log"
	"github.com/ovh/cds/sdk/log/hook"
	"github.com/ovh/cds/sdk/telemetry"
)

var (
	logCache = gocache.New(20*time.Minute, 20*time.Minute)
)

var globalRateLimit *rateLimiter

// Start TCP Server
func (s *Service) runTCPLogServer(ctx context.Context) error {
	// Init hatcheries cache
	if err := s.refreshHatcheriesPK(ctx); err != nil {
		return sdk.WrapError(err, "unable to init hatcheries cache")
	}

	globalRateLimit = NewRateLimiter(ctx, float64(s.Cfg.TCP.GlobalTCPRateLimit), 1024)

	// Start TCP server
	log.Info(ctx, "Starting tcp server %s:%d", s.Cfg.TCP.Addr, s.Cfg.TCP.Port)
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Cfg.TCP.Addr, s.Cfg.TCP.Port))
	if err != nil {
		return sdk.WrapError(err, "unable to start tcp log server")
	}

	//Gracefully shutdown the tcp server
	s.GoRoutines.Run(ctx, "service.runTCPLogServer.shutdown", func(ctx context.Context) {
		<-ctx.Done()
		log.Info(ctx, "CDN> Shutdown tcp log Server")
		_ = listener.Close()
	})

	// Looking for something to dequeue
	s.GoRoutines.Run(ctx, "cdn-waiting-job", func(ctx context.Context) {
		s.waitingJobs(ctx)
	})

	s.GoRoutines.Run(ctx, "service.runTCPLogServer.accept", func(ctx context.Context) {
		for {
			conn, err := listener.Accept()
			if err != nil {
				telemetry.Record(ctx, s.Metrics.tcpServerErrorsCount, 1)
				log.Error(ctx, "unable to accept connection: %v", err)
				return
			}
			s.GoRoutines.Exec(ctx, "cdn-logServer", func(ctx context.Context) {
				telemetry.Record(ctx, s.Metrics.tcpServerHitsCount, 1)
				s.handleConnection(ctx, conn)
			})
		}
	})

	return nil
}

// Handle TCP Connection: Global Rate Limit + Line Rate Limit
func (s *Service) handleConnection(ctx context.Context, conn net.Conn) {
	defer func() {
		_ = conn.Close()
	}()

	lineRateLimiter := NewRateLimiter(ctx, float64(s.Cfg.Log.StepLinesRateLimit), 1)

	bufReader := bufio.NewReader(conn)

	b := make([]byte, 1024)
	currentBuffer := make([]byte, 0)
	for {
		// Can i try to read the next 1024B
		if err := globalRateLimit.WaitN(1024); err != nil {
			fields := log.Fields{}
			fields["stack_trace"] = fmt.Sprintf("%+v", err)
			log.ErrorWithFields(ctx, fields, "cdn.log> %v", err)
			continue
		}

		n, err := bufReader.Read(b)
		if err != nil {
			log.Debug("client left: (%v) %v", conn.RemoteAddr(), err)
			return
		}

		// Search for end of line separator
		for i := 0; i < n; i++ {
			if b[i] != byte(0) {
				currentBuffer = append(currentBuffer, b[i])
				continue
			}

			// Check if we can send line
			if err := lineRateLimiter.WaitN(1); err != nil {
				fields := log.Fields{}
				fields["stack_trace"] = fmt.Sprintf("%+v", err)
				log.ErrorWithFields(ctx, fields, "cdn.log> %v", err)
				continue
			}
			if err := s.handleLogMessage(ctx, currentBuffer); err != nil {
				telemetry.Record(ctx, s.Metrics.tcpServerErrorsCount, 1)
				isErrWithStack := sdk.IsErrorWithStack(err)
				fields := log.Fields{}
				if isErrWithStack {
					fields["stack_trace"] = fmt.Sprintf("%+v", err)
				}
				log.ErrorWithFields(ctx, fields, "cdn.log> %v", err)
			}
			currentBuffer = make([]byte, 0)
		}
	}
}

// Handle Message: Worker/Hatchery
func (s *Service) handleLogMessage(ctx context.Context, messageReceived []byte) error {
	m := hook.Message{}
	if err := m.UnmarshalJSON(messageReceived); err != nil {
		return sdk.WrapError(err, "unable to unmarshall gelf message: %s", string(messageReceived))
	}

	// Extract Signature
	sig, ok := m.Extra["_"+log.ExtraFieldSignature]
	if !ok || sig == "" {
		return sdk.WithStack(fmt.Errorf("signature not found on log message: %+v", m))
	}

	// Unsafe parse of signature to get datas
	var signature log.Signature
	if err := jws.UnsafeParse(sig.(string), &signature); err != nil {
		return err
	}

	switch {
	case signature.Worker != nil:
		telemetry.Record(ctx, s.Metrics.tcpServerStepLogCount, 1)
		return s.handleWorkerLog(ctx, signature.Worker.WorkerName, signature.Worker.WorkerID, sig, m)
	case signature.Service != nil:
		telemetry.Record(ctx, s.Metrics.tcpServerServiceLogCount, 1)
		return s.handleServiceLog(ctx, signature.Service.HatcheryID, signature.Service.HatcheryName, signature.Service.WorkerName, sig, m)
	default:
		return sdk.WithStack(sdk.ErrWrongRequest)
	}
}

// Handle Message from worker (job logs). Enqueue in Redis
func (s *Service) handleWorkerLog(ctx context.Context, workerName string, workerID string, sig interface{}, m hook.Message) error {
	var signature log.Signature

	// Get worker data from cache
	workerData, err := s.getClearWorker(ctx, workerName)
	if err != nil {
		return err
	}

	// Verify Signature
	if err := jws.Verify(workerData.PrivateKey, sig.(string), &signature); err != nil {
		return sdk.WrapError(err, "worker key: %d", len(workerData.PrivateKey))
	}
	if workerData.JobRunID == nil || *workerData.JobRunID != signature.JobID || workerData.ID != workerID {
		return sdk.WithStack(sdk.ErrForbidden)
	}

	terminatedI := m.Extra["_"+log.ExtraFieldTerminated]
	terminated := cast.ToBool(terminatedI)

	hm := handledMessage{
		Signature:    signature,
		Msg:          m,
		IsTerminated: terminated,
	}

	sizeQueueKey := cache.Key(keyJobLogSize, strconv.Itoa(int(hm.Signature.JobID)))
	jobQueue := cache.Key(keyJobLogQueue, strconv.Itoa(int(hm.Signature.JobID)))

	if err := s.sendIntoIncomingQueue(hm, jobQueue, sizeQueueKey); err != nil {
		return err
	}
	return nil
}

func (s *Service) sendIntoIncomingQueue(hm handledMessage, incomingQueue string, sizeKey string) error {
	var currentSize int64
	if _, err := s.Cache.Get(sizeKey, &currentSize); err != nil {
		return err
	}
	if currentSize >= s.Cfg.Log.StepMaxSize && !hm.IsTerminated {
		return nil
	}
	if currentSize >= s.Cfg.Log.StepMaxSize && hm.IsTerminated {
		hm.Msg.Full = "...truncated\n"
		hm.Msg.Level = int32(hook.LOG_WARNING)
	}

	if err := s.Cache.Enqueue(incomingQueue, hm); err != nil {
		return err
	}

	if hm.IsTerminated {
		_ = s.Cache.Delete(sizeKey)
	} else {
		// Update size for the job
		newSize := currentSize + int64(len(hm.Msg.Full))
		if err := s.Cache.SetWithTTL(sizeKey, newSize, 3600*24); err != nil {
			return err
		}
	}
	return nil
}

func buildMessage(hm handledMessage) string {
	val := hm.Msg.Full
	if !strings.HasSuffix(val, "\n") {
		val += "\n"
	}
	return fmt.Sprintf("[%s] %s", getLevelString(hm.Msg.Level), val)
}

func getLevelString(level int32) string {
	var lvl string
	switch level {
	case int32(hook.LOG_DEBUG):
		lvl = "DEBUG"
	case int32(hook.LOG_INFO):
		lvl = "INFO"
	case int32(hook.LOG_NOTICE):
		lvl = "NOTICE"
	case int32(hook.LOG_WARNING):
		lvl = "WARN"
	case int32(hook.LOG_ERR):
		lvl = "ERROR"
	case int32(hook.LOG_CRIT):
		lvl = "CRITICAL"
	case int32(hook.LOG_ALERT):
		lvl = "ALERT"
	case int32(hook.LOG_EMERG):
		lvl = "EMERGENCY"
	}
	return lvl
}

//
func (s *Service) handleServiceLog(ctx context.Context, hatcheryID int64, hatcheryName string, workerName string, sig interface{}, m hook.Message) error {
	var signature log.Signature
	var pk *rsa.PublicKey

	// Get hatchery public key from cache
	cacheData, ok := logCache.Get(fmt.Sprintf("hatchery-key-%d", hatcheryID))
	if !ok {
		// Refresh hatcheries cache
		if err := s.refreshHatcheriesPK(ctx); err != nil {
			return err
		}
		cacheData, ok = logCache.Get(fmt.Sprintf("hatchery-key-%d", hatcheryID))
		if !ok {
			return sdk.WrapError(sdk.ErrForbidden, "unable to find hatchery %d/%s", hatcheryID, hatcheryName)
		}
	}
	pk = cacheData.(*rsa.PublicKey)

	// Verify signature
	if err := jws.Verify(pk, sig.(string), &signature); err != nil {
		return err
	}

	// Get worker + check hatchery ID
	w, err := s.getClearWorker(ctx, workerName)

	if err != nil {
		return err
	}
	if w.HatcheryID == nil {
		return sdk.WrapError(sdk.ErrWrongRequest, "hatchery %d cannot send service log for worker %s started by %s that is no more linked to an hatchery", signature.Service.HatcheryID, w.ID, w.HatcheryName)
	}
	if *w.HatcheryID != signature.Service.HatcheryID {
		return sdk.WrapError(sdk.ErrWrongRequest, "cannot send service log for worker %s from hatchery (expected: %d/actual: %d)", w.ID, *w.HatcheryID, signature.Service.HatcheryID)
	}

	terminatedI := m.Extra["_"+log.ExtraFieldTerminated]
	terminated := cast.ToBool(terminatedI)

	hm := handledMessage{
		Signature:    signature,
		Msg:          m,
		IsTerminated: terminated,
	}

	reqKey := fmt.Sprintf("%d-%d", signature.JobID, signature.Service.RequirementID)
	sizeQueueKey := cache.Key(keyJobLogSize, reqKey)
	jobQueue := cache.Key(keyJobLogQueue, reqKey)

	if err := s.sendIntoIncomingQueue(hm, jobQueue, sizeQueueKey); err != nil {
		return err
	}
	return nil
}

func (s *Service) getClearWorker(ctx context.Context, workerName string) (sdk.Worker, error) {
	workerKey := fmt.Sprintf("worker-%s", workerName)

	// Get worker from cache
	cacheData, ok := logCache.Get(workerKey)
	if ok {
		return cacheData.(sdk.Worker), nil
	}

	// Get worker from API
	w, err := s.Client.WorkerGet(ctx, workerName, cdsclient.WithQueryParameter("withKey", "true"))
	if err != nil {
		return sdk.Worker{}, err
	}
	publicKeyDecoded, err := base64.StdEncoding.DecodeString(string(w.PrivateKey))
	if err != nil {
		return sdk.Worker{}, sdk.WithStack(err)
	}
	w.PrivateKey = publicKeyDecoded
	logCache.Set(workerKey, *w, gocache.DefaultExpiration)

	return *w, nil
}

func (s *Service) refreshHatcheriesPK(ctx context.Context) error {
	srvs, err := s.Client.ServiceConfigurationGet(ctx, sdk.TypeHatchery)
	if err != nil {
		return sdk.WrapError(sdk.ErrNotFound, "unable to find hatcheries")
	}
	for _, s := range srvs {
		publicKey, err := base64.StdEncoding.DecodeString(s.PublicKey)
		if err != nil {
			return sdk.WithStack(err)
		}
		pk, err := jws.NewPublicKeyFromPEM(publicKey)
		if err != nil {
			return sdk.WithStack(err)
		}
		logCache.Set(fmt.Sprintf("hatchery-key-%d", s.ID), pk, gocache.DefaultExpiration)
	}
	return nil
}
<commit_msg>fix(cdn): manage worker without private key in cache (#5566)<commit_after>package cdn

import (
	"bufio"
	"context"
	"crypto/rsa"
	"encoding/base64"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"

	gocache "github.com/patrickmn/go-cache"
	"github.com/spf13/cast"

	"github.com/ovh/cds/engine/cache"
	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/cdsclient"
	"github.com/ovh/cds/sdk/jws"
	"github.com/ovh/cds/sdk/log"
	"github.com/ovh/cds/sdk/log/hook"
	"github.com/ovh/cds/sdk/telemetry"
)

var (
	logCache = gocache.New(20*time.Minute, 20*time.Minute)
)

var globalRateLimit *rateLimiter

type GetWorkerOptions struct {
	NeedPrivateKey bool
}

// Start TCP Server
func (s *Service) runTCPLogServer(ctx context.Context) error {
	// Init hatcheries cache
	if err := s.refreshHatcheriesPK(ctx); err != nil {
		return sdk.WrapError(err, "unable to init hatcheries cache")
	}

	globalRateLimit = NewRateLimiter(ctx, float64(s.Cfg.TCP.GlobalTCPRateLimit), 1024)

	// Start TCP server
	log.Info(ctx, "Starting tcp server %s:%d", s.Cfg.TCP.Addr, s.Cfg.TCP.Port)
	listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.Cfg.TCP.Addr, s.Cfg.TCP.Port))
	if err != nil {
		return sdk.WrapError(err, "unable to start tcp log server")
	}

	//Gracefully shutdown the tcp server
	s.GoRoutines.Run(ctx, "service.runTCPLogServer.shutdown", func(ctx context.Context) {
		<-ctx.Done()
		log.Info(ctx, "CDN> Shutdown tcp log Server")
		_ = listener.Close()
	})

	// Looking for something to dequeue
	s.GoRoutines.Run(ctx, "cdn-waiting-job", func(ctx context.Context) {
		s.waitingJobs(ctx)
	})

	s.GoRoutines.Run(ctx, "service.runTCPLogServer.accept", func(ctx context.Context) {
		for {
			conn, err := listener.Accept()
			if err != nil {
				telemetry.Record(ctx, s.Metrics.tcpServerErrorsCount, 1)
				log.Error(ctx, "unable to accept connection: %v", err)
				return
			}
			s.GoRoutines.Exec(ctx, "cdn-logServer", func(ctx context.Context) {
				telemetry.Record(ctx, s.Metrics.tcpServerHitsCount, 1)
				s.handleConnection(ctx, conn)
			})
		}
	})

	return nil
}

// Handle TCP Connection: Global Rate Limit + Line Rate Limit
func (s *Service) handleConnection(ctx context.Context, conn net.Conn) {
	defer func() {
		_ = conn.Close()
	}()

	lineRateLimiter := NewRateLimiter(ctx, float64(s.Cfg.Log.StepLinesRateLimit), 1)

	bufReader := bufio.NewReader(conn)

	b := make([]byte, 1024)
	currentBuffer := make([]byte, 0)
	for {
		// Can i try to read the next 1024B
		if err := globalRateLimit.WaitN(1024); err != nil {
			fields := log.Fields{}
			fields["stack_trace"] = fmt.Sprintf("%+v", err)
			log.ErrorWithFields(ctx, fields, "cdn.log> %v", err)
			continue
		}

		n, err := bufReader.Read(b)
		if err != nil {
			log.Debug("client left: (%v) %v", conn.RemoteAddr(), err)
			return
		}

		// Search for end of line separator
		for i := 0; i < n; i++ {
			if b[i] != byte(0) {
				currentBuffer = append(currentBuffer, b[i])
				continue
			}

			// Check if we can send line
			if err := lineRateLimiter.WaitN(1); err != nil {
				fields := log.Fields{}
				fields["stack_trace"] = fmt.Sprintf("%+v", err)
				log.ErrorWithFields(ctx, fields, "cdn.log> %v", err)
				continue
			}
			if err := s.handleLogMessage(ctx, currentBuffer); err != nil {
				telemetry.Record(ctx, s.Metrics.tcpServerErrorsCount, 1)
				isErrWithStack := sdk.IsErrorWithStack(err)
				fields := log.Fields{}
				if isErrWithStack {
					fields["stack_trace"] = fmt.Sprintf("%+v", err)
				}
				log.ErrorWithFields(ctx, fields, "cdn.log> %v", err)
			}
			currentBuffer = make([]byte, 0)
		}
	}
}

// Handle Message: Worker/Hatchery
func (s *Service) handleLogMessage(ctx context.Context, messageReceived []byte) error {
	m := hook.Message{}
	if err := m.UnmarshalJSON(messageReceived); err != nil {
		return sdk.WrapError(err, "unable to unmarshall gelf message: %s", string(messageReceived))
	}

	// Extract Signature
	sig, ok := m.Extra["_"+log.ExtraFieldSignature]
	if !ok || sig == "" {
		return sdk.WithStack(fmt.Errorf("signature not found on log message: %+v", m))
	}

	// Unsafe parse of signature to get datas
	var signature log.Signature
	if err := jws.UnsafeParse(sig.(string), &signature); err != nil {
		return err
	}

	switch {
	case signature.Worker != nil:
		telemetry.Record(ctx, s.Metrics.tcpServerStepLogCount, 1)
		return s.handleWorkerLog(ctx, signature.Worker.WorkerName, signature.Worker.WorkerID, sig, m)
	case signature.Service != nil:
		telemetry.Record(ctx, s.Metrics.tcpServerServiceLogCount, 1)
		return s.handleServiceLog(ctx, signature.Service.HatcheryID, signature.Service.HatcheryName, signature.Service.WorkerName, sig, m)
	default:
		return sdk.WithStack(sdk.ErrWrongRequest)
	}
}

// Handle Message from worker (job logs). Enqueue in Redis
func (s *Service) handleWorkerLog(ctx context.Context, workerName string, workerID string, sig interface{}, m hook.Message) error {
	var signature log.Signature

	// Get worker data from cache
	workerData, err := s.getWorker(ctx, workerName, GetWorkerOptions{NeedPrivateKey: true})
	if err != nil {
		return err
	}

	// Verify Signature
	if err := jws.Verify(workerData.PrivateKey, sig.(string), &signature); err != nil {
		return sdk.WrapError(err, "worker key: %d", len(workerData.PrivateKey))
	}
	if workerData.JobRunID == nil || *workerData.JobRunID != signature.JobID || workerData.ID != workerID {
		return sdk.WithStack(sdk.ErrForbidden)
	}

	terminatedI := m.Extra["_"+log.ExtraFieldTerminated]
	terminated := cast.ToBool(terminatedI)

	hm := handledMessage{
		Signature:    signature,
		Msg:          m,
		IsTerminated: terminated,
	}

	sizeQueueKey := cache.Key(keyJobLogSize, strconv.Itoa(int(hm.Signature.JobID)))
	jobQueue := cache.Key(keyJobLogQueue, strconv.Itoa(int(hm.Signature.JobID)))

	if err := s.sendIntoIncomingQueue(hm, jobQueue, sizeQueueKey); err != nil {
		return err
	}
	return nil
}

func (s *Service) sendIntoIncomingQueue(hm handledMessage, incomingQueue string, sizeKey string) error {
	var currentSize int64
	if _, err := s.Cache.Get(sizeKey, &currentSize); err != nil {
		return err
	}
	if currentSize >= s.Cfg.Log.StepMaxSize && !hm.IsTerminated {
		return nil
	}
	if currentSize >= s.Cfg.Log.StepMaxSize && hm.IsTerminated {
		hm.Msg.Full = "...truncated\n"
		hm.Msg.Level = int32(hook.LOG_WARNING)
	}

	if err := s.Cache.Enqueue(incomingQueue, hm); err != nil {
		return err
	}

	if hm.IsTerminated {
		_ = s.Cache.Delete(sizeKey)
	} else {
		// Update size for the job
		newSize := currentSize + int64(len(hm.Msg.Full))
		if err := s.Cache.SetWithTTL(sizeKey, newSize, 3600*24); err != nil {
			return err
		}
	}
	return nil
}

func buildMessage(hm handledMessage) string {
	val := hm.Msg.Full
	if !strings.HasSuffix(val, "\n") {
		val += "\n"
	}
	return fmt.Sprintf("[%s] %s", getLevelString(hm.Msg.Level), val)
}

func getLevelString(level int32) string {
	var lvl string
	switch level {
	case int32(hook.LOG_DEBUG):
		lvl = "DEBUG"
	case int32(hook.LOG_INFO):
		lvl = "INFO"
	case int32(hook.LOG_NOTICE):
		lvl = "NOTICE"
	case int32(hook.LOG_WARNING):
		lvl = "WARN"
	case int32(hook.LOG_ERR):
		lvl = "ERROR"
	case int32(hook.LOG_CRIT):
		lvl = "CRITICAL"
	case int32(hook.LOG_ALERT):
		lvl = "ALERT"
	case int32(hook.LOG_EMERG):
		lvl = "EMERGENCY"
	}
	return lvl
}

//
func (s *Service) handleServiceLog(ctx context.Context, hatcheryID int64, hatcheryName string, workerName string, sig interface{}, m hook.Message) error {
	var signature log.Signature
	var pk *rsa.PublicKey

	// Get hatchery public key from cache
	cacheData, ok := logCache.Get(fmt.Sprintf("hatchery-key-%d", hatcheryID))
	if !ok {
		// Refresh hatcheries cache
		if err := s.refreshHatcheriesPK(ctx); err != nil {
			return err
		}
		cacheData, ok = logCache.Get(fmt.Sprintf("hatchery-key-%d", hatcheryID))
		if !ok {
			return sdk.WrapError(sdk.ErrForbidden, "unable to find hatchery %d/%s", hatcheryID, hatcheryName)
		}
	}
	pk = cacheData.(*rsa.PublicKey)

	// Verify signature
	if err := jws.Verify(pk, sig.(string), &signature); err != nil {
		return err
	}

	// Get worker + check hatchery ID
	w, err := s.getWorker(ctx, workerName, GetWorkerOptions{NeedPrivateKey: false})
	if err != nil {
		return err
	}
	if w.HatcheryID == nil {
		return sdk.WrapError(sdk.ErrWrongRequest, "hatchery %d cannot send service log for worker %s started by %s that is no more linked to an hatchery", signature.Service.HatcheryID, w.ID, w.HatcheryName)
	}
	if *w.HatcheryID != signature.Service.HatcheryID {
		return sdk.WrapError(sdk.ErrWrongRequest, "cannot send service log for worker %s from hatchery (expected: %d/actual: %d)", w.ID, *w.HatcheryID, signature.Service.HatcheryID)
	}

	terminatedI := m.Extra["_"+log.ExtraFieldTerminated]
	terminated := cast.ToBool(terminatedI)

	hm := handledMessage{
		Signature:    signature,
		Msg:          m,
		IsTerminated: terminated,
	}

	reqKey := fmt.Sprintf("%d-%d", signature.JobID, signature.Service.RequirementID)
	sizeQueueKey := cache.Key(keyJobLogSize, reqKey)
	jobQueue := cache.Key(keyJobLogQueue, reqKey)

	if err := s.sendIntoIncomingQueue(hm, jobQueue, sizeQueueKey); err != nil {
		return err
	}
	return nil
}

func (s *Service) getWorker(ctx context.Context, workerName string, opts GetWorkerOptions) (sdk.Worker, error) {
	workerKey := fmt.Sprintf("worker-%s", workerName)

	// Get worker from cache
	cacheData, ok := logCache.Get(workerKey)
	if ok {
	    w, ok := cacheData.(sdk.Worker)
	    if ok && (!opts.NeedPrivateKey || len(w.PrivateKey) > 0) {
		      return w, nil
		  }
	}

	// Get worker from API
	w, err := s.Client.WorkerGet(ctx, workerName, cdsclient.WithQueryParameter("withKey", "true"))
	if err != nil {
		return sdk.Worker{}, err
	}
	privateKeyDecoded, err := base64.StdEncoding.DecodeString(string(w.PrivateKey))
	if err != nil {
		return sdk.Worker{}, sdk.WithStack(err)
	}
	w.PrivateKey = privateKeyDecoded
	logCache.Set(workerKey, *w, gocache.DefaultExpiration)

	return *w, nil
}

func (s *Service) refreshHatcheriesPK(ctx context.Context) error {
	srvs, err := s.Client.ServiceConfigurationGet(ctx, sdk.TypeHatchery)
	if err != nil {
		return sdk.WrapError(sdk.ErrNotFound, "unable to find hatcheries")
	}
	for _, s := range srvs {
		publicKey, err := base64.StdEncoding.DecodeString(s.PublicKey)
		if err != nil {
			return sdk.WithStack(err)
		}
		pk, err := jws.NewPublicKeyFromPEM(publicKey)
		if err != nil {
			return sdk.WithStack(err)
		}
		logCache.Set(fmt.Sprintf("hatchery-key-%d", s.ID), pk, gocache.DefaultExpiration)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Authors of Cilium
//
// 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 helpers

import (
	"fmt"
	"strings"
)

// ContainerExec executes cmd in the container with the provided name along with
// any other additional arguments needed.
func (s *SSHMeta) ContainerExec(name string, cmd string, optionalArgs ...string) *CmdRes {
	optionalArgsCoalesced := ""
	if len(optionalArgs) > 0 {
		optionalArgsCoalesced = strings.Join(optionalArgs, " ")
	}
	dockerCmd := fmt.Sprintf("docker exec -i %s %s %s", optionalArgsCoalesced, name, cmd)
	return s.Exec(dockerCmd)
}

// ContainerCreate is a wrapper for `docker run`. It runs an instance of the
// specified Docker image with the provided network, name, and options.
func (s *SSHMeta) ContainerCreate(name, image, net, options string) *CmdRes {
	cmd := fmt.Sprintf(
		"docker run -d --name %s --net %s %s %s", name, net, options, image)
	log.Debugf("spinning up container with command '%v'", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerRm is a wrapper around `docker rm -f`. It forcibly removes the
// Docker container of the provided name.
func (s *SSHMeta) ContainerRm(name string) *CmdRes {
	cmd := fmt.Sprintf("docker rm -f %s", name)
	log.Debugf("removing container with command '%v'", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerInspect runs `docker inspect` for the container with the provided
// name.
func (s *SSHMeta) ContainerInspect(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker inspect %s", name))
}

// ContainerInspectNet returns a map of Docker networking information fields and
// their associated values for the container of the provided name. An error
// is returned if the networking information could not be retrieved.
func (s *SSHMeta) ContainerInspectNet(name string) (map[string]string, error) {
	res := s.ContainerInspect(name)
	properties := map[string]string{
		"EndpointID":        "EndpointID",
		"GlobalIPv6Address": IPv6,
		"IPAddress":         IPv4,
		"NetworkID":         "NetworkID",
		"IPv6Gateway":       "IPv6Gateway",
	}

	if !res.WasSuccessful() {
		return nil, fmt.Errorf("could not inspect container %s", name)
	}
	filter := fmt.Sprintf(`{ [0].NetworkSettings.Networks.%s }`, CiliumDockerNetwork)
	result := map[string]string{
		Name: name,
	}
	data, err := res.FindResults(filter)
	if err != nil {
		return nil, err
	}
	for _, val := range data {
		iface := val.Interface()
		for k, v := range iface.(map[string]interface{}) {
			if key, ok := properties[k]; ok {
				result[key] = fmt.Sprintf("%s", v)
			}
		}
	}
	return result, nil
}

// NetworkCreate creates a Docker network of the provided name with the
// specified subnet. It is a wrapper around `docker network create`.
func (s *SSHMeta) NetworkCreate(name string, subnet string) *CmdRes {
	if subnet == "" {
		subnet = "::1/112"
	}
	cmd := fmt.Sprintf(
		"docker network create --ipv6 --subnet %s --driver cilium --ipam-driver cilium %s",
		subnet, name)
	return s.ExecWithSudo(cmd)
}

// NetworkDelete deletes the Docker network of the provided name. It is a wrapper
// around `docker network rm`.
func (s *SSHMeta) NetworkDelete(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network rm  %s", name))
}

// NetworkGet returns all of the Docker network configuration for the provided
// network. It is a wrapper around `docker network inspect`.
func (s *SSHMeta) NetworkGet(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network inspect %s", name))
}

func (s *SSHMeta) execCmd(cmd string) *CmdRes {
	return s.ExecWithSudo(cmd)
}

// SampleContainersActions creates or deletes various containers used for
// testing Cilium and adds said containers to the provided Docker network.
func (s *SSHMeta) SampleContainersActions(mode string, networkName string) {
	images := map[string]string{
		Httpd1: HttpdImage,
		Httpd2: HttpdImage,
		Httpd3: HttpdImage,
		App1:   NetperfImage,
		App2:   NetperfImage,
		App3:   NetperfImage,
	}

	switch mode {
	case Create:
		for k, v := range images {
			s.ContainerCreate(k, v, networkName, fmt.Sprintf("-l id.%s", k))
		}
	case Delete:
		for k := range images {
			s.ContainerRm(k)
		}
	}
}

// GatherDockerLogs dumps docker containers logs output to the directory
// testResultsPath
func (s *SSHMeta) GatherDockerLogs() {
	res := s.Exec("docker ps -aq")
	if !res.WasSuccessful() {
		log.WithField("error", res.CombineOutput()).Errorf("cannot get docker logs")
		return
	}
	commands := map[string]string{}
	for _, k := range res.ByLines() {
		key := fmt.Sprintf("docker logs %s", k)
		commands[key] = fmt.Sprintf("container_%s.logs", k)
	}

	testPath, err := CreateReportDirectory()
	if err != nil {
		s.logger.WithError(err).Errorf(
			"cannot create test results path '%s'", testPath)
		return
	}
	reportMap(testPath, commands, s)
}
<commit_msg>test/helpers: use .log extension instead of .logs for container logs<commit_after>// Copyright 2017 Authors of Cilium
//
// 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 helpers

import (
	"fmt"
	"strings"
)

// ContainerExec executes cmd in the container with the provided name along with
// any other additional arguments needed.
func (s *SSHMeta) ContainerExec(name string, cmd string, optionalArgs ...string) *CmdRes {
	optionalArgsCoalesced := ""
	if len(optionalArgs) > 0 {
		optionalArgsCoalesced = strings.Join(optionalArgs, " ")
	}
	dockerCmd := fmt.Sprintf("docker exec -i %s %s %s", optionalArgsCoalesced, name, cmd)
	return s.Exec(dockerCmd)
}

// ContainerCreate is a wrapper for `docker run`. It runs an instance of the
// specified Docker image with the provided network, name, and options.
func (s *SSHMeta) ContainerCreate(name, image, net, options string) *CmdRes {
	cmd := fmt.Sprintf(
		"docker run -d --name %s --net %s %s %s", name, net, options, image)
	log.Debugf("spinning up container with command '%v'", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerRm is a wrapper around `docker rm -f`. It forcibly removes the
// Docker container of the provided name.
func (s *SSHMeta) ContainerRm(name string) *CmdRes {
	cmd := fmt.Sprintf("docker rm -f %s", name)
	log.Debugf("removing container with command '%v'", cmd)
	return s.ExecWithSudo(cmd)
}

// ContainerInspect runs `docker inspect` for the container with the provided
// name.
func (s *SSHMeta) ContainerInspect(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker inspect %s", name))
}

// ContainerInspectNet returns a map of Docker networking information fields and
// their associated values for the container of the provided name. An error
// is returned if the networking information could not be retrieved.
func (s *SSHMeta) ContainerInspectNet(name string) (map[string]string, error) {
	res := s.ContainerInspect(name)
	properties := map[string]string{
		"EndpointID":        "EndpointID",
		"GlobalIPv6Address": IPv6,
		"IPAddress":         IPv4,
		"NetworkID":         "NetworkID",
		"IPv6Gateway":       "IPv6Gateway",
	}

	if !res.WasSuccessful() {
		return nil, fmt.Errorf("could not inspect container %s", name)
	}
	filter := fmt.Sprintf(`{ [0].NetworkSettings.Networks.%s }`, CiliumDockerNetwork)
	result := map[string]string{
		Name: name,
	}
	data, err := res.FindResults(filter)
	if err != nil {
		return nil, err
	}
	for _, val := range data {
		iface := val.Interface()
		for k, v := range iface.(map[string]interface{}) {
			if key, ok := properties[k]; ok {
				result[key] = fmt.Sprintf("%s", v)
			}
		}
	}
	return result, nil
}

// NetworkCreate creates a Docker network of the provided name with the
// specified subnet. It is a wrapper around `docker network create`.
func (s *SSHMeta) NetworkCreate(name string, subnet string) *CmdRes {
	if subnet == "" {
		subnet = "::1/112"
	}
	cmd := fmt.Sprintf(
		"docker network create --ipv6 --subnet %s --driver cilium --ipam-driver cilium %s",
		subnet, name)
	return s.ExecWithSudo(cmd)
}

// NetworkDelete deletes the Docker network of the provided name. It is a wrapper
// around `docker network rm`.
func (s *SSHMeta) NetworkDelete(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network rm  %s", name))
}

// NetworkGet returns all of the Docker network configuration for the provided
// network. It is a wrapper around `docker network inspect`.
func (s *SSHMeta) NetworkGet(name string) *CmdRes {
	return s.ExecWithSudo(fmt.Sprintf("docker network inspect %s", name))
}

func (s *SSHMeta) execCmd(cmd string) *CmdRes {
	return s.ExecWithSudo(cmd)
}

// SampleContainersActions creates or deletes various containers used for
// testing Cilium and adds said containers to the provided Docker network.
func (s *SSHMeta) SampleContainersActions(mode string, networkName string) {
	images := map[string]string{
		Httpd1: HttpdImage,
		Httpd2: HttpdImage,
		Httpd3: HttpdImage,
		App1:   NetperfImage,
		App2:   NetperfImage,
		App3:   NetperfImage,
	}

	switch mode {
	case Create:
		for k, v := range images {
			s.ContainerCreate(k, v, networkName, fmt.Sprintf("-l id.%s", k))
		}
	case Delete:
		for k := range images {
			s.ContainerRm(k)
		}
	}
}

// GatherDockerLogs dumps docker containers logs output to the directory
// testResultsPath
func (s *SSHMeta) GatherDockerLogs() {
	res := s.Exec("docker ps -aq")
	if !res.WasSuccessful() {
		log.WithField("error", res.CombineOutput()).Errorf("cannot get docker logs")
		return
	}
	commands := map[string]string{}
	for _, k := range res.ByLines() {
		key := fmt.Sprintf("docker logs %s", k)
		commands[key] = fmt.Sprintf("container_%s.log", k)
	}

	testPath, err := CreateReportDirectory()
	if err != nil {
		s.logger.WithError(err).Errorf(
			"cannot create test results path '%s'", testPath)
		return
	}
	reportMap(testPath, commands, s)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/aes"
	"crypto/cipher"
	"fmt"
	"net"

	"github.com/alicebob/alac"
	"github.com/mesilliac/pulse-simple"
)

func writeUdp(aesiv, aeskey []byte, fmtp []int) {
	udpaddr, err := net.ResolveUDPAddr("udp", ":6000")
	if err != nil {
		panic(err)
	}
	udpconn, err := net.ListenUDP("udp", udpaddr)
	if err != nil {
		panic(err)
	}
	// Never closes zomg

	dec, err := alac.New()
	if err != nil {
		panic(err)
	}

	// packetchan := make(chan []byte, 1000)
	// go CreateALACPlayer(fmtp, packetchan)

	ss := pulse.SampleSpec{pulse.SAMPLE_S16LE, 44100, 2}
	stream, _ := pulse.Playback("ituned", "my stream", &ss)
	defer stream.Free()
	defer stream.Drain()

	buf := make([]byte, 1024*16)
	for {
		n, _, err := udpconn.ReadFromUDP(buf)
		if err != nil {
			panic(err)
		}
		packet := buf[:n]
		audio := packet[12:]
		todec := audio
		block, err := aes.NewCipher(aeskey)
		if err != nil {
			panic(err)
		}
		AESDec := cipher.NewCBCDecrypter(block, aesiv)
		for len(todec) >= aes.BlockSize {
			AESDec.CryptBlocks(todec[:aes.BlockSize], todec[:aes.BlockSize])
			todec = todec[aes.BlockSize:]
		}

		decoded := dec.Decode(audio)
		// fmt.Printf("audio packet %d->%d\n", len(audio), len(decoded))
		// send := make([]byte, len(audio))
		// copy(send, audio)
		// packetchan <- send
		stream.Write(decoded)
	}
}
<commit_msg>make things compile :/<commit_after>package main

import (
	"crypto/aes"
	"crypto/cipher"
	"net"

	"github.com/alicebob/alac"
	"github.com/mesilliac/pulse-simple"
)

func writeUdp(aesiv, aeskey []byte, fmtp []int) {
	udpaddr, err := net.ResolveUDPAddr("udp", ":6000")
	if err != nil {
		panic(err)
	}
	udpconn, err := net.ListenUDP("udp", udpaddr)
	if err != nil {
		panic(err)
	}
	// Never closes zomg

	dec, err := alac.New()
	if err != nil {
		panic(err)
	}

	// packetchan := make(chan []byte, 1000)
	// go CreateALACPlayer(fmtp, packetchan)

	ss := pulse.SampleSpec{pulse.SAMPLE_S16LE, 44100, 2}
	stream, _ := pulse.Playback("ituned", "my stream", &ss)
	defer stream.Free()
	defer stream.Drain()

	buf := make([]byte, 1024*16)
	for {
		n, _, err := udpconn.ReadFromUDP(buf)
		if err != nil {
			panic(err)
		}
		packet := buf[:n]
		audio := packet[12:]
		todec := audio
		block, err := aes.NewCipher(aeskey)
		if err != nil {
			panic(err)
		}
		AESDec := cipher.NewCBCDecrypter(block, aesiv)
		for len(todec) >= aes.BlockSize {
			AESDec.CryptBlocks(todec[:aes.BlockSize], todec[:aes.BlockSize])
			todec = todec[aes.BlockSize:]
		}

		decoded := dec.Decode(audio)
		// fmt.Printf("audio packet %d->%d\n", len(audio), len(decoded))
		// send := make([]byte, len(audio))
		// copy(send, audio)
		// packetchan <- send
		stream.Write(decoded)
	}
}
<|endoftext|>


<commit_before>package main

import "github.com/fhs/gompd/mpd"

type playerRequestType int

const (
	syncLibrary playerRequestType = iota
	syncPlaylist
	prev
	play
	next
)

type playerRequest struct {
	request playerRequestType
	err     chan error
}

/*Dial Connects to mpd server.*/
func Dial(network, addr string) (p *Player, err error) {
	// connect to mpd
	p = new(Player)
	p.stop = make(chan bool)
	p.requestChannel = make(chan *playerRequest)
	p.network = network
	p.addr = addr
	err = p.connect()
	if err != nil {
		return p, err
	}

	// initialize library
	err = p.SyncLibrary()
	if err != nil {
		p.Close()
		return
	}
	// initialize playlist
	err = p.SyncPlaylist()
	go p.daemon()
	return
}

/*Player represents mpd control interface.*/
type Player struct {
	network        string
	addr           string
	conn           *mpd.Client
	stop           chan bool
	requestChannel chan *playerRequest
	library        []mpd.Attrs
	playlist       []mpd.Attrs
}

func (p *Player) daemon() {
loop:
	for {
		select {
		case <-p.stop:
			break loop
		case r := <-p.requestChannel:
			switch r.request {
			case prev:
				r.err <- p.conn.Previous()
			case play:
				r.err <- p.conn.Play(-1)
			case next:
				r.err <- p.conn.Next()
			}
		}
	}
}

func (p *Player) connect() error {
	conn, err := mpd.Dial(p.network, p.addr)
	if err != nil {
		return err
	}
	p.conn = conn
	return nil
}

/*SyncLibrary updates Player.library*/
func (p *Player) SyncLibrary() error {
	library, err := p.conn.ListAllInfo("/")
	if err != nil {
		return err
	}
	p.library = library
	return nil
}

/*Library returns mpd library song list.*/
func (p *Player) Library() []mpd.Attrs {
	return p.library
}

/*SyncPlaylist updates Player.playlist*/
func (p *Player) SyncPlaylist() error {
	playlist, err := p.conn.PlaylistInfo(-1, -1)
	if err != nil {
		return err
	}
	p.playlist = playlist
	return nil
}

/*Playlist returns json string mpd playlist.*/
func (p *Player) Playlist() []mpd.Attrs {
	return p.playlist
}

func (p *Player) request(req playerRequestType) error {
	r := new(playerRequest)
	r.request = req
	r.err = make(chan error)
	p.requestChannel <- r
	return <-r.err
}

/*Prev song.*/
func (p *Player) Prev() error {
	return p.request(prev)
}

/*Play or resume song.*/
func (p *Player) Play() error {
	return p.request(play)
}

/*Pause song.*/
func (p *Player) Pause() error {
	return p.conn.Pause(true)
}

/*Next song.*/
func (p *Player) Next() error {
	return p.request(next)
}

/*Close mpd connection.*/
func (p *Player) Close() error {
	p.stop <- true
	return p.conn.Close()
}
<commit_msg>rename playerRequest to connMessage<commit_after>package main

import "github.com/fhs/gompd/mpd"

type connMessageType int

const (
	syncLibrary connMessageType = iota
	syncPlaylist
	prev
	play
	next
)

type connMessage struct {
	request connMessageType
	err     chan error
}

/*Dial Connects to mpd server.*/
func Dial(network, addr string) (p *Player, err error) {
	// connect to mpd
	p = new(Player)
	p.stop = make(chan bool)
	p.connC = make(chan *connMessage)
	p.network = network
	p.addr = addr
	err = p.connect()
	if err != nil {
		return p, err
	}

	// initialize library
	err = p.SyncLibrary()
	if err != nil {
		p.Close()
		return
	}
	// initialize playlist
	err = p.SyncPlaylist()
	go p.connDaemon()
	return
}

/*Player represents mpd control interface.*/
type Player struct {
	network  string
	addr     string
	conn     *mpd.Client
	stop     chan bool
	connC    chan *connMessage
	library  []mpd.Attrs
	playlist []mpd.Attrs
}

func (p *Player) connDaemon() {
loop:
	for {
		select {
		case <-p.stop:
			break loop
		case m := <-p.connC:
			switch m.request {
			case prev:
				m.err <- p.conn.Previous()
			case play:
				m.err <- p.conn.Play(-1)
			case next:
				m.err <- p.conn.Next()
			}
		}
	}
}

func (p *Player) connect() error {
	conn, err := mpd.Dial(p.network, p.addr)
	if err != nil {
		return err
	}
	p.conn = conn
	return nil
}

/*SyncLibrary updates Player.library*/
func (p *Player) SyncLibrary() error {
	library, err := p.conn.ListAllInfo("/")
	if err != nil {
		return err
	}
	p.library = library
	return nil
}

/*Library returns mpd library song list.*/
func (p *Player) Library() []mpd.Attrs {
	return p.library
}

/*SyncPlaylist updates Player.playlist*/
func (p *Player) SyncPlaylist() error {
	playlist, err := p.conn.PlaylistInfo(-1, -1)
	if err != nil {
		return err
	}
	p.playlist = playlist
	return nil
}

/*Playlist returns json string mpd playlist.*/
func (p *Player) Playlist() []mpd.Attrs {
	return p.playlist
}

func (p *Player) request(req connMessageType) error {
	r := new(connMessage)
	r.request = req
	r.err = make(chan error)
	p.connC <- r
	return <-r.err
}

/*Prev song.*/
func (p *Player) Prev() error {
	return p.request(prev)
}

/*Play or resume song.*/
func (p *Player) Play() error {
	return p.request(play)
}

/*Pause song.*/
func (p *Player) Pause() error {
	return p.conn.Pause(true)
}

/*Next song.*/
func (p *Player) Next() error {
	return p.request(next)
}

/*Close mpd connection.*/
func (p *Player) Close() error {
	p.stop <- true
	return p.conn.Close()
}
<|endoftext|>


<commit_before><commit_msg>Add maxLength/maxItems/maxProperties support to cel.Compile.<commit_after><|endoftext|>