<commit_before>package groupmebot

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strings"
)

type GroupMeBot struct {
	ID               string `json:"bot_id"`
	GroupID          string `json:"group_id"`
	Host             string `json:"host"`
	Port             string `json:"port"`
	TrackBotMessages bool   `json:"trackbotmessages"`
	Server           string
	Hooks            map[string]func(InboundMessage) string
	Logger
}

type InboundMessage struct {
	Id           string                   `json:"id"`
	Avatar_url   string                   `json:"avatar_url"`
	Name         string                   `json:"name"`
	Sender_id    string                   `json:"sender_id"`
	Sender_type  string                   `json:"sender_type"`
	System       bool                     `json:"system"`
	Text         string                   `json:"text"`
	Source_guid  string                   `json:"source_guid"`
	Created_at   int                      `json:"created_at"`
	User_id      string                   `json:"user_id"`
	Group_id     string                   `json:"group_id"`
	Favorited_by []string                 `json:"favorited_by"`
	Attachments  []map[string]interface{} `json:"attachments"`
}

type OutboundMessage struct {
	ID   string `json:"bot_id"`
	Text string `json:"text"`
}

// A CSVLogger comes with the bot, but any logger can be substituted so long as
// it satisfies this interface
type Logger interface {
	LogMessage(msg InboundMessage)
}

/// NewBotFromJson (json cfg file name)
/// This reads a json file containing the keys
/// See the example bot_cfg.json
/// Returns err from ioutil if file can not be read
func NewBotFromJson(filename string) (*GroupMeBot, error) {
	file, err := ioutil.ReadFile(filename)

	var bot GroupMeBot
	if err != nil {
		log.Fatal("Error reading bot configuration json file")
		return nil, err
	}

	// Parse out information from file
	json.Unmarshal(file, &bot)

	bot.Server = bot.Host + ":" + bot.Port
	log.Printf("Creating bot at %s\n", bot.Server)
	bot.Hooks = make(map[string]func(InboundMessage) string)

	return &bot, err
}

/// Updates existing bot with parameters from JSON filename
/// When using a Logging interface create the bot with the logger first and then
/// configure it with json
func (b *GroupMeBot) ConfigureFromJson(filename string) error {
	file, err := ioutil.ReadFile(filename)

	if err != nil {
		log.Fatal("Error reading bot configuration json file")
		return err
	}

	// Parse out information from file
	json.Unmarshal(file, b)

	b.Server = b.Host + ":" + b.Port
	log.Printf("Creating b at %s\n", b.Server)
	b.Hooks = make(map[string]func(InboundMessage) string)

	return err
}

func (b *GroupMeBot) SendMessage(outMessage string) (*http.Response, error) {
	msg := OutboundMessage{b.ID, outMessage}
	payload, err := json.Marshal(msg)
	if err != nil {
		return nil, err
	}

	j_payload := string(payload)
	return http.Post("https://api.groupme.com/v3/bots/post", "application/json", strings.NewReader(j_payload))
}

func (b *GroupMeBot) AddHook(trigger string, response func(InboundMessage) string) {
	b.Hooks[trigger] = response
}

func (b *GroupMeBot) HandleMessage(msg InboundMessage) {
	resp := ""
	for trig, hook := range b.Hooks {
		matched, err := regexp.MatchString(trig, msg.Text)

		if matched {
			resp = hook(msg)
		} else if err != nil {
			log.Fatal("Error matching:", err)
		}

	}
	if len(resp) > 0 {
		log.Printf("Sending message: %v\n", resp)
		_, err := b.SendMessage(resp)
		if err != nil {
			log.Fatal("Error when sending.", err)
		}
	}

}

/*
 This is legitimate black magic, this is pretty cool, not usually able to do
 things like this in other languages. This is a function that takes
 a list of trigger functions and returns a function that can handle the Server
 Requests
*/
func (b *GroupMeBot) Handler() http.HandlerFunc {
	// Request Handler function

	return func(w http.ResponseWriter, req *http.Request) {
		if req.Method == "POST" {
			//log.Println("Bot recieving and handling message.")
			defer req.Body.Close()
			var msg InboundMessage
			err := json.NewDecoder(req.Body).Decode(&msg)
			if err != nil {
				log.Println("Couldn't parse the request body")
				msg.Sender_type = "bot"
			}
			if msg.Sender_type != "bot" || b.TrackBotMessages {
				b.LogMessage(msg)
				// Find hook by running through hooklist
				b.HandleMessage(msg)
			}
		} else {
			//log.Println("Bot not responding to unknown message")
			//io.WriteString(w, "GOTEM")
		}
	}
}
<commit_msg>Bot is now created as an object then updated with json data<commit_after>package groupmebot

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
	"strings"
)

type GroupMeBot struct {
	ID               string `json:"bot_id"`
	GroupID          string `json:"group_id"`
	Host             string `json:"host"`
	Port             string `json:"port"`
	TrackBotMessages bool   `json:"trackbotmessages"`
	Server           string
	Hooks            map[string]func(InboundMessage) string
	Logger
}

type InboundMessage struct {
	Id           string                   `json:"id"`
	Avatar_url   string                   `json:"avatar_url"`
	Name         string                   `json:"name"`
	Sender_id    string                   `json:"sender_id"`
	Sender_type  string                   `json:"sender_type"`
	System       bool                     `json:"system"`
	Text         string                   `json:"text"`
	Source_guid  string                   `json:"source_guid"`
	Created_at   int                      `json:"created_at"`
	User_id      string                   `json:"user_id"`
	Group_id     string                   `json:"group_id"`
	Favorited_by []string                 `json:"favorited_by"`
	Attachments  []map[string]interface{} `json:"attachments"`
}

type OutboundMessage struct {
	ID   string `json:"bot_id"`
	Text string `json:"text"`
}

// A CSVLogger comes with the bot, but any logger can be substituted so long as
// it satisfies this interface
type Logger interface {
	LogMessage(msg InboundMessage)
}

/// This reads a json file containing the keys
/// See the example bot_cfg.json
/// Updates existing bot with parameters from JSON filename
/// Returns err from ioutil if file can not be read
func (b *GroupMeBot) ConfigureFromJson(filename string) error {
	file, err := ioutil.ReadFile(filename)

	if err != nil {
		log.Fatal("Error reading bot configuration json file")
		return err
	}

	// Parse out information from file
	json.Unmarshal(file, b)

	b.Server = b.Host + ":" + b.Port
	log.Printf("Creating b at %s\n", b.Server)
	b.Hooks = make(map[string]func(InboundMessage) string)

	return err
}

func (b *GroupMeBot) SendMessage(outMessage string) (*http.Response, error) {
	msg := OutboundMessage{b.ID, outMessage}
	payload, err := json.Marshal(msg)
	if err != nil {
		return nil, err
	}

	j_payload := string(payload)
	return http.Post("https://api.groupme.com/v3/bots/post", "application/json", strings.NewReader(j_payload))
}

func (b *GroupMeBot) AddHook(trigger string, response func(InboundMessage) string) {
	b.Hooks[trigger] = response
}

func (b *GroupMeBot) HandleMessage(msg InboundMessage) {
	resp := ""
	for trig, hook := range b.Hooks {
		matched, err := regexp.MatchString(trig, msg.Text)

		if matched {
			resp = hook(msg)
		} else if err != nil {
			log.Fatal("Error matching:", err)
		}

	}
	if len(resp) > 0 {
		log.Printf("Sending message: %v\n", resp)
		_, err := b.SendMessage(resp)
		if err != nil {
			log.Fatal("Error when sending.", err)
		}
	}

}

/*
 This is legitimate black magic, this is pretty cool, not usually able to do
 things like this in other languages. This is a function that takes
 a list of trigger functions and returns a function that can handle the Server
 Requests
*/
func (b *GroupMeBot) Handler() http.HandlerFunc {
	// Request Handler function

	return func(w http.ResponseWriter, req *http.Request) {
		if req.Method == "POST" {
			//log.Println("Bot recieving and handling message.")
			defer req.Body.Close()
			var msg InboundMessage
			err := json.NewDecoder(req.Body).Decode(&msg)
			if err != nil {
				log.Println("Couldn't parse the request body")
				msg.Sender_type = "bot"
			}
			if msg.Sender_type != "bot" || b.TrackBotMessages {
				b.LogMessage(msg)
				// Find hook by running through hooklist
				b.HandleMessage(msg)
			}
		} else {
			//log.Println("Bot not responding to unknown message")
			//io.WriteString(w, "GOTEM")
		}
	}
}
<|endoftext|>


<commit_before>//Package gsm provides a parser for dongle configuration file for asterisk. The
//configuration format is a subset of the astersk dial plan.
//
// The abstract syntax tree is basic, and made to accomodate the urgent need to
// parse the configuration file and also as a means to see if scanning is done
// well will the scanner.
//
//TODO(gernest) rewrite the AST and move it into a separate package.
package gsm

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"

	config "github.com/FarmRadioHangar/fessboxconfig/scanner"
)

// Ast is an abstract syntax tree for a configuration object. The configuration
// format should be section based( or you can say namespacing).
type Ast struct {
	sections []*NodeSection
}

//Section returns the section named name or an error if the section is not found
//in the Ast
func (a *Ast) Section(name string) (*NodeSection, error) {
	for _, v := range a.sections {
		if v.name == name {
			return v, nil
		}
	}
	return nil, errors.New("section not found")
}

//ToJSON marhalls *Ast to a json string and writes the result to dst
func (a *Ast) ToJSON(dst io.Writer) error {
	o := make(map[string]interface{})
	for _, v := range a.sections {
		sec := make(map[string]interface{})
		for _, value := range v.values {
			sec[value.key] = value.value
		}
		o[v.name] = sec
	}
	return json.NewEncoder(dst).Encode(o)
}

//LoadJSON loads AST from json src
func (a *Ast) LoadJSON(src []byte) error {
	var obj map[string]interface{}
	err := json.Unmarshal(src, &obj)
	if err != nil {
		return err
	}
	for key, value := range obj {
		ns := &NodeSection{name: key}
		switch value.(type) {
		case map[string]interface{}:
			sec := value.(map[string]interface{})
			for k, v := range sec {
				ident := &nodeIdent{}
				ident.key = k
				ident.value = fmt.Sprint(v)
				ns.values = append(ns.values, ident)
			}
		}
		a.sections = append(a.sections, ns)
	}
	return nil
}

func PrintAst(dst io.Writer, src *Ast) {
	for _, v := range src.sections {
		if v.name == "main" {
			fmt.Fprintf(dst, "\n\n")
			for _, sub := range v.values {
				fmt.Fprintf(dst, "%s=%s \n", sub.key, sub.value)
			}
			fmt.Fprint(dst, "\n\n")
			continue
		}
		fmt.Fprintf(dst, "\n [%s]\n", v.name)
		for _, sub := range v.values {
			fmt.Fprintf(dst, "%s=%s \n", sub.key, sub.value)
		}
		fmt.Fprint(dst, "\n\n")
		continue
	}
}

//NodeSection represent a section in the configuration object. Sections are name
//spaces that contains configurations definitions under them.
type NodeSection struct {
	name   string
	line   int
	values []*nodeIdent
}

//Get access the key definition and returns its value or an error if the key is
//not part of the section.
func (n *NodeSection) Get(key string) (string, error) {
	for _, v := range n.values {
		if v.key == key {
			return v.value, nil
		}
	}
	return "", errors.New("key not found")
}

//nodeIdent represents a configuration definition, which can be the key value
//definition.
type nodeIdent struct {
	key   string
	value string
	line  int
}

// Parser is a Parser for configuration files. It supports utf-8 encoded
// configuration files.
//
// Only modem configuration files are supported for the momment.
type Parser struct {
	tokens  []*config.Token
	Ast     *Ast
	currPos int
}

//NewParser returns a new Parser that parses input from src. The returned Parser
//supports gsm modem configuration format only.
func NewParser(src io.Reader) (*Parser, error) {
	s := config.NewScanner(src)
	var toks []*config.Token
	var err error
	var tok *config.Token
	for err == nil {
		tok, err = s.Scan()
		if err != nil {
			if err.Error() != io.EOF.Error() {
				return nil, err
			}

			// we are at the end of the input
			break
		}
		if tok != nil {
			switch tok.Type {
			case config.WhiteSpace, config.Comment:

				// Skip comments and whitespaces but preserve the newlines to aid in
				// parsing
				continue
			default:
				toks = append(toks, tok)
			}

		}
	}
	return &Parser{tokens: toks, Ast: &Ast{}}, nil
}

