<commit_before>package balancer

import (
    "github.com/trendrr/goshire/dynmap"
    // "github.com/trendrr/goshire/cheshire"
    "github.com/trendrr/goshire-shards/shards"
    clog "github.com/trendrr/goshire/log"
    "sort"
    "fmt"
    "io/ioutil"
    "log"
    "sync"
)

type Services struct {
    DataDir string
    services map[string]*shards.RouterTable
    Logger *clog.Logger
    lock sync.Mutex
}

var Servs = &Services{
    services : make(map[string]*shards.RouterTable),
    Logger : clog.NewLogger(),
}

func (this *Services) Load() error {
    this.lock.Lock()
    defer this.lock.Unlock()
    //attempt to load from datadir
    filename := fmt.Sprintf("%s/%s",this.DataDir, "services.json")
    bytes, err := ioutil.ReadFile(filename)
    if err != nil {
        return err
    }
    mp := dynmap.NewDynMap()
    err = mp.UnmarshalJSON(bytes)
    if err != nil {
        return err
    }

    for k,_ := range(mp.Map) {
        rt,ok := mp.GetDynMap(k)
        if !ok {
            continue
        }
        table, err := shards.ToRouterTable(rt)
        if err != nil {
            log.Println(err)
            continue
        }
        this.services[k] = table
    }
    return nil
}

func (this *Services) Save() error {
    this.lock.Lock()
    defer this.lock.Unlock()

    mp := dynmap.NewDynMap()

    for k,v := range(this.services) {
        mp.Put(k, v.ToDynMap())
    }

    bytes,err := mp.MarshalJSON()
    if err != nil {
        this.Logger.Printf("Error marshalling services table -- %s", err)
        return err
    }
    err = ioutil.WriteFile(fmt.Sprintf("%s/%s",this.DataDir, "services.json"), bytes, 0644)
    return err
}

//Will create and save a new router table.
func (this *Services) NewRouterTable(service string, totalshards int, repFactor int, partitionKeys []string) error {

    _, ok := this.RouterTable(service)
    if ok {
        //already exists
        return fmt.Errorf("Router Table %s already exists!", service)
    }

    rt := shards.NewRouterTable(service)
    rt.TotalPartitions = totalshards
    rt.ReplicationFactor= repFactor
    rt.PartitionKeys = partitionKeys
    this.SetRouterTable(rt)
    return nil
}

func (this *Services) Remove(service string) {
    this.lock.Lock()
    defer this.lock.Unlock()
    delete(this.services, service)
}

func (this *Services) SetRouterTable(table *shards.RouterTable) {
    this.lock.Lock()
    this.services[table.Service] = table
    this.lock.Unlock()
    err := this.Save()
    if err != nil {
        log.Printf("Error saving %s", err)
    }
}

func (this *Services) RouterTable(service string) (*shards.RouterTable, bool) {
    this.lock.Lock()
    defer this.lock.Unlock()
    t, ok := this.services[service]
    return t,ok
}

// Returns a sorted list of the available router tables.
func (this *Services) RouterTables() ([]*shards.RouterTable) {
    this.lock.Lock()
    defer this.lock.Unlock()

    tables := make([]*shards.RouterTable, 0)
    var keys []string
    for k,_ := range(this.services) {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    for _,k := range(keys) {
        v, ok := this.services[k]
        if !ok {
            continue
        }
        tables = append(tables, v)
    }
    return tables

}
<commit_msg>save after delete<commit_after>package balancer

import (
    "github.com/trendrr/goshire/dynmap"
    // "github.com/trendrr/goshire/cheshire"
    "github.com/trendrr/goshire-shards/shards"
    clog "github.com/trendrr/goshire/log"
    "sort"
    "fmt"
    "io/ioutil"
    "log"
    "sync"
)

type Services struct {
    DataDir string
    services map[string]*shards.RouterTable
    Logger *clog.Logger
    lock sync.Mutex
}

var Servs = &Services{
    services : make(map[string]*shards.RouterTable),
    Logger : clog.NewLogger(),
}

func (this *Services) Load() error {
    this.lock.Lock()
    defer this.lock.Unlock()
    //attempt to load from datadir
    filename := fmt.Sprintf("%s/%s",this.DataDir, "services.json")
    bytes, err := ioutil.ReadFile(filename)
    if err != nil {
        return err
    }
    mp := dynmap.NewDynMap()
    err = mp.UnmarshalJSON(bytes)
    if err != nil {
        return err
    }

    for k,_ := range(mp.Map) {
        rt,ok := mp.GetDynMap(k)
        if !ok {
            continue
        }
        table, err := shards.ToRouterTable(rt)
        if err != nil {
            log.Println(err)
            continue
        }
        this.services[k] = table
    }
    return nil
}

func (this *Services) Save() error {
    this.lock.Lock()
    defer this.lock.Unlock()

    mp := dynmap.NewDynMap()

    for k,v := range(this.services) {
        mp.Put(k, v.ToDynMap())
    }

    bytes,err := mp.MarshalJSON()
    if err != nil {
        this.Logger.Printf("Error marshalling services table -- %s", err)
        return err
    }
    err = ioutil.WriteFile(fmt.Sprintf("%s/%s",this.DataDir, "services.json"), bytes, 0644)
    return err
}

//Will create and save a new router table.
func (this *Services) NewRouterTable(service string, totalshards int, repFactor int, partitionKeys []string) error {

    _, ok := this.RouterTable(service)
    if ok {
        //already exists
        return fmt.Errorf("Router Table %s already exists!", service)
    }

    rt := shards.NewRouterTable(service)
    rt.TotalPartitions = totalshards
    rt.ReplicationFactor= repFactor
    rt.PartitionKeys = partitionKeys
    this.SetRouterTable(rt)
    return nil
}

func (this *Services) Remove(service string) {
    //defers are executed in the reverse order
    defer this.Save()
    this.lock.Lock()
    defer this.lock.Unlock()
    delete(this.services, service)
}

func (this *Services) SetRouterTable(table *shards.RouterTable) {
    this.lock.Lock()
    this.services[table.Service] = table
    this.lock.Unlock()
    err := this.Save()
    if err != nil {
        log.Printf("Error saving %s", err)
    }
}

func (this *Services) RouterTable(service string) (*shards.RouterTable, bool) {
    this.lock.Lock()
    defer this.lock.Unlock()
    t, ok := this.services[service]
    return t,ok
}

// Returns a sorted list of the available router tables.
func (this *Services) RouterTables() ([]*shards.RouterTable) {
    this.lock.Lock()
    defer this.lock.Unlock()

    tables := make([]*shards.RouterTable, 0)
    var keys []string
    for k,_ := range(this.services) {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    for _,k := range(keys) {
        v, ok := this.services[k]
        if !ok {
            continue
        }
        tables = append(tables, v)
    }
    return tables

}
<|endoftext|>


<commit_before>package indicsoundex

import (
	"langcomputing/charmap"
	"strings"
	// "strconv"
	"fmt"
)

func Calculate(word string, padding int) string {
	unicodeWord := strings.Split(word, "")
	wordLength, fcLength := len(unicodeWord), len(unicodeWord[0])-1

	sndx := make([]rune, wordLength)

	var isFc = true

	i := 0

	for _, value := range word {
		if isFc {
			isFc = false
			sndx[i] = value
			i++
			continue
		}

		d, err := charmap.SoundexCode(value)
		if err == nil {
			if len(sndx) != 0 || d != sndx[len(sndx)-1] {
				sndx[i] = d
				i++
			}
		}
	}

	result := string(sndx) + strings.Repeat(`0`, padding)
	fmt.Println(result)
	return string(result[0 : padding+fcLength])
}
<commit_msg>Documentation and code formatting<commit_after>// Soundex algorithm implementation for Indian languages.
package indicsoundex

import (
	"langcomputing/charmap"
	"strings"
)

func Calculate(word string, padding int) string {
	unicodeWord := strings.Split(word, "")

	// We need Unicode length of the word not length of UTF-8
	// encoded Unicode word.
	// .
	// Additionally unlike expected word[0] is not a Unicode
	// letter  instead first byte of UTF-8 encoded Unicode letter
	// (utf-8 encoded Unicode letter for Indian language is
	// normally  3 bytes in length). We need to reduce length by 1
	// to get last index of first Unicode character as strings are
	// 0 indexed.

	wordLength, firstCharLastIndex := len(unicodeWord), len(unicodeWord[0])-1

	sndx := make([]rune, wordLength)

	// Is this the first char
	var isFc = true

	i := 0

	// Note that range splits string on Unicode code point
	for _, value := range word {
		if isFc {
			// First letter of calculated soundex should
			// be replaced with first letter of the word.
			//
			// We don't need to calculate Soundex code for
			// first letter of the word.
			isFc = false
			sndx[i] = value
			i++
			continue
		}

		d, err := charmap.SoundexCode(value)

		// FIXME: do we need to do error handling?
		if err == nil {
			if d == '0' {
				continue
			}

			// Ignore consecutive characters
			if len(sndx) != 0 || d != sndx[len(sndx)-1] {
				sndx[i] = d
				i++
			}
		}
	}

	// Convert sndx a rune slice into single string and padd it
	// with `padding' number of 0
	result := string(sndx) + strings.Repeat(`0`, padding)

	// Return the string slice 0 to padding+firstCharLastIndex
	return result[0 : padding+firstCharLastIndex]
}
<|endoftext|>


<commit_before>package quic

import (
	"bytes"
	"errors"

	"github.com/lucas-clemente/quic-go/protocol"
	"github.com/lucas-clemente/quic-go/qerr"
	"github.com/lucas-clemente/quic-go/utils"
)

var (
	errPacketNumberLenNotSet             = errors.New("PublicHeader: PacketNumberLen not set")
	errResetAndVersionFlagSet            = errors.New("PublicHeader: Reset Flag and Version Flag should not be set at the same time")
	errReceivedTruncatedConnectionID     = qerr.Error(qerr.InvalidPacketHeader, "receiving packets with truncated ConnectionID is not supported")
	errInvalidConnectionID               = qerr.Error(qerr.InvalidPacketHeader, "connection ID cannot be 0")
	errGetLengthNotForVersionNegotiation = errors.New("PublicHeader: GetLength cannot be called for VersionNegotiation packets")
)

// The PublicHeader of a QUIC packet
type PublicHeader struct {
	Raw                  []byte
	ConnectionID         protocol.ConnectionID
	VersionFlag          bool
	ResetFlag            bool
	TruncateConnectionID bool
	PacketNumberLen      protocol.PacketNumberLen
	PacketNumber         protocol.PacketNumber
	VersionNumber        protocol.VersionNumber   // VersionNumber sent by the client
	SupportedVersions    []protocol.VersionNumber // VersionNumbers sent by the server
	DiversificationNonce []byte
}

// Write writes a public header
func (h *PublicHeader) Write(b *bytes.Buffer, version protocol.VersionNumber, pers protocol.Perspective) error {
	publicFlagByte := uint8(0x00)

	if h.VersionFlag && h.ResetFlag {
		return errResetAndVersionFlagSet
	}

	if h.VersionFlag {
		publicFlagByte |= 0x01
	}
	if h.ResetFlag {
		publicFlagByte |= 0x02
	}
	if !h.TruncateConnectionID {
		publicFlagByte |= 0x08
	}

	if len(h.DiversificationNonce) > 0 {
		if len(h.DiversificationNonce) != 32 {
			return errors.New("invalid diversification nonce length")
		}
		publicFlagByte |= 0x04
	}

	// only set PacketNumberLen bits if a packet number will be written
	if h.hasPacketNumber(pers) {
		switch h.PacketNumberLen {
		case protocol.PacketNumberLen1:
			publicFlagByte |= 0x00
		case protocol.PacketNumberLen2:
			publicFlagByte |= 0x10
		case protocol.PacketNumberLen4:
			publicFlagByte |= 0x20
		case protocol.PacketNumberLen6:
			publicFlagByte |= 0x30
		}
	}

	b.WriteByte(publicFlagByte)

	if !h.TruncateConnectionID {
		utils.WriteUint64(b, uint64(h.ConnectionID))
	}

	if h.VersionFlag && pers == protocol.PerspectiveClient {
		utils.WriteUint32(b, protocol.VersionNumberToTag(h.VersionNumber))
	}

	if len(h.DiversificationNonce) > 0 {
		b.Write(h.DiversificationNonce)
	}

	// if we're a server, and the VersionFlag is set, we must not include anything else in the packet
	if !h.hasPacketNumber(pers) {
		return nil
	}

	if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 && h.PacketNumberLen != protocol.PacketNumberLen6 {
		return errPacketNumberLenNotSet
	}

	switch h.PacketNumberLen {
	case protocol.PacketNumberLen1:
		b.WriteByte(uint8(h.PacketNumber))
	case protocol.PacketNumberLen2:
		utils.WriteUint16(b, uint16(h.PacketNumber))
	case protocol.PacketNumberLen4:
		utils.WriteUint32(b, uint32(h.PacketNumber))
	case protocol.PacketNumberLen6:
		utils.WriteUint48(b, uint64(h.PacketNumber))
	default:
		return errPacketNumberLenNotSet
	}

	return nil
}

// ParsePublicHeader parses a QUIC packet's public header
// the packetSentBy is the perspective of the peer that sent this PublicHeader, i.e. if we're the server, packetSentBy should be PerspectiveClient
func ParsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*PublicHeader, error) {
	header := &PublicHeader{}

	// First byte
	publicFlagByte, err := b.ReadByte()
	if err != nil {
		return nil, err
	}
	header.VersionFlag = publicFlagByte&0x01 > 0
	header.ResetFlag = publicFlagByte&0x02 > 0

	// TODO: activate this check once Chrome sends the correct value
	// see https://github.com/lucas-clemente/quic-go/issues/232
	// if publicFlagByte&0x04 > 0 {
	// 	return nil, errors.New("diversification nonces should only be sent by servers")
	// }

	if publicFlagByte&0x08 == 0 {
		return nil, errReceivedTruncatedConnectionID
	}

	if header.hasPacketNumber(packetSentBy) {
		switch publicFlagByte & 0x30 {
		case 0x30:
			header.PacketNumberLen = protocol.PacketNumberLen6
		case 0x20:
			header.PacketNumberLen = protocol.PacketNumberLen4
		case 0x10:
			header.PacketNumberLen = protocol.PacketNumberLen2
		case 0x00:
			header.PacketNumberLen = protocol.PacketNumberLen1
		}
	}

	// Connection ID
	connID, err := utils.ReadUint64(b)
	if err != nil {
		return nil, err
	}

	header.ConnectionID = protocol.ConnectionID(connID)
	if header.ConnectionID == 0 {
		return nil, errInvalidConnectionID
	}

	if packetSentBy == protocol.PerspectiveServer && publicFlagByte&0x04 > 0 {
		header.DiversificationNonce = make([]byte, 32)
		for i := 0; i < 32; i++ {
			var val byte
			val, err = b.ReadByte()
			if err != nil {
				return nil, err
			}
			header.DiversificationNonce[i] = val
		}
	}

	// Version (optional)
	if !header.ResetFlag {
		if header.VersionFlag {
			if packetSentBy == protocol.PerspectiveClient {
				var versionTag uint32
				versionTag, err = utils.ReadUint32(b)
				if err != nil {
					return nil, err
				}
				header.VersionNumber = protocol.VersionTagToNumber(versionTag)
			} else { // parse the version negotiaton packet
			if b.Len()%4 != 0 {
				return nil, qerr.InvalidVersionNegotiationPacket
			}
				header.SupportedVersions = make([]protocol.VersionNumber, 0)
				for {
					var versionTag uint32
					versionTag, err = utils.ReadUint32(b)
					if err != nil {
						break
					}
					v := protocol.VersionTagToNumber(versionTag)
					if !protocol.IsSupportedVersion(v) {
						v = protocol.VersionUnsupported
					}
					header.SupportedVersions = append(header.SupportedVersions, v)
				}
			}
		}
	}

	// Packet number
	if header.hasPacketNumber(packetSentBy) {
		packetNumber, err := utils.ReadUintN(b, uint8(header.PacketNumberLen))
		if err != nil {
			return nil, err
		}
		header.PacketNumber = protocol.PacketNumber(packetNumber)
	}

	return header, nil
}

// GetLength gets the length of the publicHeader in bytes
// can only be called for regular packets
func (h *PublicHeader) GetLength(pers protocol.Perspective) (protocol.ByteCount, error) {
	if h.VersionFlag && h.ResetFlag {
		return 0, errResetAndVersionFlagSet
	}

	if h.VersionFlag && pers == protocol.PerspectiveServer {
		return 0, errGetLengthNotForVersionNegotiation
	}

	length := protocol.ByteCount(1) // 1 byte for public flags

	if h.hasPacketNumber(pers) {
		if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 && h.PacketNumberLen != protocol.PacketNumberLen6 {
			return 0, errPacketNumberLenNotSet
		}
		length += protocol.ByteCount(h.PacketNumberLen)
	}

	if !h.TruncateConnectionID {
		length += 8 // 8 bytes for the connection ID
	}

	// Version Number in packets sent by the client
	if h.VersionFlag {
		length += 4
	}

	length += protocol.ByteCount(len(h.DiversificationNonce))

	return length, nil
}

// hasPacketNumber determines if this PublicHeader will contain a packet number
// this depends on the ResetFlag, the VersionFlag and who sent the packet
func (h *PublicHeader) hasPacketNumber(packetSentBy protocol.Perspective) bool {
	if h.ResetFlag {
		return false
	}
	if h.VersionFlag && packetSentBy == protocol.PerspectiveServer {
		return false
	}
	return true
}
<commit_msg>add workaround for incorrect public flag values sent by Google servers<commit_after>package quic

import (
	"bytes"
	"errors"

	"github.com/lucas-clemente/quic-go/protocol"
	"github.com/lucas-clemente/quic-go/qerr"
	"github.com/lucas-clemente/quic-go/utils"
)

var (
	errPacketNumberLenNotSet             = errors.New("PublicHeader: PacketNumberLen not set")
	errResetAndVersionFlagSet            = errors.New("PublicHeader: Reset Flag and Version Flag should not be set at the same time")
	errReceivedTruncatedConnectionID     = qerr.Error(qerr.InvalidPacketHeader, "receiving packets with truncated ConnectionID is not supported")
	errInvalidConnectionID               = qerr.Error(qerr.InvalidPacketHeader, "connection ID cannot be 0")
	errGetLengthNotForVersionNegotiation = errors.New("PublicHeader: GetLength cannot be called for VersionNegotiation packets")
)

// The PublicHeader of a QUIC packet
type PublicHeader struct {
	Raw                  []byte
	ConnectionID         protocol.ConnectionID
	VersionFlag          bool
	ResetFlag            bool
	TruncateConnectionID bool
	PacketNumberLen      protocol.PacketNumberLen
	PacketNumber         protocol.PacketNumber
	VersionNumber        protocol.VersionNumber   // VersionNumber sent by the client
	SupportedVersions    []protocol.VersionNumber // VersionNumbers sent by the server
	DiversificationNonce []byte
}

// Write writes a public header
func (h *PublicHeader) Write(b *bytes.Buffer, version protocol.VersionNumber, pers protocol.Perspective) error {
	publicFlagByte := uint8(0x00)

	if h.VersionFlag && h.ResetFlag {
		return errResetAndVersionFlagSet
	}

	if h.VersionFlag {
		publicFlagByte |= 0x01
	}
	if h.ResetFlag {
		publicFlagByte |= 0x02
	}
	if !h.TruncateConnectionID {
		publicFlagByte |= 0x08
	}

	if len(h.DiversificationNonce) > 0 {
		if len(h.DiversificationNonce) != 32 {
			return errors.New("invalid diversification nonce length")
		}
		publicFlagByte |= 0x04
	}

	// only set PacketNumberLen bits if a packet number will be written
	if h.hasPacketNumber(pers) {
		switch h.PacketNumberLen {
		case protocol.PacketNumberLen1:
			publicFlagByte |= 0x00
		case protocol.PacketNumberLen2:
			publicFlagByte |= 0x10
		case protocol.PacketNumberLen4:
			publicFlagByte |= 0x20
		case protocol.PacketNumberLen6:
			publicFlagByte |= 0x30
		}
	}

	b.WriteByte(publicFlagByte)

	if !h.TruncateConnectionID {
		utils.WriteUint64(b, uint64(h.ConnectionID))
	}

	if h.VersionFlag && pers == protocol.PerspectiveClient {
		utils.WriteUint32(b, protocol.VersionNumberToTag(h.VersionNumber))
	}

	if len(h.DiversificationNonce) > 0 {
		b.Write(h.DiversificationNonce)
	}

	// if we're a server, and the VersionFlag is set, we must not include anything else in the packet
	if !h.hasPacketNumber(pers) {
		return nil
	}

	if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 && h.PacketNumberLen != protocol.PacketNumberLen6 {
		return errPacketNumberLenNotSet
	}

	switch h.PacketNumberLen {
	case protocol.PacketNumberLen1:
		b.WriteByte(uint8(h.PacketNumber))
	case protocol.PacketNumberLen2:
		utils.WriteUint16(b, uint16(h.PacketNumber))
	case protocol.PacketNumberLen4:
		utils.WriteUint32(b, uint32(h.PacketNumber))
	case protocol.PacketNumberLen6:
		utils.WriteUint48(b, uint64(h.PacketNumber))
	default:
		return errPacketNumberLenNotSet
	}

	return nil
}

// ParsePublicHeader parses a QUIC packet's public header
// the packetSentBy is the perspective of the peer that sent this PublicHeader, i.e. if we're the server, packetSentBy should be PerspectiveClient
func ParsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*PublicHeader, error) {
	header := &PublicHeader{}

	// First byte
	publicFlagByte, err := b.ReadByte()
	if err != nil {
		return nil, err
	}
	header.VersionFlag = publicFlagByte&0x01 > 0
	header.ResetFlag = publicFlagByte&0x02 > 0

	// TODO: activate this check once Chrome sends the correct value
	// see https://github.com/lucas-clemente/quic-go/issues/232
	// if publicFlagByte&0x04 > 0 {
	// 	return nil, errors.New("diversification nonces should only be sent by servers")
	// }

	if publicFlagByte&0x08 == 0 {
		return nil, errReceivedTruncatedConnectionID
	}

	if header.hasPacketNumber(packetSentBy) {
		switch publicFlagByte & 0x30 {
		case 0x30:
			header.PacketNumberLen = protocol.PacketNumberLen6
		case 0x20:
			header.PacketNumberLen = protocol.PacketNumberLen4
		case 0x10:
			header.PacketNumberLen = protocol.PacketNumberLen2
		case 0x00:
			header.PacketNumberLen = protocol.PacketNumberLen1
		}
	}

	// Connection ID
	connID, err := utils.ReadUint64(b)
	if err != nil {
		return nil, err
	}

	header.ConnectionID = protocol.ConnectionID(connID)
	if header.ConnectionID == 0 {
		return nil, errInvalidConnectionID
	}

	if packetSentBy == protocol.PerspectiveServer && publicFlagByte&0x04 > 0 {
		// TODO: remove the if once the Google servers send the correct value
		// assume that a packet doesn't contain a diversification nonce if the version flag or the reset flag is set, no matter what the public flag says
		// see https://github.com/lucas-clemente/quic-go/issues/232
		if !header.VersionFlag && !header.ResetFlag {
			header.DiversificationNonce = make([]byte, 32)
			for i := 0; i < 32; i++ {
				var val byte
				val, err = b.ReadByte()
				if err != nil {
					return nil, err
				}
				header.DiversificationNonce[i] = val
			}
		}
	}

	// Version (optional)
	if !header.ResetFlag {
		if header.VersionFlag {
			if packetSentBy == protocol.PerspectiveClient {
				var versionTag uint32
				versionTag, err = utils.ReadUint32(b)
				if err != nil {
					return nil, err
				}
				header.VersionNumber = protocol.VersionTagToNumber(versionTag)
			} else { // parse the version negotiaton packet
			if b.Len()%4 != 0 {
				return nil, qerr.InvalidVersionNegotiationPacket
			}
				header.SupportedVersions = make([]protocol.VersionNumber, 0)
				for {
					var versionTag uint32
					versionTag, err = utils.ReadUint32(b)
					if err != nil {
						break
					}
					v := protocol.VersionTagToNumber(versionTag)
					if !protocol.IsSupportedVersion(v) {
						v = protocol.VersionUnsupported
					}
					header.SupportedVersions = append(header.SupportedVersions, v)
				}
			}
		}
	}

	// Packet number
	if header.hasPacketNumber(packetSentBy) {
		packetNumber, err := utils.ReadUintN(b, uint8(header.PacketNumberLen))
		if err != nil {
			return nil, err
		}
		header.PacketNumber = protocol.PacketNumber(packetNumber)
	}

	return header, nil
}