// Parse parses the scanned input and return its *Ast or arror if any.
func (p *Parser) Parse() (*Ast, error) {
	var err error
	if err != nil {
		return nil, err
	}
	mainSec := &NodeSection{name: "main"}
END:
	for {
		tok := p.next()
		if tok.Type == config.EOF {
			break END
		}
		switch tok.Type {
		case config.OpenBrace:
			p.rewind()
			err = p.parseSection()
			if err != nil {
				break END
			}
		case config.Ident:
			p.rewind()
			err = p.parseIdent(mainSec)
			if err != nil {
				break END
			}

		}
	}
	if err != nil {
		return nil, err
	}
	p.Ast.sections = append([]*NodeSection{mainSec}, p.Ast.sections...)
	return p.Ast, err
}

func (p *Parser) next() *config.Token {
	if p.currPos >= len(p.tokens)-1 {
		return &config.Token{Type: config.EOF}
	}
	t := p.tokens[p.currPos]
	p.currPos++
	return t
}

func (p *Parser) seek(at int) {
	p.currPos = at
}

func (p *Parser) parseSection() (err error) {
	left := p.next()
	if left.Type != config.OpenBrace {
		return errors.New("bad token")
	}
	ns := &NodeSection{}
	completeName := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == config.EOF {
			p.rewind()
			break END
		}

		if !completeName {
			switch tok.Type {
			case config.Ident:
				ns.name = ns.name + tok.Text
				goto BEGIN
			case config.ClosingBrace:
				completeName = true
				goto BEGIN
			}
		}
		switch tok.Type {
		case config.NewLine:
			n1 := p.next()
			if n1.Type == config.NewLine {
				n2 := p.next()
				if n2.Type == config.NewLine {
					break END
				}
				p.rewind()
				goto BEGIN
			}
			goto BEGIN
		case config.Ident:
			p.rewind()
			err = p.parseIdent(ns)
			if err != nil {
				break END
			}
		default:
			break END
		}
	}
	if err == nil {
		p.Ast.sections = append(p.Ast.sections, ns)
	}
	return
}

func (p *Parser) rewind() {
	p.currPos--
}

func (p *Parser) parseIdent(sec *NodeSection) (err error) {
	n := &nodeIdent{}
	doneKey := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == config.EOF {
			p.rewind()
			break END
		}

		if !doneKey {
			switch tok.Type {
			case config.Ident:
				n.key = n.key + tok.Text
				goto BEGIN
			case config.Operand:
				doneKey = true
				goto BEGIN
			default:
				err = errors.New("some fish")
				break END
			}

		}
		switch tok.Type {
		case config.Ident:
			n.value = n.value + tok.Text
			goto BEGIN
		case config.NewLine:
			break END
		default:
			err = errors.New("some fish")
			break END
		}
	}
	if err == nil {
		sec.values = append(sec.values, n)
	}

	return
}
<commit_msg>Fix import<commit_after>//Package gsm provides a parser for dongle configuration file for asterisk. The
//configuration format is a subset of the astersk dial plan.
//
// The abstract syntax tree is basic, and made to accomodate the urgent need to
// parse the configuration file and also as a means to see if scanning is done
// well will the scanner.
//
//TODO(gernest) rewrite the AST and move it into a separate package.
package gsm

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"

	"github.com/FarmRadioHangar/fessboxconfig/ast"
	config "github.com/FarmRadioHangar/fessboxconfig/scanner"
)

// Ast is an abstract syntax tree for a configuration object. The configuration
// format should be section based( or you can say namespacing).
type Ast struct {
	sections []*NodeSection
}

//Section returns the section named name or an error if the section is not found
//in the Ast
func (a *Ast) Section(name string) (*NodeSection, error) {
	for _, v := range a.sections {
		if v.name == name {
			return v, nil
		}
	}
	return nil, errors.New("section not found")
}

//ToJSON marhalls *Ast to a json string and writes the result to dst
func (a *Ast) ToJSON(dst io.Writer) error {
	o := make(map[string]interface{})
	for _, v := range a.sections {
		sec := make(map[string]interface{})
		for _, value := range v.values {
			sec[value.key] = value.value
		}
		o[v.name] = sec
	}
	return json.NewEncoder(dst).Encode(o)
}

//LoadJSON loads AST from json src
func (a *Ast) LoadJSON(src []byte) error {
	var obj map[string]interface{}
	err := json.Unmarshal(src, &obj)
	if err != nil {
		return err
	}
	for key, value := range obj {
		ns := &NodeSection{name: key}
		switch value.(type) {
		case map[string]interface{}:
			sec := value.(map[string]interface{})
			for k, v := range sec {
				ident := &nodeIdent{}
				ident.key = k
				ident.value = fmt.Sprint(v)
				ns.values = append(ns.values, ident)
			}
		}
		a.sections = append(a.sections, ns)
	}
	return nil
}

func PrintAst(dst io.Writer, src *Ast) {
	for _, v := range src.sections {
		if v.name == "main" {
			fmt.Fprintf(dst, "\n\n")
			for _, sub := range v.values {
				fmt.Fprintf(dst, "%s=%s \n", sub.key, sub.value)
			}
			fmt.Fprint(dst, "\n\n")
			continue
		}
		fmt.Fprintf(dst, "\n [%s]\n", v.name)
		for _, sub := range v.values {
			fmt.Fprintf(dst, "%s=%s \n", sub.key, sub.value)
		}
		fmt.Fprint(dst, "\n\n")
		continue
	}
}

//NodeSection represent a section in the configuration object. Sections are name
//spaces that contains configurations definitions under them.
type NodeSection struct {
	name   string
	line   int
	values []*nodeIdent
}

//Get access the key definition and returns its value or an error if the key is
//not part of the section.
func (n *NodeSection) Get(key string) (string, error) {
	for _, v := range n.values {
		if v.key == key {
			return v.value, nil
		}
	}
	return "", errors.New("key not found")
}

//nodeIdent represents a configuration definition, which can be the key value
//definition.
type nodeIdent struct {
	key   string
	value string
	line  int
}

// Parser is a Parser for configuration files. It supports utf-8 encoded
// configuration files.
//
// Only modem configuration files are supported for the momment.
type Parser struct {
	tokens  []*ast.Token
	Ast     *Ast
	currPos int
}

//NewParser returns a new Parser that parses input from src. The returned Parser
//supports gsm modem configuration format only.
func NewParser(src io.Reader) (*Parser, error) {
	s := config.NewScanner(src)
	var toks []*ast.Token
	var err error
	var tok *ast.Token
	for err == nil {
		tok, err = s.Scan()
		if err != nil {
			if err.Error() != io.EOF.Error() {
				return nil, err
			}

			// we are at the end of the input
			break
		}
		if tok != nil {
			switch tok.Type {
			case ast.WhiteSpace, ast.Comment:

				// Skip comments and whitespaces but preserve the newlines to aid in
				// parsing
				continue
			default:
				toks = append(toks, tok)
			}

		}
	}
	return &Parser{tokens: toks, Ast: &Ast{}}, nil
}

// Parse parses the scanned input and return its *Ast or arror if any.
func (p *Parser) Parse() (*Ast, error) {
	var err error
	if err != nil {
		return nil, err
	}
	mainSec := &NodeSection{name: "main"}
END:
	for {
		tok := p.next()
		if tok.Type == ast.EOF {
			break END
		}
		switch tok.Type {
		case ast.LBrace:
			p.rewind()
			err = p.parseSection()
			if err != nil {
				break END
			}
		case ast.Ident:
			p.rewind()
			err = p.parseIdent(mainSec)
			if err != nil {
				break END
			}

		}
	}
	if err != nil {
		return nil, err
	}
	p.Ast.sections = append([]*NodeSection{mainSec}, p.Ast.sections...)
	return p.Ast, err
}

func (p *Parser) next() *ast.Token {
	if p.currPos >= len(p.tokens)-1 {
		return &ast.Token{Type: ast.EOF}
	}
	t := p.tokens[p.currPos]
	p.currPos++
	return t
}

func (p *Parser) seek(at int) {
	p.currPos = at
}

func (p *Parser) parseSection() (err error) {
	left := p.next()
	if left.Type != ast.LBrace {
		return errors.New("bad token")
	}
	ns := &NodeSection{}
	completeName := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == ast.EOF {
			p.rewind()
			break END
		}

		if !completeName {
			switch tok.Type {
			case ast.Ident:
				ns.name = ns.name + tok.Text
				goto BEGIN
			case ast.RBrace:
				completeName = true
				goto BEGIN
			}
		}
		switch tok.Type {
		case ast.NLine:
			n1 := p.next()
			if n1.Type == ast.NLine {
				n2 := p.next()
				if n2.Type == ast.NLine {
					break END
				}
				p.rewind()
				goto BEGIN
			}
			goto BEGIN
		case ast.Ident:
			p.rewind()
			err = p.parseIdent(ns)
			if err != nil {
				break END
			}
		default:
			break END
		}
	}
	if err == nil {
		p.Ast.sections = append(p.Ast.sections, ns)
	}
	return
}

func (p *Parser) rewind() {
	p.currPos--
}

func (p *Parser) parseIdent(sec *NodeSection) (err error) {
	n := &nodeIdent{}
	doneKey := false
END:
	for {
	BEGIN:
		tok := p.next()
		if tok.Type == ast.EOF {
			p.rewind()
			break END
		}

		if !doneKey {
			switch tok.Type {
			case ast.Ident:
				n.key = n.key + tok.Text
				goto BEGIN
			case ast.Assign:
				doneKey = true
				goto BEGIN
			default:
				err = errors.New("some fish")
				break END
			}

		}
		switch tok.Type {
		case ast.Ident:
			n.value = n.value + tok.Text
			goto BEGIN
		case ast.NLine:
			break END
		default:
			err = errors.New("some fish")
			break END
		}
	}
	if err == nil {
		sec.values = append(sec.values, n)
	}

	return
}
<|endoftext|>


<commit_before>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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
 */

package keys

import (
	"crypto/rsa"
	"encoding/json"
	"math/big"
)

type RSAPublicKey struct {
	*rsa.PublicKey
}

type auxRSAPublicKey struct {
	Exponent int    `json:"exponent"`
	Modulus  []byte `json:"modulus"`
}

// MarshalJSON implements the json.Marshal interface
func (rp *RSAPublicKey) MarshalJSON() ([]byte, error) {
	var aux auxRSAPublicKey
	if rp.PublicKey != nil {
		aux.Exponent = rp.E
		aux.Modulus = rp.N.Bytes()
	}
	return json.Marshal(&aux)
}

// UnmarshalJSON implements teh json.Unmarshal interface
func (rp *RSAPublicKey) UnmarshalJSON(b []byte) error {
	var aux auxRSAPublicKey
	if err := json.Unmarshal(b, &aux); err != nil {
		return err
	}
	if rp.PublicKey == nil {
		rp.PublicKey = new(rsa.PublicKey)
	}
	rp.E = aux.Exponent
	rp.N = big.NewInt(0).SetBytes(aux.Modulus)
	return nil
}
<commit_msg>Specify RSA modulus length<commit_after>/*
 * ZGrab Copyright 2015 Regents of the University of Michigan
 *
 * 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
 */

package keys

import (
	"crypto/rsa"
	"encoding/json"
	"fmt"
	"math/big"
)

type RSAPublicKey struct {
	*rsa.PublicKey
}

type auxRSAPublicKey struct {
	Exponent int    `json:"exponent"`
	Modulus  []byte `json:"modulus"`
	Length   int    `json:"length"`
}

// MarshalJSON implements the json.Marshal interface
func (rp *RSAPublicKey) MarshalJSON() ([]byte, error) {
	var aux auxRSAPublicKey
	if rp.PublicKey != nil {
		aux.Exponent = rp.E
		aux.Modulus = rp.N.Bytes()
		aux.Length = len(aux.Modulus) * 8
	}
	return json.Marshal(&aux)
}