// GetLength gets the length of the publicHeader in bytes
// can only be called for regular packets
func (h *PublicHeader) GetLength(pers protocol.Perspective) (protocol.ByteCount, error) {
	if h.VersionFlag && h.ResetFlag {
		return 0, errResetAndVersionFlagSet
	}

	if h.VersionFlag && pers == protocol.PerspectiveServer {
		return 0, errGetLengthNotForVersionNegotiation
	}

	length := protocol.ByteCount(1) // 1 byte for public flags

	if h.hasPacketNumber(pers) {
		if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 && h.PacketNumberLen != protocol.PacketNumberLen6 {
			return 0, errPacketNumberLenNotSet
		}
		length += protocol.ByteCount(h.PacketNumberLen)
	}

	if !h.TruncateConnectionID {
		length += 8 // 8 bytes for the connection ID
	}

	// Version Number in packets sent by the client
	if h.VersionFlag {
		length += 4
	}

	length += protocol.ByteCount(len(h.DiversificationNonce))

	return length, nil
}

// hasPacketNumber determines if this PublicHeader will contain a packet number
// this depends on the ResetFlag, the VersionFlag and who sent the packet
func (h *PublicHeader) hasPacketNumber(packetSentBy protocol.Perspective) bool {
	if h.ResetFlag {
		return false
	}
	if h.VersionFlag && packetSentBy == protocol.PerspectiveServer {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package client

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

func spawnServer(g *libkb.GlobalContext, cl libkb.CommandLine, forkType keybase1.ForkType) (pid int, err error) {

	// If we're running under systemd, start the service as a user unit instead
	// of forking it directly. We do this here instead of higher up, because we
	// want to handle the case where the service was previously autoforked, and
	// then the user upgrades their keybase package to a version with systemd
	// support. The flock-checking code will short-circuit before we get here,
	// if the service is running, so we don't have to worry about a conflict.
	//
	// We only do this in prod mode, because keybase.service always starts
	// /usr/bin/keybase, which is probably not what you want if you're
	// autoforking in dev mode. To run the service you just built in prod mode,
	// you can either do `keybase --run-mode=prod service` manually, or you can
	// add a systemd override file (see https://askubuntu.com/q/659267/73244).
	if g.Env.WantsSystemd() {
		g.Log.Info("Starting keybase.service.")
		startCmd := exec.Command("systemctl", "--user", "start", "keybase.service")
		startCmd.Stdout = os.Stderr
		startCmd.Stderr = os.Stderr
		err = startCmd.Run()
		if err != nil {
			g.Log.Error("Failed to start keybase.service.")
		}
		return
	}

	var files []uintptr
	var cmd string
	var args []string
	var devnull *os.File

	defer func() {
		if err != nil && devnull != nil {
			devnull.Close()
		}
	}()

	if devnull, err = os.OpenFile("/dev/null", os.O_RDONLY, 0); err != nil {
		return
	}
	nullfd := devnull.Fd()
	files = append(files, nullfd, nullfd, nullfd)

	attr := syscall.ProcAttr{
		Env:   os.Environ(),
		Sys:   &syscall.SysProcAttr{Setsid: true},
		Files: files,
	}

	cmd, args, err = makeServerCommandLine(g, cl, forkType)
	if err != nil {
		return
	}

	pid, err = syscall.ForkExec(cmd, args, &attr)
	if err != nil {
		err = fmt.Errorf("Error in ForkExec: %s", err)
	} else {
		g.Log.Info("Forking background server with pid=%d", pid)
	}
	return
}
<commit_msg>always restart keybase.socket when autoforking<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package client

import (
	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
)

func spawnServer(g *libkb.GlobalContext, cl libkb.CommandLine, forkType keybase1.ForkType) (pid int, err error) {

	// If we're running under systemd, start the service as a user unit instead
	// of forking it directly. We do this here instead of higher up, because we
	// want to handle the case where the service was previously autoforked, and
	// then the user upgrades their keybase package to a version with systemd
	// support. The flock-checking code will short-circuit before we get here,
	// if the service is running, so we don't have to worry about a conflict.
	//
	// We only do this in prod mode, because keybase.service always starts
	// /usr/bin/keybase, which is probably not what you want if you're
	// autoforking in dev mode. To run the service you just built in prod mode,
	// you can either do `keybase --run-mode=prod service` manually, or you can
	// add a systemd override file (see https://askubuntu.com/q/659267/73244).
	if g.Env.WantsSystemd() {
		g.Log.Info("Starting keybase.service.")
		// Explicitly restarting the socket ensures it gets recreated, in case
		// a non-systemd invocation of the service deleted it in the meantime
		// without telling systemd it was "stopped".
		startCmd := exec.Command("systemctl", "--user", "restart", "keybase.socket", "keybase.service")
		startCmd.Stdout = os.Stderr
		startCmd.Stderr = os.Stderr
		err = startCmd.Run()
		if err != nil {
			g.Log.Error("Failed to start keybase.service.")
		}
		return
	}

	var files []uintptr
	var cmd string
	var args []string
	var devnull *os.File

	defer func() {
		if err != nil && devnull != nil {
			devnull.Close()
		}
	}()

	if devnull, err = os.OpenFile("/dev/null", os.O_RDONLY, 0); err != nil {
		return
	}
	nullfd := devnull.Fd()
	files = append(files, nullfd, nullfd, nullfd)

	attr := syscall.ProcAttr{
		Env:   os.Environ(),
		Sys:   &syscall.SysProcAttr{Setsid: true},
		Files: files,
	}

	cmd, args, err = makeServerCommandLine(g, cl, forkType)
	if err != nil {
		return
	}

	pid, err = syscall.ForkExec(cmd, args, &attr)
	if err != nil {
		err = fmt.Errorf("Error in ForkExec: %s", err)
	} else {
		g.Log.Info("Forking background server with pid=%d", pid)
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2020 The Bazel Authors. All rights reserved.
//
// 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 bzltestutil

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
)

// TestWrapperAbnormalExit is used by Wrap to indicate the child
// process exitted without an exit code (for example being killed by a signal).
// We use 6, in line with Bazel's RUN_FAILURE.
const TestWrapperAbnormalExit = 6

func ShouldWrap() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP: %q", wrapEnv)
		}
		return wrap
	}
	_, ok := os.LookupEnv("XML_OUTPUT_FILE")
	return ok
}

// shouldAddTestV indicates if the test wrapper should prepend a -test.v flag to
// the test args. This is required to get information about passing tests from
// test2json for complete XML reports.
func shouldAddTestV() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP_TESTV"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP_TESTV: %q", wrapEnv)
		}
		return wrap
	}
	return false
}

func Wrap(pkg string) error {
	var jsonBuffer bytes.Buffer
	jsonConverter := NewConverter(&jsonBuffer, pkg, Timestamp)

	args := os.Args[1:]
	if shouldAddTestV() {
		args = append([]string{"-test.v"}, args...)
	}
	exePath := os.Args[0]
	if !filepath.IsAbs(exePath) && strings.ContainsRune(exePath, filepath.Separator) && testExecDir != "" {
		exePath = filepath.Join(testExecDir, exePath)
	}
	cmd := exec.Command(exePath, args...)
	cmd.Env = append(os.Environ(), "GO_TEST_WRAP=0")
	cmd.Stderr = os.Stderr
	cmd.Stdout = io.MultiWriter(os.Stdout, jsonConverter)
	err := cmd.Run()
	jsonConverter.Close()
	if out, ok := os.LookupEnv("XML_OUTPUT_FILE"); ok {
		werr := writeReport(jsonBuffer, pkg, out)
		if werr != nil {
			if err != nil {
				return fmt.Errorf("error while generating testreport: %s, (error wrapping test execution: %s)", werr, err)
			}
			return fmt.Errorf("error while generating testreport: %s", werr)
		}
	}
	return err
}

func writeReport(jsonBuffer bytes.Buffer, pkg string, path string) error {
	xml, cerr := json2xml(&jsonBuffer, pkg)
	if cerr != nil {
		return fmt.Errorf("error converting test output to xml: %s", cerr)
	}
	if err := ioutil.WriteFile(path, xml, 0664); err != nil {
		return fmt.Errorf("error writing test xml: %s", err)
	}
	return nil
}
<commit_msg>also write test stderr to json (xml) output file (#3300)<commit_after>// Copyright 2020 The Bazel Authors. All rights reserved.
//
// 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 bzltestutil

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

// TestWrapperAbnormalExit is used by Wrap to indicate the child
// process exitted without an exit code (for example being killed by a signal).
// We use 6, in line with Bazel's RUN_FAILURE.
const TestWrapperAbnormalExit = 6

func ShouldWrap() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP: %q", wrapEnv)
		}
		return wrap
	}
	_, ok := os.LookupEnv("XML_OUTPUT_FILE")
	return ok
}

// shouldAddTestV indicates if the test wrapper should prepend a -test.v flag to
// the test args. This is required to get information about passing tests from
// test2json for complete XML reports.
func shouldAddTestV() bool {
	if wrapEnv, ok := os.LookupEnv("GO_TEST_WRAP_TESTV"); ok {
		wrap, err := strconv.ParseBool(wrapEnv)
		if err != nil {
			log.Fatalf("invalid value for GO_TEST_WRAP_TESTV: %q", wrapEnv)
		}
		return wrap
	}
	return false
}

func Wrap(pkg string) error {
	var jsonBuffer bytes.Buffer
	jsonConverter := NewConverter(&jsonBuffer, pkg, Timestamp)
	pipeRead, pipeWrite := io.Pipe()

	args := os.Args[1:]
	if shouldAddTestV() {
		args = append([]string{"-test.v"}, args...)
	}
	exePath := os.Args[0]
	if !filepath.IsAbs(exePath) && strings.ContainsRune(exePath, filepath.Separator) && testExecDir != "" {
		exePath = filepath.Join(testExecDir, exePath)
	}
	cmd := exec.Command(exePath, args...)
	cmd.Env = append(os.Environ(), "GO_TEST_WRAP=0")
	cmd.Stderr = io.MultiWriter(os.Stderr, pipeWrite)
	cmd.Stdout = io.MultiWriter(os.Stdout, pipeWrite)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		_, err := io.Copy(jsonConverter, pipeRead)
		if err != nil {
			panic(err)
		}
		wg.Done()
	}()
	err := cmd.Run()
	pipeWrite.Close()
	wg.Wait()
	jsonConverter.Close()
	if out, ok := os.LookupEnv("XML_OUTPUT_FILE"); ok {
		werr := writeReport(jsonBuffer, pkg, out)
		if werr != nil {
			if err != nil {
				return fmt.Errorf("error while generating testreport: %s, (error wrapping test execution: %s)", werr, err)
			}
			return fmt.Errorf("error while generating testreport: %s", werr)
		}
	}
	return err
}

func writeReport(jsonBuffer bytes.Buffer, pkg string, path string) error {
	xml, cerr := json2xml(&jsonBuffer, pkg)
	if cerr != nil {
		return fmt.Errorf("error converting test output to xml: %s", cerr)
	}
	if err := ioutil.WriteFile(path, xml, 0664); err != nil {
		return fmt.Errorf("error writing test xml: %s", err)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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 servenv

import (
	"flag"
	"fmt"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"math"
	"time"

	"github.com/grpc-ecosystem/go-grpc-prometheus"

	"golang.org/x/net/context"
	"google.golang.org/grpc/keepalive"
	"vitess.io/vitess/go/vt/grpccommon"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/vttls"
)

// This file handles gRPC server, on its own port.
// Clients register servers, based on service map:
//
// servenv.RegisterGRPCFlags()
// servenv.OnRun(func() {
//   if servenv.GRPCCheckServiceMap("XXX") {
//     pb.RegisterXXX(servenv.GRPCServer, XXX)
//   }
// }
//
// Note servenv.GRPCServer can only be used in servenv.OnRun,
// and not before, as it is initialized right before calling OnRun.
var (
	// GRPCPort is the port to listen on for gRPC. If not set or zero, don't listen.
	GRPCPort = flag.Int("grpc_port", 0, "Port to listen on for gRPC calls")

	// GRPCCert is the cert to use if TLS is enabled
	GRPCCert = flag.String("grpc_cert", "", "certificate to use, requires grpc_key, enables TLS")

	// GRPCKey is the key to use if TLS is enabled
	GRPCKey = flag.String("grpc_key", "", "key to use, requires grpc_cert, enables TLS")

	// GRPCCA is the CA to use if TLS is enabled
	GRPCCA = flag.String("grpc_ca", "", "ca to use, requires TLS, and enforces client cert check")

	// GRPCAuth which auth plugin to use (at the moment now only static is supported)
	GRPCAuth = flag.String("grpc_auth_mode", "", "Which auth plugin implementation to use (eg: static)")

	// GRPCServer is the global server to serve gRPC.
	GRPCServer *grpc.Server

	// GRPCMaxConnectionAge is the maximum age of a client connection, before GoAway is sent.
	// This is useful for L4 loadbalancing to ensure rebalancing after scaling.
	GRPCMaxConnectionAge = flag.Duration("grpc_max_connection_age", time.Duration(math.MaxInt64), "Maximum age of a client connection before GoAway is sent.")

	// GRPCMaxConnectionAgeGrace is an additional grace period after GRPCMaxConnectionAge, after which
	// connections are forcibly closed.
	GRPCMaxConnectionAgeGrace = flag.Duration("grpc_max_connection_age_grace", time.Duration(math.MaxInt64), "Additional grace period after grpc_max_connection_age, after which connections are forcibly closed.")

	authPlugin Authenticator
)

// isGRPCEnabled returns true if gRPC server is set
func isGRPCEnabled() bool {
	if GRPCPort != nil && *GRPCPort != 0 {
		return true
	}

	if SocketFile != nil && *SocketFile != "" {
		return true
	}

	return false
}

// createGRPCServer create the gRPC server we will be using.
// It has to be called after flags are parsed, but before
// services register themselves.
func createGRPCServer() {
	// skip if not registered
	if !isGRPCEnabled() {
		log.Infof("Skipping gRPC server creation")
		return
	}

	grpccommon.EnableTracingOpt()

	var opts []grpc.ServerOption
	if GRPCPort != nil && *GRPCCert != "" && *GRPCKey != "" {
		config, err := vttls.ServerConfig(*GRPCCert, *GRPCKey, *GRPCCA)
		if err != nil {
			log.Exitf("Failed to log gRPC cert/key/ca: %v", err)
		}

		// create the creds server options
		creds := credentials.NewTLS(config)
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	// Override the default max message size for both send and receive
	// (which is 4 MiB in gRPC 1.0.0).
	// Large messages can occur when users try to insert or fetch very big
	// rows. If they hit the limit, they'll see the following error:
	// grpc: received message length XXXXXXX exceeding the max size 4194304
	// Note: For gRPC 1.0.0 it's sufficient to set the limit on the server only
	// because it's not enforced on the client side.
	log.Infof("Setting grpc max message size to %d", *grpccommon.MaxMessageSize)
	opts = append(opts, grpc.MaxRecvMsgSize(*grpccommon.MaxMessageSize))
	opts = append(opts, grpc.MaxSendMsgSize(*grpccommon.MaxMessageSize))

	if GRPCMaxConnectionAge != nil {
		ka := keepalive.ServerParameters{
			MaxConnectionAge: *GRPCMaxConnectionAge,
		}
		if GRPCMaxConnectionAgeGrace != nil {
			ka.MaxConnectionAgeGrace = *GRPCMaxConnectionAgeGrace
		}
		opts = append(opts, grpc.KeepaliveParams(ka))
	}

	if *GRPCAuth != "" {
		log.Infof("enabling auth plugin %v", *GRPCAuth)
		pluginInitializer := GetAuthenticator(*GRPCAuth)
		authPluginImpl, err := pluginInitializer()
		if err != nil {
			log.Fatalf("Failed to load auth plugin: %v", err)
		}
		authPlugin = authPluginImpl
		opts = append(opts, grpc.StreamInterceptor(streamInterceptor))
		opts = append(opts, grpc.UnaryInterceptor(unaryInterceptor))
	}

	if *grpccommon.EnableGRPCPrometheus {
		opts = append(opts, grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor))
		opts = append(opts, grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor))
	}

	GRPCServer = grpc.NewServer(opts...)
}

func serveGRPC() {
	if *grpccommon.EnableGRPCPrometheus {
		grpc_prometheus.Register(GRPCServer)
		grpc_prometheus.EnableHandlingTimeHistogram()
	}
	// skip if not registered
	if GRPCPort == nil || *GRPCPort == 0 {
		return
	}

	// listen on the port
	log.Infof("Listening for gRPC calls on port %v", *GRPCPort)
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", *GRPCPort))
	if err != nil {
		log.Exitf("Cannot listen on port %v for gRPC: %v", *GRPCPort, err)
	}

	// and serve on it
	// NOTE: Before we call Serve(), all services must have registered themselves
	//       with "GRPCServer". This is the case because go/vt/servenv/run.go
	//       runs all OnRun() hooks after createGRPCServer() and before
	//       serveGRPC(). If this was not the case, the binary would crash with
	//       the error "grpc: Server.RegisterService after Server.Serve".
	go GRPCServer.Serve(listener)

	OnTermSync(func() {
		log.Info("Initiated graceful stop of gRPC server")
		GRPCServer.GracefulStop()
		log.Info("gRPC server stopped")
	})
}

// GRPCCheckServiceMap returns if we should register a gRPC service
// (and also logs how to enable / disable it)
func GRPCCheckServiceMap(name string) bool {
	// Silently fail individual services if gRPC is not enabled in
	// the first place (either on a grpc port or on the socket file)
	if !isGRPCEnabled() {
		return false
	}

	// then check ServiceMap
	return CheckServiceMap("grpc", name)
}

func streamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
	newCtx, err := authPlugin.Authenticate(stream.Context(), info.FullMethod)

	if err != nil {
		return err
	}

	wrapped := WrapServerStream(stream)
	wrapped.WrappedContext = newCtx
	return handler(srv, wrapped)
}

func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	newCtx, err := authPlugin.Authenticate(ctx, info.FullMethod)
	if err != nil {
		return nil, err
	}

	return handler(newCtx, req)
}

// WrappedServerStream is based on the service stream wrapper from: https://github.com/grpc-ecosystem/go-grpc-middleware
type WrappedServerStream struct {
	grpc.ServerStream
	WrappedContext context.Context
}

// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
func (w *WrappedServerStream) Context() context.Context {
	return w.WrappedContext
}