// UnmarshalJSON implements teh json.Unmarshal interface
func (rp *RSAPublicKey) UnmarshalJSON(b []byte) error {
	var aux auxRSAPublicKey
	if err := json.Unmarshal(b, &aux); err != nil {
		return err
	}
	if rp.PublicKey == nil {
		rp.PublicKey = new(rsa.PublicKey)
	}
	rp.E = aux.Exponent
	rp.N = big.NewInt(0).SetBytes(aux.Modulus)
	if len(aux.Modulus)*8 != aux.Length {
		return fmt.Errorf("mismatched length (got %d, field specified %d)", len(aux.Modulus), aux.Length)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Package iterkernel is a low-level helpr for implementing iterators.
*/
package iterkernel
<commit_msg>added more docs<commit_after>/*
Package iterkernel is a low-level helper for implementing iterators.
*/
package iterkernel
<|endoftext|>


<commit_before>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"encoding/json"
	"fmt"

	. "github.com/araddon/gou"
)

var (
	_ = DEBUG
)

// A bool (and/or) clause
type BoolClause string

// Filter clause is either a boolClause or FilterOp
type FilterClause interface {
	String() string
}

// A wrapper to allow for custom serialization
type FilterWrap struct {
	boolClause string
	filters    []interface{}
}

func NewFilterWrap() *FilterWrap {
	return &FilterWrap{filters: make([]interface{}, 0), boolClause: "and"}
}

func (f *FilterWrap) String() string {
	return fmt.Sprintf(`fopv: %d:%v`, len(f.filters), f.filters)
}

// Bool sets the type of boolean filter to use.
// Accepted values are "and" and "or".
func (f *FilterWrap) Bool(s string) {
	f.boolClause = s
}

// Custom marshalling to support the query dsl
func (f *FilterWrap) addFilters(fl []interface{}) {
	if len(fl) > 1 {
		fc := fl[0]
		switch fc.(type) {
		case BoolClause, string:
			f.boolClause = fc.(string)
			fl = fl[1:]
		}
	}
	f.filters = append(f.filters, fl...)
}

// Custom marshalling to support the query dsl
func (f *FilterWrap) MarshalJSON() ([]byte, error) {
	var root interface{}
	if len(f.filters) > 1 {
		root = map[string]interface{}{f.boolClause: f.filters}
	} else if len(f.filters) == 1 {
		root = f.filters[0]
	}
	return json.Marshal(root)
}

/*
	"filter": {
		"range": {
		  "@timestamp": {
		    "from": "2012-12-29T16:52:48+00:00",
		    "to": "2012-12-29T17:52:48+00:00"
		  }
		}
	}
	"filter": {
	    "missing": {
	        "field": "repository.name"
	    }
	}

	"filter" : {
	    "terms" : {
	        "user" : ["kimchy", "elasticsearch"],
	        "execution" : "bool",
	        "_cache": true
	    }
	}

	"filter" : {
	    "term" : { "user" : "kimchy"}
	}

	"filter" : {
	    "and" : [
	        {
	            "range" : {
	                "postDate" : {
	                    "from" : "2010-03-01",
	                    "to" : "2010-04-01"
	                }
	            }
	        },
	        {
	            "prefix" : { "name.second" : "ba" }
	        }
	    ]
	}

*/

// Filter Operation
//
//   Filter().Term("user","kimchy")
//
//   // we use variadics to allow n arguments, first is the "field" rest are values
//   Filter().Terms("user", "kimchy", "elasticsearch")
//
//   Filter().Exists("repository.name")
//
func Filter() *FilterOp {
	return &FilterOp{}
}

func CompoundFilter(fl ...interface{}) *FilterWrap {
	FilterVal := NewFilterWrap()
	FilterVal.addFilters(fl)
	return FilterVal
}

type FilterOp struct {
	curField   string
	TermsMap   map[string][]interface{}          `json:"terms,omitempty"`
	Range      map[string]map[string]interface{} `json:"range,omitempty"`
	Exist      map[string]string                 `json:"exists,omitempty"`
	MissingVal map[string]string                 `json:"missing,omitempty"`
}

// A range is a special type of Filter operation
//
//    Range().Exists("repository.name")
func Range() *FilterOp {
	return &FilterOp{Range: make(map[string]map[string]interface{})}
}

func (f *FilterOp) Field(fld string) *FilterOp {
	f.curField = fld
	if _, ok := f.Range[fld]; !ok {
		m := make(map[string]interface{})
		f.Range[fld] = m
	}
	return f
}

// Filter Terms
//
//   Filter().Terms("user","kimchy")
//
//   // we use variadics to allow n arguments, first is the "field" rest are values
//   Filter().Terms("user", "kimchy", "elasticsearch")
//
func (f *FilterOp) Terms(field string, values ...interface{}) *FilterOp {
	if len(f.TermsMap) == 0 {
		f.TermsMap = make(map[string][]interface{})
	}
	for _, val := range values {
		f.TermsMap[field] = append(f.TermsMap[field], val)
	}

	return f
}
func (f *FilterOp) From(from string) *FilterOp {
	f.Range[f.curField]["from"] = from
	return f
}
func (f *FilterOp) To(to string) *FilterOp {
	f.Range[f.curField]["to"] = to
	return f
}
func (f *FilterOp) Gt(gt interface{}) *FilterOp {
	f.Range[f.curField]["gt"] = gt
	return f
}
func (f *FilterOp) Lt(lt interface{}) *FilterOp {
	f.Range[f.curField]["lt"] = lt
	return f
}
func (f *FilterOp) Exists(name string) *FilterOp {
	f.Exist = map[string]string{"field": name}
	return f
}
func (f *FilterOp) Missing(name string) *FilterOp {
	f.MissingVal = map[string]string{"field": name}
	return f
}

// Add another Filterop, "combines" two filter ops into one
func (f *FilterOp) Add(fop *FilterOp) *FilterOp {
	// TODO, this is invalid, refactor
	if len(fop.Exist) > 0 {
		f.Exist = fop.Exist
	}
	if len(fop.MissingVal) > 0 {
		f.MissingVal = fop.MissingVal
	}
	if len(fop.Range) > 0 {
		f.Range = fop.Range
	}
	return f
}
<commit_msg>add lte and gte to the Range filter<commit_after>// Copyright 2013 Matthew Baird
// 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 elastigo

import (
	"encoding/json"
	"fmt"

	. "github.com/araddon/gou"
)

var (
	_ = DEBUG
)

// A bool (and/or) clause
type BoolClause string

// Filter clause is either a boolClause or FilterOp
type FilterClause interface {
	String() string
}

// A wrapper to allow for custom serialization
type FilterWrap struct {
	boolClause string
	filters    []interface{}
}

func NewFilterWrap() *FilterWrap {
	return &FilterWrap{filters: make([]interface{}, 0), boolClause: "and"}
}

func (f *FilterWrap) String() string {
	return fmt.Sprintf(`fopv: %d:%v`, len(f.filters), f.filters)
}

// Bool sets the type of boolean filter to use.
// Accepted values are "and" and "or".
func (f *FilterWrap) Bool(s string) {
	f.boolClause = s
}

// Custom marshalling to support the query dsl
func (f *FilterWrap) addFilters(fl []interface{}) {
	if len(fl) > 1 {
		fc := fl[0]
		switch fc.(type) {
		case BoolClause, string:
			f.boolClause = fc.(string)
			fl = fl[1:]
		}
	}
	f.filters = append(f.filters, fl...)
}

// Custom marshalling to support the query dsl
func (f *FilterWrap) MarshalJSON() ([]byte, error) {
	var root interface{}
	if len(f.filters) > 1 {
		root = map[string]interface{}{f.boolClause: f.filters}
	} else if len(f.filters) == 1 {
		root = f.filters[0]
	}
	return json.Marshal(root)
}

/*
	"filter": {
		"range": {
		  "@timestamp": {
		    "from": "2012-12-29T16:52:48+00:00",
		    "to": "2012-12-29T17:52:48+00:00"
		  }
		}
	}
	"filter": {
	    "missing": {
	        "field": "repository.name"
	    }
	}

	"filter" : {
	    "terms" : {
	        "user" : ["kimchy", "elasticsearch"],
	        "execution" : "bool",
	        "_cache": true
	    }
	}

	"filter" : {
	    "term" : { "user" : "kimchy"}
	}

	"filter" : {
	    "and" : [
	        {
	            "range" : {
	                "postDate" : {
	                    "from" : "2010-03-01",
	                    "to" : "2010-04-01"
	                }
	            }
	        },
	        {
	            "prefix" : { "name.second" : "ba" }
	        }
	    ]
	}

*/

// Filter Operation
//
//   Filter().Term("user","kimchy")
//
//   // we use variadics to allow n arguments, first is the "field" rest are values
//   Filter().Terms("user", "kimchy", "elasticsearch")
//
//   Filter().Exists("repository.name")
//
func Filter() *FilterOp {
	return &FilterOp{}
}

func CompoundFilter(fl ...interface{}) *FilterWrap {
	FilterVal := NewFilterWrap()
	FilterVal.addFilters(fl)
	return FilterVal
}

type FilterOp struct {
	curField   string
	TermsMap   map[string][]interface{}          `json:"terms,omitempty"`
	Range      map[string]map[string]interface{} `json:"range,omitempty"`
	Exist      map[string]string                 `json:"exists,omitempty"`
	MissingVal map[string]string                 `json:"missing,omitempty"`
}

// A range is a special type of Filter operation
//
//    Range().Exists("repository.name")
func Range() *FilterOp {
	return &FilterOp{Range: make(map[string]map[string]interface{})}
}

func (f *FilterOp) Field(fld string) *FilterOp {
	f.curField = fld
	if _, ok := f.Range[fld]; !ok {
		m := make(map[string]interface{})
		f.Range[fld] = m
	}
	return f
}

// Filter Terms
//
//   Filter().Terms("user","kimchy")
//
//   // we use variadics to allow n arguments, first is the "field" rest are values
//   Filter().Terms("user", "kimchy", "elasticsearch")
//
func (f *FilterOp) Terms(field string, values ...interface{}) *FilterOp {
	if len(f.TermsMap) == 0 {
		f.TermsMap = make(map[string][]interface{})
	}
	for _, val := range values {
		f.TermsMap[field] = append(f.TermsMap[field], val)
	}

	return f
}
func (f *FilterOp) From(from string) *FilterOp {
	f.Range[f.curField]["from"] = from
	return f
}
func (f *FilterOp) To(to string) *FilterOp {
	f.Range[f.curField]["to"] = to
	return f
}
func (f *FilterOp) Gt(gt interface{}) *FilterOp {
	f.Range[f.curField]["gt"] = gt
	return f
}
func (f *FilterOp) Lt(lt interface{}) *FilterOp {
	f.Range[f.curField]["lt"] = lt
	return f
}
func (f *FilterOp) Gte(gte interface{}) *FilterOp {
	f.Range[f.curField]["gte"] = gte
	return f
}
func (f *FilterOp) Lte(lte interface{}) *FilterOp {
	f.Range[f.curField]["lte"] = lte
	return f
}
func (f *FilterOp) Exists(name string) *FilterOp {
	f.Exist = map[string]string{"field": name}
	return f
}
func (f *FilterOp) Missing(name string) *FilterOp {
	f.MissingVal = map[string]string{"field": name}
	return f
}

// Add another Filterop, "combines" two filter ops into one
func (f *FilterOp) Add(fop *FilterOp) *FilterOp {
	// TODO, this is invalid, refactor
	if len(fop.Exist) > 0 {
		f.Exist = fop.Exist
	}
	if len(fop.MissingVal) > 0 {
		f.MissingVal = fop.MissingVal
	}
	if len(fop.Range) > 0 {
		f.Range = fop.Range
	}
	return f
}
<|endoftext|>


<commit_before>package vaulted

import (
	"reflect"
	"sort"
	"testing"
	"time"
)

func TestSessionVariables(t *testing.T) {
	e := Session{
		Name:       "vault",
		Expiration: time.Now(),

		Vars: map[string]string{
			"TEST":         "TESTING",
			"ANOTHER_TEST": "TEST TEST",
		},
	}
	var expectedSet map[string]string = map[string]string{
		"ANOTHER_TEST":           "TEST TEST",
		"TEST":                   "TESTING",
		"VAULTED_ENV":            e.Name,
		"VAULTED_ENV_EXPIRATION": e.Expiration.UTC().Format(time.RFC3339),
	}
	var expectedUnset []string

	vars := e.Variables()

	if !reflect.DeepEqual(expectedSet, vars.Set) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedSet, vars.Set)
	}

	if !reflect.DeepEqual(expectedUnset, vars.Unset) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedUnset, vars.Unset)
	}
}