// WrapServerStream returns a ServerStream that has the ability to overwrite context.
func WrapServerStream(stream grpc.ServerStream) *WrappedServerStream {
	if existing, ok := stream.(*WrappedServerStream); ok {
		return existing
	}
	return &WrappedServerStream{ServerStream: stream, WrappedContext: stream.Context()}
}
<commit_msg>Add grpc window size server<commit_after>/*
Copyright 2017 Google Inc.

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 servenv

import (
	"flag"
	"fmt"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"

	"math"
	"time"

	"github.com/grpc-ecosystem/go-grpc-prometheus"

	"golang.org/x/net/context"
	"google.golang.org/grpc/keepalive"
	"vitess.io/vitess/go/vt/grpccommon"
	"vitess.io/vitess/go/vt/log"
	"vitess.io/vitess/go/vt/vttls"
)

// This file handles gRPC server, on its own port.
// Clients register servers, based on service map:
//
// servenv.RegisterGRPCFlags()
// servenv.OnRun(func() {
//   if servenv.GRPCCheckServiceMap("XXX") {
//     pb.RegisterXXX(servenv.GRPCServer, XXX)
//   }
// }
//
// Note servenv.GRPCServer can only be used in servenv.OnRun,
// and not before, as it is initialized right before calling OnRun.
var (
	// GRPCPort is the port to listen on for gRPC. If not set or zero, don't listen.
	GRPCPort = flag.Int("grpc_port", 0, "Port to listen on for gRPC calls")

	// GRPCCert is the cert to use if TLS is enabled
	GRPCCert = flag.String("grpc_cert", "", "certificate to use, requires grpc_key, enables TLS")

	// GRPCKey is the key to use if TLS is enabled
	GRPCKey = flag.String("grpc_key", "", "key to use, requires grpc_cert, enables TLS")

	// GRPCCA is the CA to use if TLS is enabled
	GRPCCA = flag.String("grpc_ca", "", "ca to use, requires TLS, and enforces client cert check")

	// GRPCAuth which auth plugin to use (at the moment now only static is supported)
	GRPCAuth = flag.String("grpc_auth_mode", "", "Which auth plugin implementation to use (eg: static)")

	// GRPCServer is the global server to serve gRPC.
	GRPCServer *grpc.Server

	// GRPCMaxConnectionAge is the maximum age of a client connection, before GoAway is sent.
	// This is useful for L4 loadbalancing to ensure rebalancing after scaling.
	GRPCMaxConnectionAge = flag.Duration("grpc_max_connection_age", time.Duration(math.MaxInt64), "Maximum age of a client connection before GoAway is sent.")

	// GRPCMaxConnectionAgeGrace is an additional grace period after GRPCMaxConnectionAge, after which
	// connections are forcibly closed.
	GRPCMaxConnectionAgeGrace = flag.Duration("grpc_max_connection_age_grace", time.Duration(math.MaxInt64), "Additional grace period after grpc_max_connection_age, after which connections are forcibly closed.")

	// GRPCInitialConnWindowSize ServerOption that sets window size for a connection.
	// The lower bound for window size is 64K and any value smaller than that will be ignored.
	GRPCInitialConnWindowSize = flag.Int("grpc_server_initial_conn_window_size", 0, "grpc server initial connection window size")

	// GRPCInitialWindowSize ServerOption that sets window size for stream.
	// The lower bound for window size is 64K and any value smaller than that will be ignored.
	GRPCInitialWindowSize = flag.Int("grpc_server_initial_window_size", 0, "grpc server initial window size")

	authPlugin Authenticator
)

// isGRPCEnabled returns true if gRPC server is set
func isGRPCEnabled() bool {
	if GRPCPort != nil && *GRPCPort != 0 {
		return true
	}

	if SocketFile != nil && *SocketFile != "" {
		return true
	}

	return false
}

// createGRPCServer create the gRPC server we will be using.
// It has to be called after flags are parsed, but before
// services register themselves.
func createGRPCServer() {
	// skip if not registered
	if !isGRPCEnabled() {
		log.Infof("Skipping gRPC server creation")
		return
	}

	grpccommon.EnableTracingOpt()

	var opts []grpc.ServerOption
	if GRPCPort != nil && *GRPCCert != "" && *GRPCKey != "" {
		config, err := vttls.ServerConfig(*GRPCCert, *GRPCKey, *GRPCCA)
		if err != nil {
			log.Exitf("Failed to log gRPC cert/key/ca: %v", err)
		}

		// create the creds server options
		creds := credentials.NewTLS(config)
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}
	// Override the default max message size for both send and receive
	// (which is 4 MiB in gRPC 1.0.0).
	// Large messages can occur when users try to insert or fetch very big
	// rows. If they hit the limit, they'll see the following error:
	// grpc: received message length XXXXXXX exceeding the max size 4194304
	// Note: For gRPC 1.0.0 it's sufficient to set the limit on the server only
	// because it's not enforced on the client side.
	log.Infof("Setting grpc max message size to %d", *grpccommon.MaxMessageSize)
	opts = append(opts, grpc.MaxRecvMsgSize(*grpccommon.MaxMessageSize))
	opts = append(opts, grpc.MaxSendMsgSize(*grpccommon.MaxMessageSize))
	opts = append(opts, grpc.MaxConcurrentStreams(10))

	if *GRPCInitialConnWindowSize != 0 {
		log.Infof("Setting grpc server initial conn window size to %d", int32(*GRPCInitialConnWindowSize))
		opts = append(opts, grpc.InitialConnWindowSize(int32(*GRPCInitialConnWindowSize)))
	}

	if *GRPCInitialWindowSize != 0 {
		log.Infof("Setting grpc server initial window size to %d", int32(*GRPCInitialWindowSize))
		opts = append(opts, grpc.InitialWindowSize(int32(*GRPCInitialWindowSize)))
	}

	if GRPCMaxConnectionAge != nil {
		ka := keepalive.ServerParameters{
			MaxConnectionAge: *GRPCMaxConnectionAge,
		}
		if GRPCMaxConnectionAgeGrace != nil {
			ka.MaxConnectionAgeGrace = *GRPCMaxConnectionAgeGrace
		}
		opts = append(opts, grpc.KeepaliveParams(ka))
	}

	if *GRPCAuth != "" {
		log.Infof("enabling auth plugin %v", *GRPCAuth)
		pluginInitializer := GetAuthenticator(*GRPCAuth)
		authPluginImpl, err := pluginInitializer()
		if err != nil {
			log.Fatalf("Failed to load auth plugin: %v", err)
		}
		authPlugin = authPluginImpl
		opts = append(opts, grpc.StreamInterceptor(streamInterceptor))
		opts = append(opts, grpc.UnaryInterceptor(unaryInterceptor))
	}

	if *grpccommon.EnableGRPCPrometheus {
		opts = append(opts, grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor))
		opts = append(opts, grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor))
	}

	GRPCServer = grpc.NewServer(opts...)
}

func serveGRPC() {
	if *grpccommon.EnableGRPCPrometheus {
		grpc_prometheus.Register(GRPCServer)
		grpc_prometheus.EnableHandlingTimeHistogram()
	}
	// skip if not registered
	if GRPCPort == nil || *GRPCPort == 0 {
		return
	}

	// listen on the port
	log.Infof("Listening for gRPC calls on port %v", *GRPCPort)
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", *GRPCPort))
	if err != nil {
		log.Exitf("Cannot listen on port %v for gRPC: %v", *GRPCPort, err)
	}

	// and serve on it
	// NOTE: Before we call Serve(), all services must have registered themselves
	//       with "GRPCServer". This is the case because go/vt/servenv/run.go
	//       runs all OnRun() hooks after createGRPCServer() and before
	//       serveGRPC(). If this was not the case, the binary would crash with
	//       the error "grpc: Server.RegisterService after Server.Serve".
	go GRPCServer.Serve(listener)

	OnTermSync(func() {
		log.Info("Initiated graceful stop of gRPC server")
		GRPCServer.GracefulStop()
		log.Info("gRPC server stopped")
	})
}

// GRPCCheckServiceMap returns if we should register a gRPC service
// (and also logs how to enable / disable it)
func GRPCCheckServiceMap(name string) bool {
	// Silently fail individual services if gRPC is not enabled in
	// the first place (either on a grpc port or on the socket file)
	if !isGRPCEnabled() {
		return false
	}

	// then check ServiceMap
	return CheckServiceMap("grpc", name)
}

func streamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
	newCtx, err := authPlugin.Authenticate(stream.Context(), info.FullMethod)

	if err != nil {
		return err
	}

	wrapped := WrapServerStream(stream)
	wrapped.WrappedContext = newCtx
	return handler(srv, wrapped)
}

func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	newCtx, err := authPlugin.Authenticate(ctx, info.FullMethod)
	if err != nil {
		return nil, err
	}

	return handler(newCtx, req)
}

// WrappedServerStream is based on the service stream wrapper from: https://github.com/grpc-ecosystem/go-grpc-middleware
type WrappedServerStream struct {
	grpc.ServerStream
	WrappedContext context.Context
}

// Context returns the wrapper's WrappedContext, overwriting the nested grpc.ServerStream.Context()
func (w *WrappedServerStream) Context() context.Context {
	return w.WrappedContext
}

// WrapServerStream returns a ServerStream that has the ability to overwrite context.
func WrapServerStream(stream grpc.ServerStream) *WrappedServerStream {
	if existing, ok := stream.(*WrappedServerStream); ok {
		return existing
	}
	return &WrappedServerStream{ServerStream: stream, WrappedContext: stream.Context()}
}
<|endoftext|>


<commit_before>package riffle

import (
	"fmt"

	"github.com/exis-io/core"
	"github.com/exis-io/core/goRiffle"
)

type Domain interface {
	Subscribe(string) (int, int)
	// Register(string, uint, []interface{}) error

	// Publish(string, uint, []interface{}) error
	// Call(string, uint, []interface{}) ([]interface{}, error)

	// Yield(uint, []interface{})

	// Unsubscribe(string) error
	// Unregister(string) error

	// Join(Connection) error
	// Leave() error
}

type App struct {
	app  core.App
	conn *goRiffle.WebsocketConnection
	recv chan []byte
}

type domain struct {
	core core.Domain
}

// var man = &Mantle{
// 	recv: make(chan []byte),
// }

func main() {}

func (m *App) NewDomain(name string) Domain {
	fmt.Println("NewDomain called!")

	if m.app == nil {
		m.app = core.NewApp()
	}

	d := domain{
		core: m.app.NewDomain(name, m),
	}

	return d
}

// Applys a set of parameters to the core domain using the passed function
// func domainCall(operation func(), endpoint string, args []interface{}) (uint, uint) {
// 	d := *(*core.Domain)(pdomain)
// 	cb, eb := core.NewID(), core.NewID()

// 	go func() {
// 		d.Subscribe(endpoint), cb, make([]interface{}, 0))
// 	}()

// 	return marshall([]uint{cb, eb})
// }

func (d domain) Subscribe(endpoint string) (int, int) {
	return 0, 0
}

/*
//export Register
func Register(endpoint string) []byte {
	d := *(*core.Domain)(pdomain)
	cb, eb := core.NewID(), core.NewID()

	go func() {
		d.Register(endpoint), cb, make([]interface{}, 0))
	}()

	return marshall([]uint{cb, eb})
}

func Yield(args []byte) {
	// This needs work
	// core.Yield(e))
}

func Publish(endpoint string) {
	d := *(*core.Domain)(pdomain)
	cb, _ := core.NewID(), core.NewID()

	go func() {
		d.Publish(endpoint), cb, make([]interface{}, 0))
	}()
}

func Call(endpoint string) {
	d := *(*core.Domain)(pdomain)
	cb, _ := core.NewID(), core.NewID()

	go func() {
		d.Call(endpoint), cb, make([]interface{}, 0))
	}()
}

func Unsubscribe(pdomain unsafe.Pointer, e string) {
	d := *(*core.Domain)(pdomain)
	d.Unsubscribe(e))
}

func Unregister(pdomain unsafe.Pointer, e string) {
	d := *(*core.Domain)(pdomain)
	d.Unregister(e))
}

//export Join
func Join(pdomain unsafe.Pointer) []byte {
	d := *(*core.Domain)(pdomain)
	cb, eb := core.NewID(), core.NewID()

	go func() {
		if man.conn != nil {
			man.InvokeError(eb, "Connection is already open!")
		}

		if c, err := goRiffle.Open(core.DevFabric); err != nil {
			man.InvokeError(eb, err.Error())
		} else {
			man.conn = c
			c.App = man.app

			if err := d.Join(c); err != nil {
				core.Warn("Unable to join! %s", err)
				man.InvokeError(eb, err.Error())
			} else {
				core.Info("Joined!")
				man.Invoke(cb, nil)
			}
		}
	}()

	return marshall([]uint{cb, eb})
}

//export Leave
func Leave(pdomain unsafe.Pointer) {
	d := *(*core.Domain)(pdomain)
	d.Leave()
}

//export Recieve
func Recieve() []byte {
	data := <-man.recv
	return data
}

func marshall(data interface{}) []byte {
	if r, e := json.Marshal(data); e == nil {
		return r
	} else {
		fmt.Println("Unable to marshall data!")
		return nil
	}
}

func unmarshall() {

}
*/

// Unexported Functions
// func (m *App) invoke(id uint, args []interface{}) {
// core.Debug("Invoke called: ", id, args)
// man.recv <- marshall(map[string]interface{}{"0": id, "1": args})
// m.recv <- marshall([]interface{}{id, args})
// }

// func (m *App) InvokeError(id uint, e string) {
// core.Debug("Invoking error: ", id, e)
// s := fmt.Sprintf("Err: %s", e)
// m.recv <- marshall([]interface{}{id, s})
// }

//export SetLoggingLevel
func SetLoggingLevel(l int) {
	core.LogLevel = l
}
<commit_msg>gopy decided to crap out on me. Restabilized<commit_after>package riffle

import (
	"fmt"

	"github.com/exis-io/core"
)

func main() {}

// type Domaine interface {
// 	Subscribe(string) (int, int)
// 	// Register(string, uint, []interface{}) error

// 	// Publish(string, uint, []interface{}) error
// 	// Call(string, uint, []interface{}) ([]interface{}, error)

// 	// Yield(uint, []interface{})

// 	// Unsubscribe(string) error
// 	// Unregister(string) error

// 	Join() (uint, uint)
// 	// Leave() error
// }

// type AppIface interface {
// 	NewDomain(string) Domain
// }

// type App struct {
// 	coreApp core.App
// 	conn    *goRiffle.WebsocketConnection
// }

// type Domain struct {
// 	*App
// 	core core.Domain
// }

// func (a *App) NewDomain(name string) Domain {
// 	if a.coreApp == nil {
// 		a.coreApp = core.NewApp()
// 	}

// 	d := Domain{
// 		App:  a,
// 		core: a.coreApp.NewDomain(name),
// 	}

// 	return d
// }

// Exmaple
// Iface has a single F() method
type AppIface interface {
	NewDomain()
}

type DomainIface interface {
	Join()
}

// T implements Iface
type App struct{}
type Domain struct{}

func (t *App) NewDomain() Domain {
	fmt.Printf("App.NewDomain\n")
	return Domain{}
}

func (t *Domain) Join() {
	fmt.Printf("Domain.Join\n")
}

// func (d *Domain) Join() int {

// 	if d.App.conn != nil {
// 		// man.InvokeError(eb, "Connection is already open!")
// 		core.Warn("Connection is already open!")
// 	}

// 	if c, err := goRiffle.Open(core.DevFabric); err != nil {
// 		// man.InvokeError(eb, err.Error())
// 		core.Warn("Unable to open connection: %s", err.Error())
// 	} else {
// 		d.App.conn = c
// 		c.App = d.App.app

// 		if err := d.core.Join(c); err != nil {
// 			core.Warn("Unable to join! %s", err)
// 			// man.InvokeError(eb, err.Error())
// 		} else {
// 			core.Info("Joined!")
// 			// man.Invoke(cb, nil)
// 		}
// 	}