func TestSessionVariablesWithPermCreds(t *testing.T) {
	e := Session{
		Name:       "vault",
		Expiration: time.Now(),

		AWSCreds: &AWSCredentials{
			ID:     "an-id",
			Secret: "the-super-sekrit",
		},
		Vars: map[string]string{
			"TEST":         "TESTING",
			"ANOTHER_TEST": "TEST TEST",
		},
	}
	var expectedSet map[string]string = map[string]string{
		"ANOTHER_TEST":           "TEST TEST",
		"AWS_ACCESS_KEY_ID":      e.AWSCreds.ID,
		"AWS_SECRET_ACCESS_KEY":  e.AWSCreds.Secret,
		"TEST":                   "TESTING",
		"VAULTED_ENV":            e.Name,
		"VAULTED_ENV_EXPIRATION": e.Expiration.UTC().Format(time.RFC3339),
	}
	var expectedUnset []string = []string{
		"AWS_SECURITY_TOKEN",
		"AWS_SESSION_TOKEN",
	}

	vars := e.Variables()

	if !reflect.DeepEqual(expectedSet, vars.Set) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedSet, vars.Set)
	}

	sort.Strings(vars.Unset)
	if !reflect.DeepEqual(expectedUnset, vars.Unset) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedUnset, vars.Unset)
	}
}

func TestSessionVariablesWithTempCreds(t *testing.T) {
	e := Session{
		Name:       "vault",
		Expiration: time.Now(),

		AWSCreds: &AWSCredentials{
			ID:     "an-id",
			Secret: "the-super-sekrit",
			Token:  "my-affections",
		},
		Vars: map[string]string{
			"TEST":         "TESTING",
			"ANOTHER_TEST": "TEST TEST",
		},
	}
	var expectedSet map[string]string = map[string]string{
		"ANOTHER_TEST":           "TEST TEST",
		"AWS_ACCESS_KEY_ID":      e.AWSCreds.ID,
		"AWS_SECRET_ACCESS_KEY":  e.AWSCreds.Secret,
		"AWS_SECURITY_TOKEN":     e.AWSCreds.Token,
		"AWS_SESSION_TOKEN":      e.AWSCreds.Token,
		"TEST":                   "TESTING",
		"VAULTED_ENV":            e.Name,
		"VAULTED_ENV_EXPIRATION": e.Expiration.UTC().Format(time.RFC3339),
	}
	var expectedUnset []string

	vars := e.Variables()

	if !reflect.DeepEqual(expectedSet, vars.Set) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedSet, vars.Set)
	}

	if !reflect.DeepEqual(expectedUnset, vars.Unset) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedUnset, vars.Unset)
	}
}
<commit_msg>Cleanup Session tests<commit_after>package vaulted

import (
	"reflect"
	"sort"
	"testing"
	"time"
)

func TestSessionVariables(t *testing.T) {
	s := Session{
		Name:       "vault",
		Expiration: time.Now(),

		Vars: map[string]string{
			"TEST":         "TESTING",
			"ANOTHER_TEST": "TEST TEST",
		},
	}
	var expectedSet = map[string]string{
		"ANOTHER_TEST":           "TEST TEST",
		"TEST":                   "TESTING",
		"VAULTED_ENV":            s.Name,
		"VAULTED_ENV_EXPIRATION": s.Expiration.UTC().Format(time.RFC3339),
	}
	var expectedUnset []string

	vars := s.Variables()

	if !reflect.DeepEqual(expectedSet, vars.Set) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedSet, vars.Set)
	}

	if !reflect.DeepEqual(expectedUnset, vars.Unset) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedUnset, vars.Unset)
	}
}

func TestSessionVariablesWithPermCreds(t *testing.T) {
	s := Session{
		Name:       "vault",
		Expiration: time.Now(),

		AWSCreds: &AWSCredentials{
			ID:     "an-id",
			Secret: "the-super-sekrit",
		},
		Vars: map[string]string{
			"TEST":         "TESTING",
			"ANOTHER_TEST": "TEST TEST",
		},
	}
	var expectedSet = map[string]string{
		"ANOTHER_TEST":           "TEST TEST",
		"AWS_ACCESS_KEY_ID":      s.AWSCreds.ID,
		"AWS_SECRET_ACCESS_KEY":  s.AWSCreds.Secret,
		"TEST":                   "TESTING",
		"VAULTED_ENV":            s.Name,
		"VAULTED_ENV_EXPIRATION": s.Expiration.UTC().Format(time.RFC3339),
	}
	var expectedUnset = []string{
		"AWS_SECURITY_TOKEN",
		"AWS_SESSION_TOKEN",
	}

	vars := s.Variables()

	if !reflect.DeepEqual(expectedSet, vars.Set) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedSet, vars.Set)
	}

	sort.Strings(vars.Unset)
	if !reflect.DeepEqual(expectedUnset, vars.Unset) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedUnset, vars.Unset)
	}
}

func TestSessionVariablesWithTempCreds(t *testing.T) {
	s := Session{
		Name:       "vault",
		Expiration: time.Now(),

		AWSCreds: &AWSCredentials{
			ID:     "an-id",
			Secret: "the-super-sekrit",
			Token:  "my-affections",
		},
		Vars: map[string]string{
			"TEST":         "TESTING",
			"ANOTHER_TEST": "TEST TEST",
		},
	}
	var expectedSet = map[string]string{
		"ANOTHER_TEST":           "TEST TEST",
		"AWS_ACCESS_KEY_ID":      s.AWSCreds.ID,
		"AWS_SECRET_ACCESS_KEY":  s.AWSCreds.Secret,
		"AWS_SECURITY_TOKEN":     s.AWSCreds.Token,
		"AWS_SESSION_TOKEN":      s.AWSCreds.Token,
		"TEST":                   "TESTING",
		"VAULTED_ENV":            s.Name,
		"VAULTED_ENV_EXPIRATION": s.Expiration.UTC().Format(time.RFC3339),
	}
	var expectedUnset []string

	vars := s.Variables()

	if !reflect.DeepEqual(expectedSet, vars.Set) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedSet, vars.Set)
	}

	if !reflect.DeepEqual(expectedUnset, vars.Unset) {
		t.Errorf("Expected: %#v\nGot: %#v\n", expectedUnset, vars.Unset)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/docopt/docopt.go"
	"log"
	"strconv"
	"strings"
)

type Dump struct {
	NetHeader    []string
	ClientHeader []string
	Networks     []string
	Clients      []string
}

type Filter struct {
	BSSID        map[string]bool
	ESSID        map[string]bool
	Probes       map[string]bool
	NetSignal    int
	ClientSignal int
	Probing      bool
	AdHoc        bool
	Infra        bool
	Nets         bool
	Clients      bool
	Negate       bool
}

// Fill header values for Wireless AP and Wireless client
func (d *Dump) Header() {
	d.NetHeader = []string{
		"BSSID",
		"First time seen",
		"Last time seen",
		"channel",
		"Speed",
		"Privacy",
		"Cipher",
		"Authentication",
		"Power",
		"# beacons",
		"# IV",
		"LAN IP",
		"ID-length",
		"ESSID",
		"Key"}
	d.ClientHeader = []string{
		"Station MAC",
		"First time seen",
		"Last time seen",
		"Power",
		"# packets",
		"BSSID",
		"Probed ESSIDs"}
}

func SplitEnc(s []SSID, delm string) []string {
	var crypt []string

	for _, ssid := range s {
		for _, enc := range ssid.Encrypt {
			if enc == "None" || enc == "WEP" {
				crypt = append(crypt, strings.Join([]string{enc, "", ""}, delm))
				continue
			}
			t := strings.Split(enc, "+")
			t = append(t[:1], strings.Split(t[1], "-")...)
			if len(t) > 2 {
				crypt = append(crypt, strings.Join(t, delm))
			} else if len(t) > 1 {
				t = append(t, "")
				crypt = append(crypt, strings.Join(t, delm))
			} else {
				crypt = append(crypt, strings.Join([]string{"None", "", ""}, delm))
			}
		}
	}

	return crypt
}

func (n *Network) Dump(p PSSID, enc string) []string {
	nets := []string{}

	nets = append(nets, n.BSSID)
	nets = append(nets, p.Time...)
	nets = append(nets, fmt.Sprintf("%v", n.Channel))
	nets = append(nets, fmt.Sprintf("%v", p.Speed))
	nets = append(nets, enc)
	nets = append(nets, fmt.Sprintf("%v", n.Power))
	nets = append(nets, fmt.Sprintf("%v", p.Packets))
	nets = append(nets, "")
	nets = append(nets, "")
	nets = append(nets, "")
	nets = append(nets, p.ESSID)
	nets = append(nets, "")

	return nets
}

func (n *Network) Check(p PSSID, filter Filter, enc string) []string {
	if n.BSSID == "00:00:00:00:00:00" {
		return nil
	}
	if n.Type == "probe" {
		return nil
	}
	if filter.Probing && !filter.Negate {
		return nil
	}

	if len(filter.BSSID) == 0 && len(filter.ESSID) == 0 {
		return n.Dump(p, enc)
	}
	if (filter.BSSID[n.BSSID] || filter.ESSID[p.ESSID]) && !filter.Negate {
		return n.Dump(p, enc)
	} else if !(filter.BSSID[n.BSSID] || filter.ESSID[p.ESSID]) && filter.Negate {
		return n.Dump(p, enc)
	}

	return nil
}

func (c *Client) Dump(bssid string) []string {
	assoc := []string{}

	assoc = append(assoc, c.MAC)
	assoc = append(assoc, c.TimeConv()...)
	assoc = append(assoc, fmt.Sprintf("%v", c.Power))
	assoc = append(assoc, fmt.Sprintf("%v", c.Packets))
	if bssid == "00:00:00:00:00:00" {
		assoc = append(assoc, "(not associated)")
	} else if c.Type == "tods" {
		assoc = append(assoc, "(probing client)")
	} else {
		assoc = append(assoc, bssid)
	}
	assoc = append(assoc, strings.Join(c.Probes, ","))

	return assoc
}

func (c *Client) Check(bssid string, filter Filter) []string {
	if c.MAC == "00:00:00:00:00:00" {
		return nil
	}
	if c.MAC == bssid && c.Type != "tods" {
		return nil
	}

	// If map[string] empty return nil
	// If map[string] match and neg false return value
	// If map[string] not match and neg true return value
	// Default return nil

	if len(filter.BSSID) == 0 && len(filter.Probes) == 0 {
		return c.Dump(bssid)
	}
	for _, probe := range c.Probes {
		if filter.Probes[probe] && !filter.Negate {
			return c.Dump(bssid)
		} else if !filter.Probes[probe] && filter.Negate {
			return c.Dump(bssid)
		}
		return nil
	}
	if filter.BSSID[bssid] && !filter.Negate {
		return c.Dump(bssid)
	} else if !filter.BSSID[bssid] && filter.Negate {
		return c.Dump(bssid)
	}
	return nil
}

func (w *WirelessData) Dump(delm string, filter Filter) {
	d := Dump{}
	d.Header()

	for _, net := range w.Networks {

		if filter.Nets || (!filter.Nets && !filter.Clients) {
			if filter.AdHoc && !filter.Negate && net.Type != "ad-hoc" {
				continue
			} else if filter.AdHoc && filter.Negate && net.Type == "ad-hoc" {
				continue
			}
			if filter.Infra && !filter.Negate && net.Type != "infrastructure" {
				continue
			} else if filter.Infra && filter.Negate && net.Type == "infrastructure" {
				continue
			}
			if filter.NetSignal != 0 && net.Power < filter.NetSignal {
				continue
			}

			pssid := net.ParseSSID(delm)
			for _, enc := range pssid.Encrypt {
				data := net.Check(pssid, filter, enc)
				if data != nil {
					d.Networks = append(d.Networks, strings.Join(data, delm))
				}
			}
		}

		if filter.Clients || (!filter.Nets && !filter.Clients) {
			for _, c := range net.Clients {
				if filter.Probing && !filter.Negate && len(c.Probes) == 0 {
					continue
				} else if filter.Probing && !filter.Negate && c.Type != "tods" {
					continue
				} else if filter.Probing && filter.Negate && c.Type == "tods" {
					continue
				}
				if (filter.AdHoc || filter.Infra) && !filter.Negate && c.Type == "tods" {
					continue
				}
				if filter.ClientSignal != 0 && c.Power < filter.ClientSignal {
					continue
				}

				data := c.Check(net.BSSID, filter)
				if data != nil {
					d.Clients = append(d.Clients, strings.Join(data, delm))
				}
			}
		}
	}

	if filter.Nets || (!filter.Nets && !filter.Clients) {
		fmt.Println()
		fmt.Println(strings.Join(d.NetHeader, delm))
	}
	for _, nets := range d.Networks {
		fmt.Println(nets)
	}
	if filter.Clients || (!filter.Nets && !filter.Clients) {
		fmt.Printf("\n\n%v\n", strings.Join(d.ClientHeader, delm))
	}
	for _, c := range d.Clients {
		fmt.Println(c)
	}
}

func main() {
	arguments, err := docopt.Parse(usage, nil, true, "kismograph 1.3", false)
	if err != nil {
		log.Fatal("Error parsing usage. Error: ", err.Error())
	}
	var filter Filter
	filter.Nets = arguments["--nets"].(bool)
	filter.Clients = arguments["--clients"].(bool)
	filter.BSSID = ParseArg(arguments["--bssid"])
	filter.ESSID = ParseArg(arguments["--essid"])
	filter.Probes = ParseArg(arguments["--probes"])
	filter.AdHoc = arguments["--ad-hoc"].(bool)
	filter.Negate = arguments["--negate"].(bool)
	filter.Infra = arguments["--infra"].(bool)

	if arguments["--netsignal"] != nil {
		sig, err := strconv.Atoi(arguments["--netsignal"].(string))
		if err != nil {
			log.Fatal(err.Error())
		}

		if sig > 0 {
			filter.NetSignal = sig - (sig * 2)
		} else {
			filter.NetSignal = sig
		}
	}
	if arguments["--clientsignal"] != nil {
		sig, err := strconv.Atoi(arguments["--clientsignal"].(string))
		if err != nil {
			log.Fatal(err.Error())
		}

		if sig > 0 {
			filter.ClientSignal = sig - (sig * 2)
		} else {
			filter.ClientSignal = sig
		}
	}

	f := arguments["<file>"].(string)
	data, err := kismoExtract(f)
	if err != nil {
		log.Fatal(err.Error())
	}

	data.Dump(", ", filter)

}
<commit_msg>Update output format<commit_after>package main

import (
	"fmt"
	"github.com/docopt/docopt.go"
	"log"
	"strconv"
	"strings"
)

type Dump struct {
	NetHeader    []string
	ClientHeader []string
	Networks     []string
	Clients      []string
}

type Filter struct {
	BSSID        map[string]bool
	ESSID        map[string]bool
	Probes       map[string]bool
	NetSignal    int
	ClientSignal int
	Probing      bool
	AdHoc        bool
	Infra        bool
	Nets         bool
	Clients      bool
	Negate       bool
}

// Fill header values for Wireless AP and Wireless client
func (d *Dump) Header() {
	d.NetHeader = []string{
		"BSSID",
		"First time seen",
		"Last time seen",
		"channel",
		"Speed",
		"Privacy",
		"Cipher",
		"Authentication",
		"Power",
		"# beacons",
		"# IV",
		"LAN IP",
		"ID-length",
		"ESSID",
		"Key"}
	d.ClientHeader = []string{
		"Station MAC",
		"First time seen",
		"Last time seen",
		"Power",
		"# packets",
		"BSSID",
		"Probed ESSIDs"}
}

func SplitEnc(s []SSID, delm string) []string {
	var crypt []string

	for _, ssid := range s {
		for _, enc := range ssid.Encrypt {
			if enc == "None" || enc == "WEP" {
				crypt = append(crypt, strings.Join([]string{enc, "", ""}, delm))
				continue
			}
			t := strings.Split(enc, "+")
			t = append(t[:1], strings.Split(t[1], "-")...)
			if len(t) > 2 {
				crypt = append(crypt, strings.Join(t, delm))
			} else if len(t) > 1 {
				t = append(t, "")
				crypt = append(crypt, strings.Join(t, delm))
			} else {
				crypt = append(crypt, strings.Join([]string{"None", "", ""}, delm))
			}
		}
	}

	return crypt
}

func (n *Network) Dump(p PSSID, enc string) []string {
	nets := []string{}

	nets = append(nets, n.BSSID)
	nets = append(nets, p.Time...)
	nets = append(nets, fmt.Sprintf("%v", n.Channel))
	nets = append(nets, fmt.Sprintf("%v", p.Speed))
	nets = append(nets, enc)
	nets = append(nets, fmt.Sprintf("%v", n.Power))
	nets = append(nets, fmt.Sprintf("%v", p.Packets))
	nets = append(nets, "")
	nets = append(nets, "")
	nets = append(nets, "")
	nets = append(nets, p.ESSID)
	nets = append(nets, "")

	return nets
}

func (n *Network) Check(p PSSID, filter Filter, enc string) []string {
	if n.BSSID == "00:00:00:00:00:00" {
		return nil
	}
	if n.Type == "probe" {
		return nil
	}
	if filter.Probing && !filter.Negate {
		return nil
	}

	if len(filter.BSSID) == 0 && len(filter.ESSID) == 0 {
		return n.Dump(p, enc)
	}
	if (filter.BSSID[n.BSSID] || filter.ESSID[p.ESSID]) && !filter.Negate {
		return n.Dump(p, enc)
	} else if !(filter.BSSID[n.BSSID] || filter.ESSID[p.ESSID]) && filter.Negate {
		return n.Dump(p, enc)
	}

	return nil
}

func (c *Client) Dump(bssid string) []string {
	assoc := []string{}

	assoc = append(assoc, c.MAC)
	assoc = append(assoc, c.TimeConv()...)
	assoc = append(assoc, fmt.Sprintf("%v", c.Power))
	assoc = append(assoc, fmt.Sprintf("%v", c.Packets))
	if bssid == "00:00:00:00:00:00" {
		assoc = append(assoc, "(not associated)")
	} else if c.Type == "tods" {
		assoc = append(assoc, "(probing client)")
	} else {
		assoc = append(assoc, bssid)
	}
	assoc = append(assoc, strings.Join(c.Probes, ","))

	return assoc
}

func (c *Client) Check(bssid string, filter Filter) []string {
	if c.MAC == "00:00:00:00:00:00" {
		return nil
	}
	if c.MAC == bssid && c.Type != "tods" {
		return nil
	}

	// If map[string] empty return nil
	// If map[string] match and neg false return value
	// If map[string] not match and neg true return value
	// Default return nil

	if len(filter.BSSID) == 0 && len(filter.Probes) == 0 {
		return c.Dump(bssid)
	}
	for _, probe := range c.Probes {
		if filter.Probes[probe] && !filter.Negate {
			return c.Dump(bssid)
		} else if !filter.Probes[probe] && filter.Negate {
			return c.Dump(bssid)
		}
		return nil
	}
	if filter.BSSID[bssid] && !filter.Negate {
		return c.Dump(bssid)
	} else if !filter.BSSID[bssid] && filter.Negate {
		return c.Dump(bssid)
	}
	return nil
}

func (w *WirelessData) Dump(delm string, filter Filter) {
	d := Dump{}
	d.Header()

	for _, net := range w.Networks {

		if filter.Nets || (!filter.Nets && !filter.Clients) {
			if filter.AdHoc && !filter.Negate && net.Type != "ad-hoc" {
				continue
			} else if filter.AdHoc && filter.Negate && net.Type == "ad-hoc" {
				continue
			}
			if filter.Infra && !filter.Negate && net.Type != "infrastructure" {
				continue
			} else if filter.Infra && filter.Negate && net.Type == "infrastructure" {
				continue
			}
			if filter.NetSignal != 0 && net.Power < filter.NetSignal {
				continue
			}

			pssid := net.ParseSSID(delm)
			for _, enc := range pssid.Encrypt {
				data := net.Check(pssid, filter, enc)
				if data != nil {
					d.Networks = append(d.Networks, strings.Join(data, delm))
				}
			}
		}

		if filter.Clients || (!filter.Nets && !filter.Clients) {
			for _, c := range net.Clients {
				if filter.Probing && !filter.Negate && len(c.Probes) == 0 {
					continue
				} else if filter.Probing && !filter.Negate && c.Type != "tods" {
					continue
				} else if filter.Probing && filter.Negate && c.Type == "tods" {
					continue
				}
				if (filter.AdHoc || filter.Infra) && !filter.Negate && c.Type == "tods" {
					continue
				}
				if filter.ClientSignal != 0 && c.Power < filter.ClientSignal {
					continue
				}

				data := c.Check(net.BSSID, filter)
				if data != nil {
					d.Clients = append(d.Clients, strings.Join(data, delm))
				}
			}
		}
	}

	if filter.Nets || (!filter.Nets && !filter.Clients) {
		fmt.Println(strings.Join(d.NetHeader, delm))
		for _, nets := range d.Networks {
			fmt.Println(nets)
		}
		fmt.Println()
	}

	if filter.Clients || (!filter.Nets && !filter.Clients) {
		fmt.Println(strings.Join(d.ClientHeader, delm))
		for _, c := range d.Clients {
			fmt.Println(c)
		}
		fmt.Println()
	}

}

func main() {
	arguments, err := docopt.Parse(usage, nil, true, "kismograph 1.3", false)
	if err != nil {
		log.Fatal("Error parsing usage. Error: ", err.Error())
	}
	var filter Filter
	filter.Nets = arguments["--nets"].(bool)
	filter.Clients = arguments["--clients"].(bool)
	filter.BSSID = ParseArg(arguments["--bssid"])
	filter.ESSID = ParseArg(arguments["--essid"])
	filter.Probes = ParseArg(arguments["--probes"])
	filter.AdHoc = arguments["--ad-hoc"].(bool)
	filter.Negate = arguments["--negate"].(bool)
	filter.Infra = arguments["--infra"].(bool)

	if arguments["--netsignal"] != nil {
		sig, err := strconv.Atoi(arguments["--netsignal"].(string))
		if err != nil {
			log.Fatal(err.Error())
		}

		if sig > 0 {
			filter.NetSignal = sig - (sig * 2)
		} else {
			filter.NetSignal = sig
		}
	}
	if arguments["--clientsignal"] != nil {
		sig, err := strconv.Atoi(arguments["--clientsignal"].(string))
		if err != nil {
			log.Fatal(err.Error())
		}

		if sig > 0 {
			filter.ClientSignal = sig - (sig * 2)
		} else {
			filter.ClientSignal = sig
		}
	}

	f := arguments["<file>"].(string)
	data, err := kismoExtract(f)
	if err != nil {
		log.Fatal(err.Error())
	}

	data.Dump(", ", filter)

}
<|endoftext|>


<commit_before>package knx

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/vapourismo/knx-go/knx/cemi"
	"github.com/vapourismo/knx-go/knx/proto"
)

// ClientConfig allows you to configure the client's behavior.
type ClientConfig struct {
	// ResendInterval is how long to wait for a response, until the request is resend. A interval
	// <= 0 can't be used. The default value will be used instead.
	ResendInterval time.Duration

	// HeartbeatDelay specifies the time which has to elapse without any incoming communication,
	// until a heartbeat is triggered. A delay <= 0 will result in the use of a default value.
	HeartbeatDelay time.Duration

	// ResponseTimeout specifies how long to wait for a response. A timeout <= 0 will not be
	// accepted. Instead, the default value will be used.
	ResponseTimeout time.Duration
}

// Default configuration elements
var (
	defaultResendInterval  = 500 * time.Millisecond
	defaultHeartbeatDelay  = 10 * time.Second
	defaultResponseTimeout = 10 * time.Second

	DefaultClientConfig = ClientConfig{
		defaultResendInterval,
		defaultHeartbeatDelay,
		defaultResponseTimeout,
	}
)