// 	return 0
// }

// func (d Domain) Subscribe(endpoint string) (int, int) {
// 	return 0, 0
// }

// Applys a set of parameters to the core domain using the passed function
// func domainCall(operation func(), endpoint string, args []interface{}) (uint, uint) {
// 	d := *(*core.Domain)(pdomain)
// 	cb, eb := core.NewID(), core.NewID()

// 	go func() {
// 		d.Subscribe(endpoint), cb, make([]interface{}, 0))
// 	}()

// 	return marshall([]uint{cb, eb})
// }

/*
//export Register
func Register(endpoint string) []byte {
	d := *(*core.Domain)(pdomain)
	cb, eb := core.NewID(), core.NewID()

	go func() {
		d.Register(endpoint), cb, make([]interface{}, 0))
	}()

	return marshall([]uint{cb, eb})
}

func Yield(args []byte) {
	// This needs work
	// core.Yield(e))
}

func Publish(endpoint string) {
	d := *(*core.Domain)(pdomain)
	cb, _ := core.NewID(), core.NewID()

	go func() {
		d.Publish(endpoint), cb, make([]interface{}, 0))
	}()
}

func Call(endpoint string) {
	d := *(*core.Domain)(pdomain)
	cb, _ := core.NewID(), core.NewID()

	go func() {
		d.Call(endpoint), cb, make([]interface{}, 0))
	}()
}

func Unsubscribe(pdomain unsafe.Pointer, e string) {
	d := *(*core.Domain)(pdomain)
	d.Unsubscribe(e))
}

func Unregister(pdomain unsafe.Pointer, e string) {
	d := *(*core.Domain)(pdomain)
	d.Unregister(e))
}

//export Leave
func Leave(pdomain unsafe.Pointer) {
	d := *(*core.Domain)(pdomain)
	d.Leave()
}

//export Recieve
func Recieve() []byte {
	data := <-man.recv
	return data
}

func marshall(data interface{}) []byte {
	if r, e := json.Marshal(data); e == nil {
		return r
	} else {
		fmt.Println("Unable to marshall data!")
		return nil
	}
}

func unmarshall() {

}
*/

// Unexported Functions
// func (m *App) invoke(id uint, args []interface{}) {
// core.Debug("Invoke called: ", id, args)
// man.recv <- marshall(map[string]interface{}{"0": id, "1": args})
// m.recv <- marshall([]interface{}{id, args})
// }

// func (m *App) InvokeError(id uint, e string) {
// core.Debug("Invoking error: ", id, e)
// s := fmt.Sprintf("Err: %s", e)
// m.recv <- marshall([]interface{}{id, s})
// }

func SetLoggingLevel(l int) {
	core.LogLevel = l
}
<|endoftext|>


<commit_before>// Package thumbnail provides a simple interface to thumbnail a JPEG stream and
// return the thumbnailed version.
package thumbnail

import (
	"io"
	"math"

	"github.com/pixiv/go-thumber/jpeg"
	"github.com/pixiv/go-thumber/swscale"
)

// ThumbnailParameters configures the thumbnailing process
type ThumbnailParameters struct {
	Width          int     // Target width
	Height         int     // Target height
	Upscale        bool    // Whether to upscale images that are smaller than the target
	ForceAspect    bool    // Whether the source aspect ratio should be preserved
	Quality        int     // JPEG quality (0-99)
	Optimize       bool    // Whether to optimize the JPEG huffman tables
	PrescaleFactor float64 // Controls whether optimized JPEG prescaling is used and how much.
}

// MakeThumbnail makes a thumbnail of a JPEG stream at src and writes it to dst.
func MakeThumbnail(src io.Reader, dst io.Writer, params ThumbnailParameters) error {
	var dparams jpeg.DecompressionParameters
	if params.PrescaleFactor > 0 {
		dparams.TargetWidth = int(math.Ceil(float64(params.Width) * params.PrescaleFactor))
		dparams.TargetHeight = int(math.Ceil(float64(params.Height) * params.PrescaleFactor))
	}
	img, err := jpeg.ReadJPEG(src, dparams)
	if err != nil {
		return err
	}
	//fmt.Printf("%dx%d\n", img.Width, img.Height);

	if !params.Upscale && !params.ForceAspect &&
		img.Width < params.Width && img.Height < params.Height {
		params.Width = img.Width
		params.Height = img.Height
	}

	if img.Width != params.Width || img.Height != params.Height ||
		(img.Format != jpeg.YUV444 && img.Format != jpeg.Grayscale) {

		var opts swscale.ScaleOptions
		opts.DstWidth = params.Width
		opts.DstHeight = params.Height
		if !params.ForceAspect {
			if opts.DstWidth > params.Height*img.Width/img.Height {
				opts.DstWidth = int(float64(params.Height*img.Width)/float64(img.Height) + 0.5)
			} else if opts.DstHeight > params.Width*img.Height/img.Width {
				opts.DstHeight = int(float64(params.Width*img.Height)/float64(img.Width) + 0.5)
			}
		}
		opts.Filter = swscale.Lanczos
		img, err = swscale.Scale(img, opts)
		if err != nil {
			return err
		}
	}

	//fmt.Printf("%dx%d\n", img.Width, img.Height);

	var cparams jpeg.CompressionParameters

	cparams.Optimize = params.Optimize
	cparams.Quality = params.Quality

	return jpeg.WriteJPEG(img, dst, cparams)
}
<commit_msg>Make sure the output size is always greater than 0<commit_after>// Package thumbnail provides a simple interface to thumbnail a JPEG stream and
// return the thumbnailed version.
package thumbnail

import (
	"io"
	"math"

	"github.com/pixiv/go-thumber/jpeg"
	"github.com/pixiv/go-thumber/swscale"
)

// ThumbnailParameters configures the thumbnailing process
type ThumbnailParameters struct {
	Width          int     // Target width
	Height         int     // Target height
	Upscale        bool    // Whether to upscale images that are smaller than the target
	ForceAspect    bool    // Whether the source aspect ratio should be preserved
	Quality        int     // JPEG quality (0-99)
	Optimize       bool    // Whether to optimize the JPEG huffman tables
	PrescaleFactor float64 // Controls whether optimized JPEG prescaling is used and how much.
}

// MakeThumbnail makes a thumbnail of a JPEG stream at src and writes it to dst.
func MakeThumbnail(src io.Reader, dst io.Writer, params ThumbnailParameters) error {
	var dparams jpeg.DecompressionParameters
	if params.PrescaleFactor > 0 {
		dparams.TargetWidth = int(math.Ceil(float64(params.Width) * params.PrescaleFactor))
		dparams.TargetHeight = int(math.Ceil(float64(params.Height) * params.PrescaleFactor))
	}
	img, err := jpeg.ReadJPEG(src, dparams)
	if err != nil {
		return err
	}
	//fmt.Printf("%dx%d\n", img.Width, img.Height);

	if !params.Upscale && !params.ForceAspect &&
		img.Width < params.Width && img.Height < params.Height {
		params.Width = img.Width
		params.Height = img.Height
	}

	if img.Width != params.Width || img.Height != params.Height ||
		(img.Format != jpeg.YUV444 && img.Format != jpeg.Grayscale) {

		var opts swscale.ScaleOptions
		opts.DstWidth = params.Width
		opts.DstHeight = params.Height
		if !params.ForceAspect {
			if opts.DstWidth > params.Height*img.Width/img.Height {
				opts.DstWidth = int(float64(params.Height*img.Width)/float64(img.Height) + 0.5)
				if opts.DstWidth <= 0 {
					opts.DstWidth = 1
				}
			} else if opts.DstHeight > params.Width*img.Height/img.Width {
				opts.DstHeight = int(float64(params.Width*img.Height)/float64(img.Width) + 0.5)
				if opts.DstHeight <= 0 {
					opts.DstHeight = 1
				}
			}
		}
		opts.Filter = swscale.Lanczos
		img, err = swscale.Scale(img, opts)
		if err != nil {
			return err
		}
	}

	//fmt.Printf("%dx%d\n", img.Width, img.Height);

	var cparams jpeg.CompressionParameters

	cparams.Optimize = params.Optimize
	cparams.Quality = params.Quality

	return jpeg.WriteJPEG(img, dst, cparams)
}
<|endoftext|>


<commit_before>package telegram

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

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/scbizu/Astral/internal/plugin/hub"
	"github.com/scbizu/Astral/pkg/getcert"
	"github.com/scbizu/Astral/pkg/talker"
	"github.com/scbizu/Astral/pkg/talker/dce"
	"github.com/sirupsen/logrus"
)

type Bot struct {
	bot         *tgbotapi.BotAPI
	isDebugMode bool
}

func NewBot(isDebugMode bool) (*Bot, error) {
	bot := new(Bot)
	tgConn, err := ConnectTG()
	if err != nil {
		return nil, err
	}
	bot.bot = tgConn
	if isDebugMode {
		logrus.SetLevel(logrus.DebugLevel)
		bot.isDebugMode = true
		tgConn.Debug = true
		logrus.Infof("bot auth passed as %s", tgConn.Self.UserName)
	}
	return bot, nil
}

func listenWebhook() {
	port := fmt.Sprintf(":%s", os.Getenv("LISTENPORT"))
	http.ListenAndServe(port, nil)
}

func (b *Bot) ServeBotUpdateMessage() error {
	go listenWebhook()
	b.bot.RemoveWebhook()
	cert := getcert.NewDomainCert(tgAPIDomain)
	domainWithToken := fmt.Sprintf("%s%s", cert.GetDomain(), token)
	if _, err := b.bot.SetWebhook(tgbotapi.NewWebhook(domainWithToken)); err != nil {
		logrus.Errorf("notify webhook failed:%s", err.Error())
		return err
	}
	if b.isDebugMode {
		logrus.SetLevel(logrus.DebugLevel)
		info, err := b.bot.GetWebhookInfo()
		if err != nil {
			return err
		}
		logrus.Debug(info.LastErrorMessage, info.LastErrorDate)
	}
	pattern := fmt.Sprintf("/%s", token)
	if b.isDebugMode {
		logrus.Debugf("token: %s", token)
	}
	updatesMsgChannel := b.bot.ListenForWebhook(pattern)

	logrus.Debugf("msg in channel:%d", len(updatesMsgChannel))
	for update := range updatesMsgChannel {
		logrus.Debugf("[raw msg]:%#v\n", update)

		if update.Message == nil {
			continue
		}
		pluginHub := hub.NewTGPluginHub(update.Message)
		msg := pluginHub.RegistTGEnabledPlugins(update.Message)
		if isMsgBadRequest(msg) {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, "Astral服务酱表示不想理你")
		}

		mbNames, ok := isMsgNewMember(update)
		if ok {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("撒花欢迎新基佬(%v)入群", mbNames))
		}

		_, ok = isMsgLeftMember(update)
		if ok {
			// drop the member left message
			continue
		}

		msg.ReplyToMessageID = update.Message.MessageID
		b.bot.Send(msg)
	}
	return nil
}

func (b *Bot) ServePushAstralServerMessage() {
	go healthCheck(b.bot)
	registerDCEServer(b.bot)
}

func isMsgNewMember(update tgbotapi.Update) ([]string, bool) {
	members := update.Message.NewChatMembers
	if members == nil {
		return nil, false
	}
	if len(*members) == 0 {
		return nil, false
	}
	var mbNames []string
	for _, m := range *members {
		mbNames = append(mbNames, m.String())
	}
	return mbNames, true
}

func isMsgLeftMember(update tgbotapi.Update) (string, bool) {
	if update.Message.LeftChatMember == nil {
		return "", false
	}
	mbName := update.Message.LeftChatMember.String()
	return mbName, true
}

func isMsgBadRequest(msg tgbotapi.MessageConfig) bool {
	if msg.Text == "" || msg.ChatID == 0 {
		return true
	}
	return false
}