// checkClientConfig makes sure that the configuration is actually usable.
func checkClientConfig(config ClientConfig) ClientConfig {
	if config.ResendInterval <= 0 {
		config.ResendInterval = defaultResendInterval
	}

	if config.HeartbeatDelay <= 0 {
		config.HeartbeatDelay = defaultHeartbeatDelay
	}

	if config.ResponseTimeout <= 0 {
		config.ResponseTimeout = defaultResponseTimeout
	}

	return config
}

// tunnelConn is a handle for a tunnel connection.
type tunnelConn struct {
	sock      Socket
	config    ClientConfig
	channel   uint8
	control   proto.HostInfo
	seqMu     *sync.Mutex
	seqNumber uint8
	ack       chan *proto.TunnelRes
	inbound   chan cemi.CEMI
}

// requestConn repeatedly sends a connection request through the socket until the provided context gets
// canceled, or a response is received. A response that renders the gateway as busy will not stop
// requestConn.
func (conn *tunnelConn) requestConn(ctx context.Context) (err error) {
	req := &proto.ConnReq{}

	// Send the initial request.
	err = conn.sock.Send(req)
	if err != nil {
		return
	}

	// Create a resend timer.
	ticker := time.NewTicker(conn.config.ResendInterval)
	defer ticker.Stop()

	// Cycle until a request gets a response.
	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return ctx.Err()

		// Resend timer triggered.
		case <-ticker.C:
			err = conn.sock.Send(req)
			if err != nil {
				return
			}

		// A message has been received or the channel has been closed.
		case msg, open := <-conn.sock.Inbound():
			if !open {
				return errors.New("Inbound channel has been closed")
			}

			// We're only interested in connection responses.
			if res, ok := msg.(*proto.ConnRes); ok {
				switch res.Status {
				// Conection has been established.
				case proto.ConnResOk:
					conn.channel = res.Channel
					conn.control = res.Control
					return nil

				// The gateway is busy, but we don't stop yet.
				case proto.ConnResBusy:
					continue

				// Connection request has been denied.
				default:
					return res.Status
				}
			}
		}
	}
}

// requestConnState periodically sends a connection state request to the gateway until it has
// received a response or the context is done.
func (conn *tunnelConn) requestConnState(
	ctx context.Context,
	heartbeat <-chan proto.ConnState,
) (proto.ConnState, error) {
	req := &proto.ConnStateReq{Channel: conn.channel, Status: 0, Control: proto.HostInfo{}}

	// Send first connection state request
	err := conn.sock.Send(req)
	if err != nil {
		return proto.ConnStateInactive, err
	}

	// Start the resend timer.
	ticker := time.NewTicker(conn.config.ResendInterval)
	defer ticker.Stop()

	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return proto.ConnStateInactive, ctx.Err()

		// Resend timer fired.
		case <-ticker.C:
			err := conn.sock.Send(req)
			if err != nil {
				return proto.ConnStateInactive, err
			}

		// Received a connection state response.
		case res, open := <-heartbeat:
			if !open {
				return proto.ConnStateInactive, errors.New("Connection server has terminated")
			}

			return res, nil
		}
	}
}

// requestDisc sends a disconnect request to the gateway.
func (conn *tunnelConn) requestDisc() error {
	return conn.sock.Send(&proto.DiscReq{
		Channel: conn.channel,
		Status:  0,
		Control: conn.control,
	})
}

// requestTunnel sends a tunnel request to the gateway and waits for an appropriate acknowledgement.
func (conn *tunnelConn) requestTunnel(
	ctx context.Context,
	data cemi.CEMI,
) error {
	// Sequence numbers cannot be reused, therefore we must protect against that.
	conn.seqMu.Lock()
	defer conn.seqMu.Unlock()

	req := &proto.TunnelReq{
		Channel:   conn.channel,
		SeqNumber: conn.seqNumber,
		Payload:   data,
	}

	// Send initial request.
	err := conn.sock.Send(req)
	if err != nil {
		return err
	}

	// Start the resend timer.
	ticker := time.NewTicker(conn.config.ResendInterval)
	defer ticker.Stop()

	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return ctx.Err()

		// Resend timer fired.
		case <-ticker.C:
			err := conn.sock.Send(req)
			if err != nil {
				return err
			}

		// Received a tunnel response.
		case res, open := <-conn.ack:
			if !open {
				return errors.New("Connection server has terminated")
			}

			// Ignore mismatching sequence numbers.
			if res.SeqNumber != conn.seqNumber {
				continue
			}

			// Gateway has received the request, therefore we can increase on our side.
			conn.seqNumber++

			// Check if the response confirms the tunnel request.
			if res.Status == 0 {
				return nil
			}

			return fmt.Errorf("Tunnel request has been rejected with status %#x", res.Status)
		}
	}
}

// performHeartbeat uses requestState to determine if the gateway is still alive.
func (conn *tunnelConn) performHeartbeat(
	ctx context.Context,
	heartbeat <-chan proto.ConnState,
	timeout chan<- struct{},
) {
	// Setup a child context which will time out with the given heartbeat timeout.
	childCtx, cancel := context.WithTimeout(ctx, conn.config.ResponseTimeout)
	defer cancel()

	// Request the connction state.
	state, err := conn.requestConnState(childCtx, heartbeat)
	if err != nil || state != proto.ConnStateNormal {
		if err != nil {
			log(conn, "conn", "Error while requesting connection state: %v", err)
		} else {
			log(conn, "conn", "Bad connection state: %v", state)
		}

		// Write to timeout as an indication that the heartbeat has failed.
		select {
		case <-ctx.Done():
		case timeout <- struct{}{}:
		}
	}
}

// handleDiscReq validates the request.
func (conn *tunnelConn) handleDiscReq(
	ctx context.Context,
	req *proto.DiscReq,
) error {
	// Validate the request channel.
	if req.Channel != conn.channel {
		return errors.New("Invalid communication channel in disconnect request")
	}

	// We don't need to check if this errors or not. It doesn't matter.
	conn.sock.Send(&proto.DiscRes{Channel: req.Channel, Status: 0})

	return nil
}

// handleDiscRes validates the response.
func (conn *tunnelConn) handleDiscRes(
	ctx context.Context,
	res *proto.DiscRes,
) error {
	// Validate the response channel.
	if res.Channel != conn.channel {
		return errors.New("Invalid communication channel in disconnect response")
	}

	return nil
}

// handleTunnelReq validates the request, pushes the data to the client and acknowledges the
// request for the gateway.
func (conn *tunnelConn) handleTunnelReq(
	ctx context.Context,
	req *proto.TunnelReq,
	seqNumber *uint8,
) error {
	// Validate the request channel.
	if req.Channel != conn.channel {
		return errors.New("Invalid communication channel in tunnel request")
	}

	// Is the sequence number what we expected?
	if req.SeqNumber == *seqNumber {
		*seqNumber++

		// Send tunnel data to the client.
		go func() {
			select {
			case <-ctx.Done():
			case conn.inbound <- req.Payload:
			}
		}()
	}

	// Send the acknowledgement.
	return conn.sock.Send(&proto.TunnelRes{
		Channel:   conn.channel,
		SeqNumber: req.SeqNumber,
		Status:    0,
	})
}

// handleTunnelRes validates the response and relays it to a sender that is awaiting an
// acknowledgement.
func (conn *tunnelConn) handleTunnelRes(
	ctx context.Context,
	res *proto.TunnelRes,
) error {
	// Validate the request channel.
	if res.Channel != conn.channel {
		return errors.New("Invalid communication channel in connection state response")
	}

	// Send to client.
	go func() {
		select {
		case <-ctx.Done():
		case <-time.After(conn.config.ResendInterval):
		case conn.ack <- res:
		}
	}()

	return nil
}

// handleConnStateRes validates the response and sends it to the heartbeat routine, if
// there is a waiting one.
func (conn *tunnelConn) handleConnStateRes(
	ctx context.Context,
	res *proto.ConnStateRes,
	heartbeat chan<- proto.ConnState,
) error {
	// Validate the request channel.
	if res.Channel != conn.channel {
		return errors.New("Invalid communication channel in connection state response")
	}

	// Send connection state to the heartbeat goroutine.
	go func() {
		select {
		case <-ctx.Done():
		case <-time.After(conn.config.ResendInterval):
		case heartbeat <- res.Status:
		}
	}()

	return nil
}

// serve processes incoming packets.
func (conn *tunnelConn) serve(
	ctx context.Context,
) error {
	defer close(conn.ack)
	defer close(conn.inbound)

	heartbeat := make(chan proto.ConnState)
	defer close(heartbeat)

	timeout := make(chan struct{})

	var seqNumber uint8

	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return ctx.Err()

		// Heartbeat worker signals a result.
		case <-timeout:
			return errors.New("Heartbeat did not succeed")

		// There were no incoming packets for some time.
		case <-time.After(conn.config.HeartbeatDelay):
			go conn.performHeartbeat(ctx, heartbeat, timeout)

		// A message has been received or the channel is closed.
		case msg, open := <-conn.sock.Inbound():
			if !open {
				return errors.New("Socket's inbound channel is closed")
			}

			// Determine what to do with the message.
			switch msg := msg.(type) {
			case *proto.DiscReq:
				err := conn.handleDiscReq(ctx, msg)
				if err == nil {
					return nil
				}

				log(conn, "conn", "Error while handling disconnect request %v: %v", msg, err)

			case *proto.DiscRes:
				err := conn.handleDiscRes(ctx, msg)
				if err == nil {
					return nil
				}

				log(conn, "conn", "Error while handling disconnect response %v: %v", msg, err)

			case *proto.TunnelReq:
				err := conn.handleTunnelReq(ctx, msg, &seqNumber)
				if err != nil {
					log(conn, "conn", "Error while handling tunnel request %v: %v", msg, err)
				}

			case *proto.TunnelRes:
				err := conn.handleTunnelRes(ctx, msg)
				if err != nil {
					log(conn, "conn", "Error while handling tunnel response %v: %v", msg, err)
				}

			case *proto.ConnStateRes:
				err := conn.handleConnStateRes(ctx, msg, heartbeat)
				if err != nil {
					log(
						conn, "conn",
						"Error while handling connection state response: %v", err,
					)
				}
			}
		}
	}
}

// Conn represents the client endpoint in a connection with a gateway.
type Conn struct {
	tunnelConn

	ctx    context.Context
	cancel context.CancelFunc
}

// Connect establishes a connection with a gateway. You can pass a zero initialized ClientConfig;
// the function will take care of filling in the default values.
func Connect(gatewayAddr string, config ClientConfig) (*Conn, error) {
	// Create socket which will be used for communication.
	sock, err := NewClientSocket(gatewayAddr)
	if err != nil {
		return nil, err
	}

	// Prepare a context for the inbound server.
	ctx, cancel := context.WithCancel(context.Background())

	// Initialize the Client structure.
	client := &Conn{
		tunnelConn: tunnelConn{
			sock:    sock,
			config:  checkClientConfig(config),
			seqMu:   &sync.Mutex{},
			ack:     make(chan *proto.TunnelRes),
			inbound: make(chan cemi.CEMI),
		},
		ctx:    ctx,
		cancel: cancel,
	}

	// Prepare a context, so that the connection request cannot run forever.
	connectCtx, cancelConnect := context.WithTimeout(ctx, client.config.ResponseTimeout)
	defer cancelConnect()

	// Connect to the gateway.
	err = client.requestConn(connectCtx)
	if err != nil {
		sock.Close()
		return nil, err
	}

	return client, nil
}

// Serve starts the internal connection server, which is needed to process incoming packets.
func (client *Conn) Serve() error {
	return client.serve(client.ctx)
}

// Close will terminate the connection.
func (client *Conn) Close() {
	client.requestDisc()
	client.cancel()
}

// Inbound retrieves the channel which transmits incoming data.
func (client *Conn) Inbound() <-chan cemi.CEMI {
	return client.inbound
}

// Send relays a tunnel request to the gateway with the given contents.
func (client *Conn) Send(data cemi.CEMI) error {
	// Prepare a context, so that we won't wait forever for a tunnel response.
	ctx, cancel := context.WithTimeout(client.ctx, client.config.ResponseTimeout)
	defer cancel()

	// Send the tunnel reqest.
	err := client.requestTunnel(ctx, data)
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Automatically start connection server when connection is established<commit_after>package knx

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/vapourismo/knx-go/knx/cemi"
	"github.com/vapourismo/knx-go/knx/proto"
)

// ClientConfig allows you to configure the client's behavior.
type ClientConfig struct {
	// ResendInterval is how long to wait for a response, until the request is resend. A interval
	// <= 0 can't be used. The default value will be used instead.
	ResendInterval time.Duration

	// HeartbeatDelay specifies the time which has to elapse without any incoming communication,
	// until a heartbeat is triggered. A delay <= 0 will result in the use of a default value.
	HeartbeatDelay time.Duration

	// ResponseTimeout specifies how long to wait for a response. A timeout <= 0 will not be
	// accepted. Instead, the default value will be used.
	ResponseTimeout time.Duration
}

// Default configuration elements
var (
	defaultResendInterval  = 500 * time.Millisecond
	defaultHeartbeatDelay  = 10 * time.Second
	defaultResponseTimeout = 10 * time.Second

	DefaultClientConfig = ClientConfig{
		defaultResendInterval,
		defaultHeartbeatDelay,
		defaultResponseTimeout,
	}
)

// checkClientConfig makes sure that the configuration is actually usable.
func checkClientConfig(config ClientConfig) ClientConfig {
	if config.ResendInterval <= 0 {
		config.ResendInterval = defaultResendInterval
	}

	if config.HeartbeatDelay <= 0 {
		config.HeartbeatDelay = defaultHeartbeatDelay
	}

	if config.ResponseTimeout <= 0 {
		config.ResponseTimeout = defaultResponseTimeout
	}

	return config
}

// tunnelConn is a handle for a tunnel connection.
type tunnelConn struct {
	sock      Socket
	config    ClientConfig
	channel   uint8
	control   proto.HostInfo
	seqMu     *sync.Mutex
	seqNumber uint8
	ack       chan *proto.TunnelRes
	inbound   chan cemi.CEMI
}

// requestConn repeatedly sends a connection request through the socket until the provided context gets
// canceled, or a response is received. A response that renders the gateway as busy will not stop
// requestConn.
func (conn *tunnelConn) requestConn(ctx context.Context) (err error) {
	req := &proto.ConnReq{}

	// Send the initial request.
	err = conn.sock.Send(req)
	if err != nil {
		return
	}

	// Create a resend timer.
	ticker := time.NewTicker(conn.config.ResendInterval)
	defer ticker.Stop()

	// Cycle until a request gets a response.
	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return ctx.Err()

		// Resend timer triggered.
		case <-ticker.C:
			err = conn.sock.Send(req)
			if err != nil {
				return
			}

		// A message has been received or the channel has been closed.
		case msg, open := <-conn.sock.Inbound():
			if !open {
				return errors.New("Inbound channel has been closed")
			}

			// We're only interested in connection responses.
			if res, ok := msg.(*proto.ConnRes); ok {
				switch res.Status {
				// Conection has been established.
				case proto.ConnResOk:
					conn.channel = res.Channel
					conn.control = res.Control
					return nil

				// The gateway is busy, but we don't stop yet.
				case proto.ConnResBusy:
					continue

				// Connection request has been denied.
				default:
					return res.Status
				}
			}
		}
	}
}

// requestConnState periodically sends a connection state request to the gateway until it has
// received a response or the context is done.
func (conn *tunnelConn) requestConnState(
	ctx context.Context,
	heartbeat <-chan proto.ConnState,
) (proto.ConnState, error) {
	req := &proto.ConnStateReq{Channel: conn.channel, Status: 0, Control: proto.HostInfo{}}

	// Send first connection state request
	err := conn.sock.Send(req)
	if err != nil {
		return proto.ConnStateInactive, err
	}

	// Start the resend timer.
	ticker := time.NewTicker(conn.config.ResendInterval)
	defer ticker.Stop()

	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return proto.ConnStateInactive, ctx.Err()

		// Resend timer fired.
		case <-ticker.C:
			err := conn.sock.Send(req)
			if err != nil {
				return proto.ConnStateInactive, err
			}

		// Received a connection state response.
		case res, open := <-heartbeat:
			if !open {
				return proto.ConnStateInactive, errors.New("Connection server has terminated")
			}

			return res, nil
		}
	}
}

// requestDisc sends a disconnect request to the gateway.
func (conn *tunnelConn) requestDisc() error {
	return conn.sock.Send(&proto.DiscReq{
		Channel: conn.channel,
		Status:  0,
		Control: conn.control,
	})
}

// requestTunnel sends a tunnel request to the gateway and waits for an appropriate acknowledgement.
func (conn *tunnelConn) requestTunnel(
	ctx context.Context,
	data cemi.CEMI,
) error {
	// Sequence numbers cannot be reused, therefore we must protect against that.
	conn.seqMu.Lock()
	defer conn.seqMu.Unlock()

	req := &proto.TunnelReq{
		Channel:   conn.channel,
		SeqNumber: conn.seqNumber,
		Payload:   data,
	}

	// Send initial request.
	err := conn.sock.Send(req)
	if err != nil {
		return err
	}

	// Start the resend timer.
	ticker := time.NewTicker(conn.config.ResendInterval)
	defer ticker.Stop()

	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return ctx.Err()

		// Resend timer fired.
		case <-ticker.C:
			err := conn.sock.Send(req)
			if err != nil {
				return err
			}

		// Received a tunnel response.
		case res, open := <-conn.ack:
			if !open {
				return errors.New("Connection server has terminated")
			}

			// Ignore mismatching sequence numbers.
			if res.SeqNumber != conn.seqNumber {
				continue
			}

			// Gateway has received the request, therefore we can increase on our side.
			conn.seqNumber++

			// Check if the response confirms the tunnel request.
			if res.Status == 0 {
				return nil
			}

			return fmt.Errorf("Tunnel request has been rejected with status %#x", res.Status)
		}
	}
}

// performHeartbeat uses requestState to determine if the gateway is still alive.
func (conn *tunnelConn) performHeartbeat(
	ctx context.Context,
	heartbeat <-chan proto.ConnState,
	timeout chan<- struct{},
) {
	// Setup a child context which will time out with the given heartbeat timeout.
	childCtx, cancel := context.WithTimeout(ctx, conn.config.ResponseTimeout)
	defer cancel()

	// Request the connction state.
	state, err := conn.requestConnState(childCtx, heartbeat)
	if err != nil || state != proto.ConnStateNormal {
		if err != nil {
			log(conn, "conn", "Error while requesting connection state: %v", err)
		} else {
			log(conn, "conn", "Bad connection state: %v", state)
		}

		// Write to timeout as an indication that the heartbeat has failed.
		select {
		case <-ctx.Done():
		case timeout <- struct{}{}:
		}
	}
}

// handleDiscReq validates the request.
func (conn *tunnelConn) handleDiscReq(
	ctx context.Context,
	req *proto.DiscReq,
) error {
	// Validate the request channel.
	if req.Channel != conn.channel {
		return errors.New("Invalid communication channel in disconnect request")
	}

	// We don't need to check if this errors or not. It doesn't matter.
	conn.sock.Send(&proto.DiscRes{Channel: req.Channel, Status: 0})

	return nil
}

// handleDiscRes validates the response.
func (conn *tunnelConn) handleDiscRes(
	ctx context.Context,
	res *proto.DiscRes,
) error {
	// Validate the response channel.
	if res.Channel != conn.channel {
		return errors.New("Invalid communication channel in disconnect response")
	}

	return nil
}

// handleTunnelReq validates the request, pushes the data to the client and acknowledges the
// request for the gateway.
func (conn *tunnelConn) handleTunnelReq(
	ctx context.Context,
	req *proto.TunnelReq,
	seqNumber *uint8,
) error {
	// Validate the request channel.
	if req.Channel != conn.channel {
		return errors.New("Invalid communication channel in tunnel request")
	}

	// Is the sequence number what we expected?
	if req.SeqNumber == *seqNumber {
		*seqNumber++

		// Send tunnel data to the client.
		go func() {
			select {
			case <-ctx.Done():
			case conn.inbound <- req.Payload:
			}
		}()
	}

	// Send the acknowledgement.
	return conn.sock.Send(&proto.TunnelRes{
		Channel:   conn.channel,
		SeqNumber: req.SeqNumber,
		Status:    0,
	})
}

// handleTunnelRes validates the response and relays it to a sender that is awaiting an
// acknowledgement.
func (conn *tunnelConn) handleTunnelRes(
	ctx context.Context,
	res *proto.TunnelRes,
) error {
	// Validate the request channel.
	if res.Channel != conn.channel {
		return errors.New("Invalid communication channel in connection state response")
	}

	// Send to client.
	go func() {
		select {
		case <-ctx.Done():
		case <-time.After(conn.config.ResendInterval):
		case conn.ack <- res:
		}
	}()

	return nil
}

// handleConnStateRes validates the response and sends it to the heartbeat routine, if
// there is a waiting one.
func (conn *tunnelConn) handleConnStateRes(
	ctx context.Context,
	res *proto.ConnStateRes,
	heartbeat chan<- proto.ConnState,
) error {
	// Validate the request channel.
	if res.Channel != conn.channel {
		return errors.New("Invalid communication channel in connection state response")
	}

	// Send connection state to the heartbeat goroutine.
	go func() {
		select {
		case <-ctx.Done():
		case <-time.After(conn.config.ResendInterval):
		case heartbeat <- res.Status:
		}
	}()

	return nil
}

// serve processes incoming packets. It will return with nil when a disconnect request or
// response has been received.
func (conn *tunnelConn) serve(
	ctx context.Context,
) error {
	defer close(conn.ack)
	defer close(conn.inbound)

	heartbeat := make(chan proto.ConnState)
	defer close(heartbeat)

	timeout := make(chan struct{})

	var seqNumber uint8

	for {
		select {
		// Termination has been requested.
		case <-ctx.Done():
			return ctx.Err()

		// Heartbeat worker signals a result.
		case <-timeout:
			return errors.New("Heartbeat did not succeed")

		// There were no incoming packets for some time.
		case <-time.After(conn.config.HeartbeatDelay):
			go conn.performHeartbeat(ctx, heartbeat, timeout)

		// A message has been received or the channel is closed.
		case msg, open := <-conn.sock.Inbound():
			if !open {
				return errors.New("Socket's inbound channel is closed")
			}

			// Determine what to do with the message.
			switch msg := msg.(type) {
			case *proto.DiscReq:
				err := conn.handleDiscReq(ctx, msg)
				if err == nil {
					return nil
				}

				log(conn, "conn", "Error while handling disconnect request %v: %v", msg, err)

			case *proto.DiscRes:
				err := conn.handleDiscRes(ctx, msg)
				if err == nil {
					return nil
				}

				log(conn, "conn", "Error while handling disconnect response %v: %v", msg, err)

			case *proto.TunnelReq:
				err := conn.handleTunnelReq(ctx, msg, &seqNumber)
				if err != nil {
					log(conn, "conn", "Error while handling tunnel request %v: %v", msg, err)
				}

			case *proto.TunnelRes:
				err := conn.handleTunnelRes(ctx, msg)
				if err != nil {
					log(conn, "conn", "Error while handling tunnel response %v: %v", msg, err)
				}

			case *proto.ConnStateRes:
				err := conn.handleConnStateRes(ctx, msg, heartbeat)
				if err != nil {
					log(
						conn, "conn",
						"Error while handling connection state response: %v", err,
					)
				}
			}
		}
	}
}

// Conn represents the client endpoint in a connection with a gateway.
type Conn struct {
	tunnelConn

	ctx    context.Context
	cancel context.CancelFunc
}

// Connect establishes a connection with a gateway. You can pass a zero initialized ClientConfig;
// the function will take care of filling in the default values.
func Connect(gatewayAddr string, config ClientConfig) (*Conn, error) {
	// Create socket which will be used for communication.
	sock, err := NewClientSocket(gatewayAddr)
	if err != nil {
		return nil, err
	}

	// Prepare a context for the inbound server.
	ctx, cancel := context.WithCancel(context.Background())

	// Initialize the Client structure.
	client := &Conn{
		tunnelConn: tunnelConn{
			sock:    sock,
			config:  checkClientConfig(config),
			seqMu:   &sync.Mutex{},
			ack:     make(chan *proto.TunnelRes),
			inbound: make(chan cemi.CEMI),
		},
		ctx:    ctx,
		cancel: cancel,
	}

	// Prepare a context, so that the connection request cannot run forever.
	connectCtx, cancelConnect := context.WithTimeout(ctx, client.config.ResponseTimeout)
	defer cancelConnect()

	// Connect to the gateway.
	err = client.requestConn(connectCtx)
	if err != nil {
		sock.Close()
		return nil, err
	}

	go client.serve(client.ctx)

	return client, nil
}