func registerDCEServer(bot *tgbotapi.BotAPI) {
	dceListenHandler := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			r.ParseForm()
			body, err := ioutil.ReadAll(r.Body)
			if err != nil {
				logrus.Println(err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

			defer r.Body.Close()
			dceObj, err := dce.NewDCEObj(string(body))
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			noti := talker.NewNotifaction(dceObj.GetRepoName(),
				dceObj.GetStageMap(), dceObj.GetCommitMsg(),
				dceObj.GetBuildDuration())
			respMsg, err := bot.Send(noti.Notify())
			if err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(err.Error()))
				return
			}
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(respMsg.Text))
		} else {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("Astral denied your request"))
		}
	}

	http.HandleFunc("/dce", dceListenHandler)

	port := fmt.Sprintf(":%s", os.Getenv("LISTENPORT"))

	http.ListenAndServe(port, nil)
}
<commit_msg>internal/telegram: fix bad domain<commit_after>package telegram

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

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/scbizu/Astral/internal/plugin/hub"
	"github.com/scbizu/Astral/pkg/getcert"
	"github.com/scbizu/Astral/pkg/talker"
	"github.com/scbizu/Astral/pkg/talker/dce"
	"github.com/sirupsen/logrus"
)

type Bot struct {
	bot         *tgbotapi.BotAPI
	isDebugMode bool
}

func NewBot(isDebugMode bool) (*Bot, error) {
	bot := new(Bot)
	tgConn, err := ConnectTG()
	if err != nil {
		return nil, err
	}
	bot.bot = tgConn
	if isDebugMode {
		logrus.SetLevel(logrus.DebugLevel)
		bot.isDebugMode = true
		tgConn.Debug = true
		logrus.Infof("bot auth passed as %s", tgConn.Self.UserName)
	}
	return bot, nil
}

func listenWebhook() {
	port := fmt.Sprintf(":%s", os.Getenv("LISTENPORT"))
	http.ListenAndServe(port, nil)
}

func (b *Bot) ServeBotUpdateMessage() error {
	go listenWebhook()
	b.bot.RemoveWebhook()
	cert := getcert.NewDomainCert(tgAPIDomain)
	domainWithToken := fmt.Sprintf("%s/%s", cert.GetDomain(), token)
	if _, err := b.bot.SetWebhook(tgbotapi.NewWebhook(domainWithToken)); err != nil {
		logrus.Errorf("notify webhook failed:%s", err.Error())
		return err
	}
	if b.isDebugMode {
		logrus.SetLevel(logrus.DebugLevel)
		info, err := b.bot.GetWebhookInfo()
		if err != nil {
			return err
		}
		logrus.Debug(info.LastErrorMessage, info.LastErrorDate)
	}
	pattern := fmt.Sprintf("/%s", token)
	if b.isDebugMode {
		logrus.Debugf("token: %s", token)
	}
	updatesMsgChannel := b.bot.ListenForWebhook(pattern)

	logrus.Debugf("msg in channel:%d", len(updatesMsgChannel))
	for update := range updatesMsgChannel {
		logrus.Debugf("[raw msg]:%#v\n", update)

		if update.Message == nil {
			continue
		}
		pluginHub := hub.NewTGPluginHub(update.Message)
		msg := pluginHub.RegistTGEnabledPlugins(update.Message)
		if isMsgBadRequest(msg) {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, "Astral服务酱表示不想理你")
		}

		mbNames, ok := isMsgNewMember(update)
		if ok {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("撒花欢迎新基佬(%v)入群", mbNames))
		}

		_, ok = isMsgLeftMember(update)
		if ok {
			// drop the member left message
			continue
		}

		msg.ReplyToMessageID = update.Message.MessageID
		b.bot.Send(msg)
	}
	return nil
}

func (b *Bot) ServePushAstralServerMessage() {
	go healthCheck(b.bot)
	registerDCEServer(b.bot)
}

func isMsgNewMember(update tgbotapi.Update) ([]string, bool) {
	members := update.Message.NewChatMembers
	if members == nil {
		return nil, false
	}
	if len(*members) == 0 {
		return nil, false
	}
	var mbNames []string
	for _, m := range *members {
		mbNames = append(mbNames, m.String())
	}
	return mbNames, true
}

func isMsgLeftMember(update tgbotapi.Update) (string, bool) {
	if update.Message.LeftChatMember == nil {
		return "", false
	}
	mbName := update.Message.LeftChatMember.String()
	return mbName, true
}

func isMsgBadRequest(msg tgbotapi.MessageConfig) bool {
	if msg.Text == "" || msg.ChatID == 0 {
		return true
	}
	return false
}

func registerDCEServer(bot *tgbotapi.BotAPI) {
	dceListenHandler := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			r.ParseForm()
			body, err := ioutil.ReadAll(r.Body)
			if err != nil {
				logrus.Println(err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

			defer r.Body.Close()
			dceObj, err := dce.NewDCEObj(string(body))
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			noti := talker.NewNotifaction(dceObj.GetRepoName(),
				dceObj.GetStageMap(), dceObj.GetCommitMsg(),
				dceObj.GetBuildDuration())
			respMsg, err := bot.Send(noti.Notify())
			if err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(err.Error()))
				return
			}
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(respMsg.Text))
		} else {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("Astral denied your request"))
		}
	}

	http.HandleFunc("/dce", dceListenHandler)

	port := fmt.Sprintf(":%s", os.Getenv("LISTENPORT"))

	http.ListenAndServe(port, nil)
}
<|endoftext|>


<commit_before>package ipfailover

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/spf13/cobra"

	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/errors"
	kclient "k8s.io/kubernetes/pkg/client/unversioned"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/runtime"

	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	"github.com/openshift/origin/pkg/cmd/util/variable"
	configcmd "github.com/openshift/origin/pkg/config/cmd"
	"github.com/openshift/origin/pkg/ipfailover"
	"github.com/openshift/origin/pkg/ipfailover/keepalived"
)

const (
	ipFailover_long = `Configure or view IP Failover configuration

This command helps to setup an IP failover configuration for the
cluster. An administrator can configure IP failover on an entire
cluster or on a subset of nodes (as defined via a labeled selector).

If an IP failover configuration does not exist with the given name,
the --create flag can be passed to create a deployment configuration that
will provide IP failover capability. If you are running in production, it is
recommended that the labeled selector for the nodes matches at least 2 nodes
to ensure you have failover protection, and that you provide a --replicas=<n>
value that matches the number of nodes for the given labeled selector.`

	ipFailover_example = `  # Check the default IP failover configuration ("ipfailover"):
  %[1]s %[2]s

  # See what the IP failover configuration would look like if it is created:
  %[1]s %[2]s -o json

  # Create an IP failover configuration if it does not already exist:
  %[1]s %[2]s ipf --virtual-ips="10.1.1.1-4" --create

  # Create an IP failover configuration on a selection of nodes labeled
  # "router=us-west-ha" (on 4 nodes with 7 virtual IPs monitoring a service
  # listening on port 80, such as the router process).
  %[1]s %[2]s ipfailover --selector="router=us-west-ha" --virtual-ips="1.2.3.4,10.1.1.100-104,5.6.7.8" --watch-port=80 --replicas=4 --create

  # Use a different IP failover config image and see the configuration:
  %[1]s %[2]s ipf-alt --selector="hagroup=us-west-ha" --virtual-ips="1.2.3.4" -o yaml --images=myrepo/myipfailover:mytag`
)

func NewCmdIPFailoverConfig(f *clientcmd.Factory, parentName, name string, out, errout io.Writer) *cobra.Command {
	options := &ipfailover.IPFailoverConfigCmdOptions{
		Action: configcmd.BulkAction{
			Out:    out,
			ErrOut: errout,
		},
		ImageTemplate:    variable.NewDefaultImageTemplate(),
		ServiceAccount:   "ipfailover",
		Selector:         ipfailover.DefaultSelector,
		ServicePort:      ipfailover.DefaultServicePort,
		WatchPort:        ipfailover.DefaultWatchPort,
		NetworkInterface: ipfailover.DefaultInterface,
		VRRPIDOffset:     0,
		Replicas:         1,
	}

	cmd := &cobra.Command{
		Use:     fmt.Sprintf("%s [NAME]", name),
		Short:   "Install an IP failover group to a set of nodes",
		Long:    ipFailover_long,
		Example: fmt.Sprintf(ipFailover_example, parentName, name),
		Run: func(cmd *cobra.Command, args []string) {
			err := Run(f, options, cmd, args)
			if err == cmdutil.ErrExit {
				os.Exit(1)
			}
			kcmdutil.CheckErr(err)
		},
	}

	cmd.Flags().StringVar(&options.Type, "type", ipfailover.DefaultType, "The type of IP failover configurator to use.")
	cmd.Flags().StringVar(&options.ImageTemplate.Format, "images", options.ImageTemplate.Format, "The image to base this IP failover configurator on - ${component} will be replaced based on --type.")
	cmd.Flags().BoolVar(&options.ImageTemplate.Latest, "latest-images", options.ImageTemplate.Latest, "If true, attempt to use the latest images instead of the current release")
	cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter nodes on.")
	cmd.Flags().StringVar(&options.Credentials, "credentials", "", "Path to a .kubeconfig file that will contain the credentials the router should use to contact the master.")
	cmd.Flags().StringVar(&options.ServiceAccount, "service-account", options.ServiceAccount, "Name of the service account to use to run the ipfailover pod.")

	cmd.Flags().BoolVar(&options.Create, "create", options.Create, "Create the configuration if it does not exist.")

	cmd.Flags().StringVar(&options.VirtualIPs, "virtual-ips", "", "A set of virtual IP ranges and/or addresses that the routers bind and serve on and provide IP failover capability for.")
	cmd.Flags().StringVarP(&options.NetworkInterface, "interface", "i", "", "Network interface bound by VRRP to use for the set of virtual IP ranges/addresses specified.")

	cmd.Flags().IntVarP(&options.WatchPort, "watch-port", "w", ipfailover.DefaultWatchPort, "Port to monitor or watch for resource availability.")
	cmd.Flags().IntVar(&options.VRRPIDOffset, "vrrp-id-offset", options.VRRPIDOffset, "Offset to use for setting ids of VRRP instances (default offset is 0). This allows multiple ipfailover instances to run within the same cluster.")
	cmd.Flags().Int32VarP(&options.Replicas, "replicas", "r", options.Replicas, "The replication factor of this IP failover configuration; commonly 2 when high availability is desired. Please ensure this matches the number of nodes that satisfy the selector (or default selector) specified.")

	// autocompletion hints
	cmd.MarkFlagFilename("credentials", "kubeconfig")
	cmd.Flags().MarkDeprecated("credentials", "use --service-account to specify the service account the ipfailover pod will use to make API calls")

	options.Action.BindForOutput(cmd.Flags())
	cmd.Flags().String("output-version", "", "The preferred API versions of the output objects")

	return cmd
}

//  Get configuration name - argv[1].
func getConfigurationName(args []string) (string, error) {
	name := ipfailover.DefaultName

	switch len(args) {
	case 0:
		// Do nothing - use default name.
	case 1:
		name = args[0]
	default:
		return "", fmt.Errorf("Please pass zero or one arguments to provide a name for this configuration.")
	}

	return name, nil
}

//  Get the configurator based on the ipfailover type.
func getPlugin(name string, f *clientcmd.Factory, options *ipfailover.IPFailoverConfigCmdOptions) (ipfailover.IPFailoverConfiguratorPlugin, error) {
	//  Currently, the only supported plugin is keepalived (default).
	plugin, err := keepalived.NewIPFailoverConfiguratorPlugin(name, f, options)

	switch options.Type {
	case ipfailover.DefaultType:
		//  Default.
	// case <new-type>:  plugin, err = makeNewTypePlugin()
	default:
		return nil, fmt.Errorf("No plugins available to handle type %q", options.Type)
	}

	if err != nil {
		return nil, fmt.Errorf("IPFailoverConfigurator %q plugin error: %v", options.Type, err)
	}

	return plugin, nil
}

// Run runs the ipfailover command.
func Run(f *clientcmd.Factory, options *ipfailover.IPFailoverConfigCmdOptions, cmd *cobra.Command, args []string) error {
	name, err := getConfigurationName(args)
	if err != nil {
		return err
	}

	if len(options.ServiceAccount) == 0 {
		return fmt.Errorf("you must specify a service account for the ipfailover pod with --service-account, it cannot be blank")
	}

	options.Action.Bulk.Mapper = clientcmd.ResourceMapper(f)
	options.Action.Bulk.Op = configcmd.Create

	if err := ipfailover.ValidateCmdOptions(options); err != nil {
		return err
	}

	p, err := getPlugin(name, f, options)
	if err != nil {
		return err
	}

	list, err := p.Generate()
	if err != nil {
		return err
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	_, kClient, err := f.Clients()
	if err != nil {
		return fmt.Errorf("error getting client: %v", err)
	}
	if err := validateServiceAccount(kClient, namespace, options.ServiceAccount); err != nil {
		return fmt.Errorf("ipfailover could not be created; %v", err)
	}

	configList := []runtime.Object{
		&kapi.ServiceAccount{ObjectMeta: kapi.ObjectMeta{Name: options.ServiceAccount}},
	}

	list.Items = append(configList, list.Items...)

	if options.Action.ShouldPrint() {
		mapper, _ := f.Object(false)
		return cmdutil.VersionedPrintObject(f.PrintObject, cmd, mapper, options.Action.Out)(list)
	}

	if errs := options.Action.WithMessage(fmt.Sprintf("Creating IP failover %s", name), "created").Run(list, namespace); len(errs) > 0 {
		return cmdutil.ErrExit
	}
	return nil
}

func validateServiceAccount(client *kclient.Client, ns string, serviceAccount string) error {

	sccList, err := client.SecurityContextConstraints().List(kapi.ListOptions{})
	if err != nil {
		if !errors.IsUnauthorized(err) {
			return fmt.Errorf("could not retrieve list of security constraints to verify service account %q: %v", serviceAccount, err)
		}
	}

	for _, scc := range sccList.Items {
		if scc.AllowPrivilegedContainer {
			for _, user := range scc.Users {
				if strings.Contains(user, serviceAccount) {
					return nil
				}
			}
		}
	}
	errMsg := "service account %q does not have sufficient privileges, grant access with oadm policy add-scc-to-user %s -z %s"
	return fmt.Errorf(errMsg, serviceAccount, bootstrappolicy.SecurityContextConstraintPrivileged, serviceAccount)
}
<commit_msg>refactor the function 'getPlugin' in the 'pkg/cmd/experimental/ipfailover/ipfailover.go'<commit_after>package ipfailover

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/spf13/cobra"

	kapi "k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/errors"
	kclient "k8s.io/kubernetes/pkg/client/unversioned"
	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
	"k8s.io/kubernetes/pkg/runtime"

	"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
	cmdutil "github.com/openshift/origin/pkg/cmd/util"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	"github.com/openshift/origin/pkg/cmd/util/variable"
	configcmd "github.com/openshift/origin/pkg/config/cmd"
	"github.com/openshift/origin/pkg/ipfailover"
	"github.com/openshift/origin/pkg/ipfailover/keepalived"
)

const (
	ipFailover_long = `Configure or view IP Failover configuration

This command helps to setup an IP failover configuration for the
cluster. An administrator can configure IP failover on an entire
cluster or on a subset of nodes (as defined via a labeled selector).

If an IP failover configuration does not exist with the given name,
the --create flag can be passed to create a deployment configuration that
will provide IP failover capability. If you are running in production, it is
recommended that the labeled selector for the nodes matches at least 2 nodes
to ensure you have failover protection, and that you provide a --replicas=<n>
value that matches the number of nodes for the given labeled selector.`

	ipFailover_example = `  # Check the default IP failover configuration ("ipfailover"):
  %[1]s %[2]s

  # See what the IP failover configuration would look like if it is created:
  %[1]s %[2]s -o json

  # Create an IP failover configuration if it does not already exist:
  %[1]s %[2]s ipf --virtual-ips="10.1.1.1-4" --create

  # Create an IP failover configuration on a selection of nodes labeled
  # "router=us-west-ha" (on 4 nodes with 7 virtual IPs monitoring a service
  # listening on port 80, such as the router process).
  %[1]s %[2]s ipfailover --selector="router=us-west-ha" --virtual-ips="1.2.3.4,10.1.1.100-104,5.6.7.8" --watch-port=80 --replicas=4 --create

  # Use a different IP failover config image and see the configuration:
  %[1]s %[2]s ipf-alt --selector="hagroup=us-west-ha" --virtual-ips="1.2.3.4" -o yaml --images=myrepo/myipfailover:mytag`
)

func NewCmdIPFailoverConfig(f *clientcmd.Factory, parentName, name string, out, errout io.Writer) *cobra.Command {
	options := &ipfailover.IPFailoverConfigCmdOptions{
		Action: configcmd.BulkAction{
			Out:    out,
			ErrOut: errout,
		},
		ImageTemplate:    variable.NewDefaultImageTemplate(),
		ServiceAccount:   "ipfailover",
		Selector:         ipfailover.DefaultSelector,
		ServicePort:      ipfailover.DefaultServicePort,
		WatchPort:        ipfailover.DefaultWatchPort,
		NetworkInterface: ipfailover.DefaultInterface,
		VRRPIDOffset:     0,
		Replicas:         1,
	}

	cmd := &cobra.Command{
		Use:     fmt.Sprintf("%s [NAME]", name),
		Short:   "Install an IP failover group to a set of nodes",
		Long:    ipFailover_long,
		Example: fmt.Sprintf(ipFailover_example, parentName, name),
		Run: func(cmd *cobra.Command, args []string) {
			err := Run(f, options, cmd, args)
			if err == cmdutil.ErrExit {
				os.Exit(1)
			}
			kcmdutil.CheckErr(err)
		},
	}

	cmd.Flags().StringVar(&options.Type, "type", ipfailover.DefaultType, "The type of IP failover configurator to use.")
	cmd.Flags().StringVar(&options.ImageTemplate.Format, "images", options.ImageTemplate.Format, "The image to base this IP failover configurator on - ${component} will be replaced based on --type.")
	cmd.Flags().BoolVar(&options.ImageTemplate.Latest, "latest-images", options.ImageTemplate.Latest, "If true, attempt to use the latest images instead of the current release")
	cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter nodes on.")
	cmd.Flags().StringVar(&options.Credentials, "credentials", "", "Path to a .kubeconfig file that will contain the credentials the router should use to contact the master.")
	cmd.Flags().StringVar(&options.ServiceAccount, "service-account", options.ServiceAccount, "Name of the service account to use to run the ipfailover pod.")

	cmd.Flags().BoolVar(&options.Create, "create", options.Create, "Create the configuration if it does not exist.")

	cmd.Flags().StringVar(&options.VirtualIPs, "virtual-ips", "", "A set of virtual IP ranges and/or addresses that the routers bind and serve on and provide IP failover capability for.")
	cmd.Flags().StringVarP(&options.NetworkInterface, "interface", "i", "", "Network interface bound by VRRP to use for the set of virtual IP ranges/addresses specified.")

	cmd.Flags().IntVarP(&options.WatchPort, "watch-port", "w", ipfailover.DefaultWatchPort, "Port to monitor or watch for resource availability.")
	cmd.Flags().IntVar(&options.VRRPIDOffset, "vrrp-id-offset", options.VRRPIDOffset, "Offset to use for setting ids of VRRP instances (default offset is 0). This allows multiple ipfailover instances to run within the same cluster.")
	cmd.Flags().Int32VarP(&options.Replicas, "replicas", "r", options.Replicas, "The replication factor of this IP failover configuration; commonly 2 when high availability is desired. Please ensure this matches the number of nodes that satisfy the selector (or default selector) specified.")

	// autocompletion hints
	cmd.MarkFlagFilename("credentials", "kubeconfig")
	cmd.Flags().MarkDeprecated("credentials", "use --service-account to specify the service account the ipfailover pod will use to make API calls")

	options.Action.BindForOutput(cmd.Flags())
	cmd.Flags().String("output-version", "", "The preferred API versions of the output objects")

	return cmd
}

//  Get configuration name - argv[1].
func getConfigurationName(args []string) (string, error) {
	name := ipfailover.DefaultName

	switch len(args) {
	case 0:
		// Do nothing - use default name.
	case 1:
		name = args[0]
	default:
		return "", fmt.Errorf("Please pass zero or one arguments to provide a name for this configuration.")
	}

	return name, nil
}

//  Get the configurator based on the ipfailover type.
func getPlugin(name string, f *clientcmd.Factory, options *ipfailover.IPFailoverConfigCmdOptions) (ipfailover.IPFailoverConfiguratorPlugin, error) {
	if options.Type == ipfailover.DefaultType {
		plugin, err := keepalived.NewIPFailoverConfiguratorPlugin(name, f, options)
		if err != nil {
			return nil, fmt.Errorf("IPFailoverConfigurator %q plugin error: %v", options.Type, err)
		}

		return plugin, nil
	}

	return nil, fmt.Errorf("No plugins available to handle type %q", options.Type)
}

// Run runs the ipfailover command.
func Run(f *clientcmd.Factory, options *ipfailover.IPFailoverConfigCmdOptions, cmd *cobra.Command, args []string) error {
	name, err := getConfigurationName(args)
	if err != nil {
		return err
	}

	if len(options.ServiceAccount) == 0 {
		return fmt.Errorf("you must specify a service account for the ipfailover pod with --service-account, it cannot be blank")
	}

	options.Action.Bulk.Mapper = clientcmd.ResourceMapper(f)
	options.Action.Bulk.Op = configcmd.Create

	if err := ipfailover.ValidateCmdOptions(options); err != nil {
		return err
	}

	p, err := getPlugin(name, f, options)
	if err != nil {
		return err
	}

	list, err := p.Generate()
	if err != nil {
		return err
	}

	namespace, _, err := f.DefaultNamespace()
	if err != nil {
		return err
	}
	_, kClient, err := f.Clients()
	if err != nil {
		return fmt.Errorf("error getting client: %v", err)
	}
	if err := validateServiceAccount(kClient, namespace, options.ServiceAccount); err != nil {
		return fmt.Errorf("ipfailover could not be created; %v", err)
	}

	configList := []runtime.Object{
		&kapi.ServiceAccount{ObjectMeta: kapi.ObjectMeta{Name: options.ServiceAccount}},
	}

	list.Items = append(configList, list.Items...)

	if options.Action.ShouldPrint() {
		mapper, _ := f.Object(false)
		return cmdutil.VersionedPrintObject(f.PrintObject, cmd, mapper, options.Action.Out)(list)
	}

	if errs := options.Action.WithMessage(fmt.Sprintf("Creating IP failover %s", name), "created").Run(list, namespace); len(errs) > 0 {
		return cmdutil.ErrExit
	}
	return nil
}

func validateServiceAccount(client *kclient.Client, ns string, serviceAccount string) error {

	sccList, err := client.SecurityContextConstraints().List(kapi.ListOptions{})
	if err != nil {
		if !errors.IsUnauthorized(err) {
			return fmt.Errorf("could not retrieve list of security constraints to verify service account %q: %v", serviceAccount, err)
		}
	}

	for _, scc := range sccList.Items {
		if scc.AllowPrivilegedContainer {
			for _, user := range scc.Users {
				if strings.Contains(user, serviceAccount) {
					return nil
				}
			}
		}
	}
	errMsg := "service account %q does not have sufficient privileges, grant access with oadm policy add-scc-to-user %s -z %s"
	return fmt.Errorf(errMsg, serviceAccount, bootstrappolicy.SecurityContextConstraintPrivileged, serviceAccount)
}
<|endoftext|>