// Close will terminate the connection.
func (client *Conn) Close() {
	client.requestDisc()
	client.cancel()
}

// Inbound retrieves the channel which transmits incoming data.
func (client *Conn) Inbound() <-chan cemi.CEMI {
	return client.inbound
}

// Send relays a tunnel request to the gateway with the given contents.
func (client *Conn) Send(data cemi.CEMI) error {
	// Prepare a context, so that we won't wait forever for a tunnel response.
	ctx, cancel := context.WithTimeout(client.ctx, client.config.ResponseTimeout)
	defer cancel()

	// Send the tunnel reqest.
	err := client.requestTunnel(ctx, data)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 * 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 main

import (
	"fmt"
	"net/url"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"

	kubeAPI "k8s.io/kubernetes/pkg/api"
	kubeCache "k8s.io/kubernetes/pkg/client/cache"
	kubeClient "k8s.io/kubernetes/pkg/client/unversioned"
	kubeClientCmd "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	kubeFramework "k8s.io/kubernetes/pkg/controller/framework"
	kubeFields "k8s.io/kubernetes/pkg/fields"
)

type ServicesWatcher interface {
	AddService(obj interface{})
	DeleteService(obj interface{})
	UpdateService(oldObj interface{}, newObj interface{})
}

type EndpointsWatcher interface {
	SyncEndpoints(obj interface{})
}

/**
Initialize a kubernetes API client
*/
func newKubeClient(apiserverURLString string) (*kubeClient.Client, error) {
	var u *url.URL
	var err error
	if u, err = url.Parse(os.ExpandEnv(apiserverURLString)); err != nil {
		return nil, fmt.Errorf("Could not parse Kubernetes apiserver URL: %v. Error: %v", apiserverURLString, err)
	}
	if u.Scheme == "" || u.Host == "" || u.Host == ":" || u.Path != "" {
		return nil, fmt.Errorf("Invalid URL provided for Kubernetes API server: %v.", u)
	}

	loadingRules := kubeClientCmd.NewDefaultClientConfigLoadingRules()
	configOverrides := &kubeClientCmd.ConfigOverrides{}
	kubeConfig := kubeClientCmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)

	config, err := kubeConfig.ClientConfig()
	if err != nil {
		return nil, err
	}
	config.Host = u.String()
	config.Version = "v1"

	log.WithFields(log.Fields{"apiserverURL": config.Host, "apiVersion": config.Version}).Debug("Creating kubernetes API client")

	return kubeClient.New(config)
}

// func testKubeConnectivity(client *kubeClient.Client, labelSelector kubeLabels.Selector) error {
// 	// _, err := client.Services(kubeAPI.NamespaceDefault).List(labelSelector)
// 	_, err := client.ServerVersion()
// 	return err
// }

func buildServiceWatch(client *kubeClient.Client, watcher ServicesWatcher, tagLabel string, resyncPeriod time.Duration) (kubeCache.Store, *kubeFramework.Controller) {
	return kubeFramework.NewInformer(
		buildServiceLW(client),
		&kubeAPI.Service{},
		resyncPeriod,
		kubeFramework.ResourceEventHandlerFuncs{
			AddFunc:    watcher.AddService,
			DeleteFunc: watcher.DeleteService,
			UpdateFunc: watcher.UpdateService,
		},
	)
}

func buildEndpointsWatch(client *kubeClient.Client, watcher EndpointsWatcher, tagLabel string, resyncPeriod time.Duration) (kubeCache.Store, *kubeFramework.Controller) {
	return kubeFramework.NewInformer(
		buildEndpointsLW(client),
		&kubeAPI.Endpoints{},
		resyncPeriod,
		kubeFramework.ResourceEventHandlerFuncs{
			AddFunc:    watcher.SyncEndpoints,
			DeleteFunc: watcher.SyncEndpoints,
			UpdateFunc: func(oldObj, newObj interface{}) {
				// TODO: Avoid unwanted updates.
				watcher.SyncEndpoints(newObj)
			},
		},
	)
}

func getServiceForEndpoints(serviceStore kubeCache.Store, e *kubeAPI.Endpoints) (*kubeAPI.Service, error) {
	var (
		err    error
		key    string
		obj    interface{}
		exists bool
		ok     bool
		svc    *kubeAPI.Service
	)
	if key, err = kubeCache.MetaNamespaceKeyFunc(e); err != nil {
		return nil, err
	}
	if obj, exists, err = serviceStore.GetByKey(key); err != nil {
		return nil, fmt.Errorf("Error getting service object from services store - %v", err)
	}
	if !exists {
		log.WithFields(log.Fields{"name": e.Name, "namespace": e.Namespace}).Warn("Unable to find service for endpoint")
		return nil, nil
	}
	if svc, ok = obj.(*kubeAPI.Service); !ok {
		return nil, fmt.Errorf("got a non service object in services store %v", obj)
	}
	return svc, nil
}

// Returns a kubeCache.ListWatch that gets all changes to services.
func buildServiceLW(client *kubeClient.Client) *kubeCache.ListWatch {
	return kubeCache.NewListWatchFromClient(client, "services", kubeAPI.NamespaceAll, kubeFields.Everything())
}

// Returns a kubeCache.ListWatch that gets all changes to endpoints.
func buildEndpointsLW(client *kubeClient.Client) *kubeCache.ListWatch {
	return kubeCache.NewListWatchFromClient(client, "endpoints", kubeAPI.NamespaceAll, kubeFields.Everything())
}
<commit_msg>Filter watched Endpoints with a labels.Selector.<commit_after>/*
 * 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 main

import (
	"fmt"
	"net/url"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"

	kubeAPI "k8s.io/kubernetes/pkg/api"
	kubeCache "k8s.io/kubernetes/pkg/client/cache"
	kubeClient "k8s.io/kubernetes/pkg/client/unversioned"
	kubeClientCmd "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
	kubeFramework "k8s.io/kubernetes/pkg/controller/framework"
	kubeFields "k8s.io/kubernetes/pkg/fields"
	kubeLabels "k8s.io/kubernetes/pkg/labels"
	kubeRuntime "k8s.io/kubernetes/pkg/runtime"
	kubeWatch "k8s.io/kubernetes/pkg/watch"
)

type ServicesWatcher interface {
	AddService(obj interface{})
	DeleteService(obj interface{})
	UpdateService(oldObj interface{}, newObj interface{})
}

type EndpointsWatcher interface {
	SyncEndpoints(obj interface{})
}

/**
Initialize a kubernetes API client
*/
func newKubeClient(apiserverURLString string) (*kubeClient.Client, error) {
	var u *url.URL
	var err error
	if u, err = url.Parse(os.ExpandEnv(apiserverURLString)); err != nil {
		return nil, fmt.Errorf("Could not parse Kubernetes apiserver URL: %v. Error: %v", apiserverURLString, err)
	}
	if u.Scheme == "" || u.Host == "" || u.Host == ":" || u.Path != "" {
		return nil, fmt.Errorf("Invalid URL provided for Kubernetes API server: %v.", u)
	}

	loadingRules := kubeClientCmd.NewDefaultClientConfigLoadingRules()
	configOverrides := &kubeClientCmd.ConfigOverrides{}
	kubeConfig := kubeClientCmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)

	config, err := kubeConfig.ClientConfig()
	if err != nil {
		return nil, err
	}
	config.Host = u.String()
	config.Version = "v1"

	log.WithFields(log.Fields{"apiserverURL": config.Host, "apiVersion": config.Version}).Debug("Creating kubernetes API client")

	return kubeClient.New(config)
}

// func testKubeConnectivity(client *kubeClient.Client, labelSelector kubeLabels.Selector) error {
// 	// _, err := client.Services(kubeAPI.NamespaceDefault).List(labelSelector)
// 	_, err := client.ServerVersion()
// 	return err
// }

func buildServiceWatch(client *kubeClient.Client, watcher ServicesWatcher, tagLabel string, resyncPeriod time.Duration) (kubeCache.Store, *kubeFramework.Controller) {
	return kubeFramework.NewInformer(
		buildServiceLW(client),
		&kubeAPI.Service{},
		resyncPeriod,
		kubeFramework.ResourceEventHandlerFuncs{
			AddFunc:    watcher.AddService,
			DeleteFunc: watcher.DeleteService,
			UpdateFunc: watcher.UpdateService,
		},
	)
}

func buildEndpointsWatch(client *kubeClient.Client, watcher EndpointsWatcher, tagLabel string, resyncPeriod time.Duration) (kubeCache.Store, *kubeFramework.Controller) {
	return kubeFramework.NewInformer(
		buildEndpointsLW(client),
		&kubeAPI.Endpoints{},
		resyncPeriod,
		kubeFramework.ResourceEventHandlerFuncs{
			AddFunc:    watcher.SyncEndpoints,
			DeleteFunc: watcher.SyncEndpoints,
			UpdateFunc: func(oldObj, newObj interface{}) {
				// TODO: Avoid unwanted updates.
				watcher.SyncEndpoints(newObj)
			},
		},
	)
}

func getServiceForEndpoints(serviceStore kubeCache.Store, e *kubeAPI.Endpoints) (*kubeAPI.Service, error) {
	var (
		err    error
		key    string
		obj    interface{}
		exists bool
		ok     bool
		svc    *kubeAPI.Service
	)
	if key, err = kubeCache.MetaNamespaceKeyFunc(e); err != nil {
		return nil, err
	}
	if obj, exists, err = serviceStore.GetByKey(key); err != nil {
		return nil, fmt.Errorf("Error getting service object from services store - %v", err)
	}
	if !exists {
		log.WithFields(log.Fields{"name": e.Name, "namespace": e.Namespace}).Warn("Unable to find service for endpoint")
		return nil, nil
	}
	if svc, ok = obj.(*kubeAPI.Service); !ok {
		return nil, fmt.Errorf("got a non service object in services store %v", obj)
	}
	return svc, nil
}

// Returns a kubeCache.ListWatch that gets all changes to services.
func buildServiceLW(client *kubeClient.Client) *kubeCache.ListWatch {
	return buildLW(client, "services", nil)
}

// Returns a kubeCache.ListWatch that gets all changes to endpoints.
func buildEndpointsLW(client *kubeClient.Client) *kubeCache.ListWatch {
	return buildLW(client, "endpoints", kubeLabels.Everything().Add(LabelServiceHTTPRouted, kubeLabels.ExistsOperator, []string{}))
}

// Returns a kubeCache.ListWatch that gets all changes to endpoints.
func buildLW(client *kubeClient.Client, resource string, labelSelector kubeLabels.Selector) *kubeCache.ListWatch {
	return newListWatchFromClient(
		client,
		resource,
		kubeAPI.NamespaceAll,
		labelSelector,
		kubeFields.Everything())
}

// copied (with slight modifications) from: k8s.io/kubernetes/pkg/client/cache NewListWatchFromClient
func newListWatchFromClient(c kubeCache.Getter, resource string, namespace string, labelSelector kubeLabels.Selector, fieldSelector kubeFields.Selector) *kubeCache.ListWatch {
	listFunc := func() (kubeRuntime.Object, error) {
		return c.Get().
			Namespace(namespace).
			Resource(resource).
			LabelsSelectorParam(labelSelector).
			FieldsSelectorParam(fieldSelector).
			Do().
			Get()
	}
	watchFunc := func(resourceVersion string) (kubeWatch.Interface, error) {
		return c.Get().
			Prefix("watch").
			Namespace(namespace).
			Resource(resource).
			LabelsSelectorParam(labelSelector).
			FieldsSelectorParam(fieldSelector).
			Param("resourceVersion", resourceVersion).
			Watch()
	}
	return &kubeCache.ListWatch{ListFunc: listFunc, WatchFunc: watchFunc}
}
<|endoftext|>