<commit_before>package http

import (
	"bufio"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"

	"v2ray.com/core/app"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/log"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/errors"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/transport/internet"
)

// Server is a HTTP proxy server.
type Server struct {
	config *ServerConfig
}

// NewServer creates a new HTTP inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
	space := app.SpaceFromContext(ctx)
	if space == nil {
		return nil, newError("no space in context.")
	}
	s := &Server{
		config: config,
	}
	return s, nil
}

func (*Server) Network() net.NetworkList {
	return net.NetworkList{
		Network: []net.Network{net.Network_TCP},
	}
}

func parseHost(rawHost string, defaultPort net.Port) (net.Destination, error) {
	port := defaultPort
	host, rawPort, err := net.SplitHostPort(rawHost)
	if err != nil {
		if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
			host = rawHost
		} else {
			return net.Destination{}, err
		}
	} else if len(rawPort) > 0 {
		intPort, err := strconv.Atoi(rawPort)
		if err != nil {
			return net.Destination{}, err
		}
		port = net.Port(intPort)
	}

	return net.TCPDestination(net.ParseAddress(host), port), nil
}

func isTimeout(err error) bool {
	nerr, ok := err.(net.Error)
	return ok && nerr.Timeout()
}

func parseBasicAuth(auth string) (username, password string, ok bool) {
	const prefix = "Basic "
	if !strings.HasPrefix(auth, prefix) {
		return
	}
	c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
	if err != nil {
		return
	}
	cs := string(c)
	s := strings.IndexByte(cs, ':')
	if s < 0 {
		return
	}
	return cs[:s], cs[s+1:], true
}

func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error {
	reader := bufio.NewReaderSize(conn, 2048)

Start:
	conn.SetReadDeadline(time.Now().Add(time.Second * 16))

	request, err := http.ReadRequest(reader)
	if err != nil {
		trace := newError("failed to read http request").Base(err)
		if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
			trace.AtWarning()
		}
		return trace
	}

	if len(s.config.Accounts) > 0 {
		user, pass, ok := parseBasicAuth(request.Header.Get("Proxy-Authorization"))
		if !ok || !s.config.HasAccount(user, pass) {
			_, err := conn.Write([]byte("HTTP/1.1 401 UNAUTHORIZED\r\n\r\n"))
			return err
		}
	}

	log.Trace(newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]"))
	conn.SetReadDeadline(time.Time{})

	defaultPort := net.Port(80)
	if strings.ToLower(request.URL.Scheme) == "https" {
		defaultPort = net.Port(443)
	}
	host := request.Host
	if len(host) == 0 {
		host = request.URL.Host
	}
	dest, err := parseHost(host, defaultPort)
	if err != nil {
		return newError("malformed proxy host: ", host).AtWarning().Base(err)
	}
	log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")

	if strings.ToUpper(request.Method) == "CONNECT" {
		return s.handleConnect(ctx, request, reader, conn, dest, dispatcher)
	}

	keepAlive := (strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive")

	err = s.handlePlainHTTP(ctx, request, reader, conn, dest, dispatcher)
	if err == errWaitAnother {
		if keepAlive {
			goto Start
		}
		err = nil
	}

	return err
}

func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	_, err := writer.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
	if err != nil {
		return newError("failed to write back OK response").Base(err)
	}

	timeout := time.Second * time.Duration(s.config.Timeout)
	if timeout == 0 {
		timeout = time.Minute * 5
	}
	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}

	requestDone := signal.ExecuteAsync(func() error {
		defer ray.InboundInput().Close()

		v2reader := buf.NewReader(reader)
		if err := buf.Copy(v2reader, ray.InboundInput(), buf.UpdateActivity(timer)); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		v2writer := buf.NewWriter(writer)
		if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil {
			return err
		}
		timer.SetTimeout(time.Second * 2)
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		ray.InboundInput().CloseError()
		ray.InboundOutput().CloseError()
		return newError("connection ends").Base(err)
	}

	runtime.KeepAlive(timer)

	return nil
}

// @VisibleForTesting
func StripHopByHopHeaders(header http.Header) {
	// Strip hop-by-hop header basaed on RFC:
	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
	// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do

	header.Del("Proxy-Connection")
	header.Del("Proxy-Authenticate")
	header.Del("Proxy-Authorization")
	header.Del("TE")
	header.Del("Trailers")
	header.Del("Transfer-Encoding")
	header.Del("Upgrade")

	connections := header.Get("Connection")
	header.Del("Connection")
	if len(connections) == 0 {
		return
	}
	for _, h := range strings.Split(connections, ",") {
		header.Del(strings.TrimSpace(h))
	}
}

var errWaitAnother = newError("keep alive")

func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	if len(request.URL.Host) <= 0 {
		response := &http.Response{
			Status:        "Bad Request",
			StatusCode:    400,
			Proto:         "HTTP/1.1",
			ProtoMajor:    1,
			ProtoMinor:    1,
			Header:        http.Header(make(map[string][]string)),
			Body:          nil,
			ContentLength: 0,
			Close:         true,
		}
		response.Header.Set("Proxy-Connection", "close")
		response.Header.Set("Connection", "close")
		return response.Write(writer)
	}

	request.Host = request.URL.Host
	StripHopByHopHeaders(request.Header)

	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}
	input := ray.InboundInput()
	output := ray.InboundOutput()
	defer input.Close()

	var result error = errWaitAnother

	requestDone := signal.ExecuteAsync(func() error {
		request.Header.Set("Connection", "close")

		requestWriter := buf.ToBytesWriter(ray.InboundInput())
		if err := request.Write(requestWriter); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		responseReader := bufio.NewReaderSize(buf.ToBytesReader(ray.InboundOutput()), 2048)
		response, err := http.ReadResponse(responseReader, request)
		if err == nil {
			StripHopByHopHeaders(response.Header)
			if response.ContentLength >= 0 {
				response.Header.Set("Proxy-Connection", "keep-alive")
				response.Header.Set("Connection", "keep-alive")
				response.Header.Set("Keep-Alive", "timeout=4")
				response.Close = false
			} else {
				response.Close = true
				result = nil
			}
		} else {
			log.Trace(newError("failed to read response from ", request.Host).Base(err).AtWarning())
			response = &http.Response{
				Status:        "Service Unavailable",
				StatusCode:    503,
				Proto:         "HTTP/1.1",
				ProtoMajor:    1,
				ProtoMinor:    1,
				Header:        http.Header(make(map[string][]string)),
				Body:          nil,
				ContentLength: 0,
				Close:         true,
			}
			response.Header.Set("Connection", "close")
			response.Header.Set("Proxy-Connection", "close")
		}
		if err := response.Write(writer); err != nil {
			return newError("failed to write response").Base(err)
		}
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		input.CloseError()
		output.CloseError()
		return newError("connection ends").Base(err)
	}

	return result
}

func init() {
	common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewServer(ctx, config.(*ServerConfig))
	}))
}
<commit_msg>check request.Host instead of request.URL.Host. fix #681<commit_after>package http

import (
	"bufio"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"

	"v2ray.com/core/app"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/log"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/errors"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/transport/internet"
)

// Server is a HTTP proxy server.
type Server struct {
	config *ServerConfig
}

// NewServer creates a new HTTP inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
	space := app.SpaceFromContext(ctx)
	if space == nil {
		return nil, newError("no space in context.")
	}
	s := &Server{
		config: config,
	}
	return s, nil
}

func (*Server) Network() net.NetworkList {
	return net.NetworkList{
		Network: []net.Network{net.Network_TCP},
	}
}

func parseHost(rawHost string, defaultPort net.Port) (net.Destination, error) {
	port := defaultPort
	host, rawPort, err := net.SplitHostPort(rawHost)
	if err != nil {
		if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
			host = rawHost
		} else {
			return net.Destination{}, err
		}
	} else if len(rawPort) > 0 {
		intPort, err := strconv.Atoi(rawPort)
		if err != nil {
			return net.Destination{}, err
		}
		port = net.Port(intPort)
	}

	return net.TCPDestination(net.ParseAddress(host), port), nil
}

func isTimeout(err error) bool {
	nerr, ok := err.(net.Error)
	return ok && nerr.Timeout()
}

func parseBasicAuth(auth string) (username, password string, ok bool) {
	const prefix = "Basic "
	if !strings.HasPrefix(auth, prefix) {
		return
	}
	c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
	if err != nil {
		return
	}
	cs := string(c)
	s := strings.IndexByte(cs, ':')
	if s < 0 {
		return
	}
	return cs[:s], cs[s+1:], true
}

func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error {
	reader := bufio.NewReaderSize(conn, 2048)

Start:
	conn.SetReadDeadline(time.Now().Add(time.Second * 16))

	request, err := http.ReadRequest(reader)
	if err != nil {
		trace := newError("failed to read http request").Base(err)
		if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
			trace.AtWarning()
		}
		return trace
	}

	if len(s.config.Accounts) > 0 {
		user, pass, ok := parseBasicAuth(request.Header.Get("Proxy-Authorization"))
		if !ok || !s.config.HasAccount(user, pass) {
			_, err := conn.Write([]byte("HTTP/1.1 401 UNAUTHORIZED\r\n\r\n"))
			return err
		}
	}

	log.Trace(newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]"))
	conn.SetReadDeadline(time.Time{})

	defaultPort := net.Port(80)
	if strings.ToLower(request.URL.Scheme) == "https" {
		defaultPort = net.Port(443)
	}
	host := request.Host
	if len(host) == 0 {
		host = request.URL.Host
	}
	dest, err := parseHost(host, defaultPort)
	if err != nil {
		return newError("malformed proxy host: ", host).AtWarning().Base(err)
	}
	log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")

	if strings.ToUpper(request.Method) == "CONNECT" {
		return s.handleConnect(ctx, request, reader, conn, dest, dispatcher)
	}

	keepAlive := (strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive")

	err = s.handlePlainHTTP(ctx, request, reader, conn, dest, dispatcher)
	if err == errWaitAnother {
		if keepAlive {
			goto Start
		}
		err = nil
	}

	return err
}

func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	_, err := writer.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
	if err != nil {
		return newError("failed to write back OK response").Base(err)
	}

	timeout := time.Second * time.Duration(s.config.Timeout)
	if timeout == 0 {
		timeout = time.Minute * 5
	}
	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}

	requestDone := signal.ExecuteAsync(func() error {
		defer ray.InboundInput().Close()

		v2reader := buf.NewReader(reader)
		if err := buf.Copy(v2reader, ray.InboundInput(), buf.UpdateActivity(timer)); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		v2writer := buf.NewWriter(writer)
		if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil {
			return err
		}
		timer.SetTimeout(time.Second * 2)
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		ray.InboundInput().CloseError()
		ray.InboundOutput().CloseError()
		return newError("connection ends").Base(err)
	}

	runtime.KeepAlive(timer)

	return nil
}

// @VisibleForTesting
func StripHopByHopHeaders(header http.Header) {
	// Strip hop-by-hop header basaed on RFC:
	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
	// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do

	header.Del("Proxy-Connection")
	header.Del("Proxy-Authenticate")
	header.Del("Proxy-Authorization")
	header.Del("TE")
	header.Del("Trailers")
	header.Del("Transfer-Encoding")
	header.Del("Upgrade")

	connections := header.Get("Connection")
	header.Del("Connection")
	if len(connections) == 0 {
		return
	}
	for _, h := range strings.Split(connections, ",") {
		header.Del(strings.TrimSpace(h))
	}
}

var errWaitAnother = newError("keep alive")

func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	if len(request.Host) <= 0 {
		response := &http.Response{
			Status:        "Bad Request",
			StatusCode:    400,
			Proto:         "HTTP/1.1",
			ProtoMajor:    1,
			ProtoMinor:    1,
			Header:        http.Header(make(map[string][]string)),
			Body:          nil,
			ContentLength: 0,
			Close:         true,
		}
		response.Header.Set("Proxy-Connection", "close")
		response.Header.Set("Connection", "close")
		return response.Write(writer)
	}

	request.Host = request.URL.Host
	StripHopByHopHeaders(request.Header)

	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}
	input := ray.InboundInput()
	output := ray.InboundOutput()
	defer input.Close()

	var result error = errWaitAnother

	requestDone := signal.ExecuteAsync(func() error {
		request.Header.Set("Connection", "close")

		requestWriter := buf.ToBytesWriter(ray.InboundInput())
		if err := request.Write(requestWriter); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		responseReader := bufio.NewReaderSize(buf.ToBytesReader(ray.InboundOutput()), 2048)
		response, err := http.ReadResponse(responseReader, request)
		if err == nil {
			StripHopByHopHeaders(response.Header)
			if response.ContentLength >= 0 {
				response.Header.Set("Proxy-Connection", "keep-alive")
				response.Header.Set("Connection", "keep-alive")
				response.Header.Set("Keep-Alive", "timeout=4")
				response.Close = false
			} else {
				response.Close = true
				result = nil
			}
		} else {
			log.Trace(newError("failed to read response from ", request.Host).Base(err).AtWarning())
			response = &http.Response{
				Status:        "Service Unavailable",
				StatusCode:    503,
				Proto:         "HTTP/1.1",
				ProtoMajor:    1,
				ProtoMinor:    1,
				Header:        http.Header(make(map[string][]string)),
				Body:          nil,
				ContentLength: 0,
				Close:         true,
			}
			response.Header.Set("Connection", "close")
			response.Header.Set("Proxy-Connection", "close")
		}
		if err := response.Write(writer); err != nil {
			return newError("failed to write response").Base(err)
		}
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		input.CloseError()
		output.CloseError()
		return newError("connection ends").Base(err)
	}

	return result
}

func init() {
	common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewServer(ctx, config.(*ServerConfig))
	}))
}
<|endoftext|>


<commit_before>package drum

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

// config
// number of 'steps' played by an instrument each song
const numSteps = 16

// each track can have multiple `Instrument`s
type Instrument struct {
	instrumentName []byte
	instrumentID   uint8
	steps          []byte
}

// one `Pattern` per `.splice` file
type Pattern struct {
	fileLen       int
	spliceHeader  [6]byte  // 6
	trackSize     int64    // 8
	versionString [32]byte // 32
	tempo         float32  // 4
	instruments   []Instrument
}

func checkError(err error) {
	if err != nil {
		fmt.Println("error: ", err)
	}
}

func (curTrack *Pattern) String() string {
	// create string of specified track information
	// include: specific track information from struct
	// loop instruments in the track and print their steps

	// write to buffer then return as buffer.String(), strings are immutable
	var buffer bytes.Buffer
	// track header;
	// Saved with HW Version: 0.909
	// Tempo: 240
	cleanedVersionString := fmt.Sprintf("%s", curTrack.versionString)
	cleanedVersionString = strings.Trim(cleanedVersionString, "\x00")
	curString := fmt.Sprintf("Saved with HW Version: %s\n", cleanedVersionString)
	//curString = strings.Trim(cleanedVersionString, "\n")

	buffer.WriteString(curString)
	//buffer.WriteString(fmt.Sprintf("Saved with HW Version: %s\n", curString))
	buffer.WriteString(fmt.Sprintf("Tempo: %v\n", curTrack.tempo))

	// print instrument/step info > (99) Maracas	|x-x-|x-x-|x-x-|x-x-|
	for _, instrument := range curTrack.instruments {
		// identification > (0) SubKick
		buffer.WriteString(fmt.Sprintf("(%v) %s\t", instrument.instrumentID, instrument.instrumentName))
		// steps > |x---|----|x---|----|
		for i, step := range instrument.steps {
			if i%4 == 0 {
				buffer.WriteString("|")
			}
			// per spec. exception: print "E" if unknown
			if step == 1 {
				buffer.WriteString("x")
			} else if step == 0 {
				buffer.WriteString("-")
			} else {
				buffer.WriteString("E")
			}
		}
		buffer.WriteString("|\n")
	}
	return buffer.String()
}

func parseTrackToStruct(fileContents []byte) Pattern {
	// parse the given `.splice` files and store
	// relevant information in the struct
	// 1. read in file
	// 2. get file length
	// 3. parse and store relevant parts, subtract size from file length
	//NOTE: Use (for debuging): fmt.Printf("%s\n", hex.Dump(fileContents))

	// track temp vars
	var fileLen int
	var spliceHeader [6]byte   // 6
	var trackSize int64        // 8
	var versionString [32]byte // 32
	var tempo float32          // 4

	// instrument temp vars
	var id uint8
	var nameLength int32

	newTrack := &Pattern{}

	buf := bytes.NewReader(fileContents)
	fileLen = len(fileContents)
	newTrack.trackSize = int64(fileLen)

	// Header: SPLICE
	err := binary.Read(buf, binary.BigEndian, &spliceHeader)
	checkError(err)
	fileLen -= binary.Size(spliceHeader)
	newTrack.spliceHeader = spliceHeader

	// Header: track size is big endian
	err = binary.Read(buf, binary.BigEndian, &trackSize)
	checkError(err)
	fileLen -= binary.Size(trackSize)
	newTrack.trackSize = trackSize

	// Header: version
	err = binary.Read(buf, binary.BigEndian, &versionString)
	checkError(err)
	fileLen -= binary.Size(versionString)
	//versionStringTrimmed := strings.TrimRight(versionString, '\x00')
	newTrack.versionString = versionString

	// Header: tempo
	// NOTE: tempo is little Endian?
	err = binary.Read(buf, binary.LittleEndian, &tempo)
	checkError(err)
	fileLen -= binary.Size(tempo)
	newTrack.tempo = tempo

	// Read in body. id+name + 16 steps
	// TODO: Issue is with pattern 5...
	// TODO: there should be safety checks each step of the way
	for fileLen > 0 {
		curInstrument := Instrument{}
		// ID
		err = binary.Read(buf, binary.BigEndian, &id)
		checkError(err)
		fileLen -= binary.Size(id)
		curInstrument.instrumentID = id

		// Length of instrument name
		err = binary.Read(buf, binary.BigEndian, &nameLength)
		checkError(err)
		if nameLength > 10 {
			// TODO: this is a cheap fix to a larger problem
			break
		}
		fileLen -= binary.Size(nameLength)

		// name of instrument
		nameBuf := make([]byte, nameLength)
		err = binary.Read(buf, binary.LittleEndian, &nameBuf)
		checkError(err)
		fileLen -= binary.Size(nameBuf)
		curInstrument.instrumentName = nameBuf

		// steps
		stepBuf := make([]byte, numSteps)
		err = binary.Read(buf, binary.LittleEndian, &stepBuf)
		checkError(err)
		fileLen -= binary.Size(stepBuf)
		curInstrument.steps = stepBuf
		// add instrument to instruments on track
		newTrack.instruments = append(newTrack.instruments, curInstrument)
	}
	return *newTrack
}

// DecodeFile decodes the drum machine file found at the provided path
// and returns a pointer to a parsed pattern which is the entry point to the
// rest of the data.
func DecodeFile(path string) (*Pattern, error) {
	fileContents, err := ioutil.ReadFile(path)
	checkError(err)

	// decode
	p := &Pattern{}
	*p = parseTrackToStruct(fileContents)

	return p, nil
}
<commit_msg>run golint, improve comments<commit_after>package drum

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

// config
// number of 'steps' played by an instrument each song
const numSteps = 16

// Instrument is a high level representation of a
// single instrument in the pattern
type Instrument struct {
	instrumentName []byte
	instrumentID   uint8
	steps          []byte
}

// Pattern is a high level representation
// of a track pattern contained within a .splice file
type Pattern struct {
	fileLen       int
	spliceHeader  [6]byte  // 6
	trackSize     int64    // 8
	versionString [32]byte // 32
	tempo         float32  // 4
	instruments   []Instrument
}

func checkError(err error) {
	if err != nil {
		fmt.Println("error: ", err)
	}
}

func (curTrack *Pattern) String() string {
	// create string of specified track information
	// include: specific track information from struct
	// loop instruments in the track and print their steps

	// write to buffer then return as buffer.String(), strings are immutable
	var buffer bytes.Buffer
	// track header;
	// Saved with HW Version: 0.909
	// Tempo: 240
	cleanedVersionString := fmt.Sprintf("%s", curTrack.versionString)
	cleanedVersionString = strings.Trim(cleanedVersionString, "\x00")
	curString := fmt.Sprintf("Saved with HW Version: %s\n", cleanedVersionString)
	//curString = strings.Trim(cleanedVersionString, "\n")

	buffer.WriteString(curString)
	//buffer.WriteString(fmt.Sprintf("Saved with HW Version: %s\n", curString))
	buffer.WriteString(fmt.Sprintf("Tempo: %v\n", curTrack.tempo))

	// print instrument/step info > (99) Maracas	|x-x-|x-x-|x-x-|x-x-|
	for _, instrument := range curTrack.instruments {
		// identification > (0) SubKick
		buffer.WriteString(fmt.Sprintf("(%v) %s\t", instrument.instrumentID, instrument.instrumentName))
		// steps > |x---|----|x---|----|
		for i, step := range instrument.steps {
			if i%4 == 0 {
				buffer.WriteString("|")
			}
			// per spec. exception: print "E" if unknown
			if step == 1 {
				buffer.WriteString("x")
			} else if step == 0 {
				buffer.WriteString("-")
			} else {
				buffer.WriteString("E")
			}
		}
		buffer.WriteString("|\n")
	}
	return buffer.String()
}

func parseTrackToStruct(fileContents []byte) Pattern {
	// parse the given `.splice` files and store
	// relevant information in the struct
	// 1. read in file
	// 2. get file length
	// 3. parse and store relevant parts, subtract size from file length
	//NOTE: Use (for debuging): fmt.Printf("%s\n", hex.Dump(fileContents))

	// track temp vars
	var fileLen int
	var spliceHeader [6]byte   // 6
	var trackSize int64        // 8
	var versionString [32]byte // 32
	var tempo float32          // 4

	// instrument temp vars
	var id uint8
	var nameLength int32

	newTrack := &Pattern{}

	buf := bytes.NewReader(fileContents)
	fileLen = len(fileContents)
	newTrack.trackSize = int64(fileLen)

	// Header: SPLICE
	err := binary.Read(buf, binary.BigEndian, &spliceHeader)
	checkError(err)
	fileLen -= binary.Size(spliceHeader)
	newTrack.spliceHeader = spliceHeader

	// Header: track size is big endian
	err = binary.Read(buf, binary.BigEndian, &trackSize)
	checkError(err)
	fileLen -= binary.Size(trackSize)
	newTrack.trackSize = trackSize

	// Header: version
	err = binary.Read(buf, binary.BigEndian, &versionString)
	checkError(err)
	fileLen -= binary.Size(versionString)
	//versionStringTrimmed := strings.TrimRight(versionString, '\x00')
	newTrack.versionString = versionString

	// Header: tempo
	// NOTE: tempo is little Endian?
	err = binary.Read(buf, binary.LittleEndian, &tempo)
	checkError(err)
	fileLen -= binary.Size(tempo)
	newTrack.tempo = tempo

	// Read in body. id+name + 16 steps
	// TODO: Issue is with pattern 5...
	// TODO: there should be safety checks each step of the way
	for fileLen > 0 {
		curInstrument := Instrument{}
		// ID
		err = binary.Read(buf, binary.BigEndian, &id)
		checkError(err)
		fileLen -= binary.Size(id)
		curInstrument.instrumentID = id

		// Length of instrument name
		err = binary.Read(buf, binary.BigEndian, &nameLength)
		checkError(err)
		if nameLength > 10 {
			// TODO: this is a cheap fix to a larger problem
			break
		}
		fileLen -= binary.Size(nameLength)

		// name of instrument
		nameBuf := make([]byte, nameLength)
		err = binary.Read(buf, binary.LittleEndian, &nameBuf)
		checkError(err)
		fileLen -= binary.Size(nameBuf)
		curInstrument.instrumentName = nameBuf

		// steps
		stepBuf := make([]byte, numSteps)
		err = binary.Read(buf, binary.LittleEndian, &stepBuf)
		checkError(err)
		fileLen -= binary.Size(stepBuf)
		curInstrument.steps = stepBuf
		// add instrument to instruments on track
		newTrack.instruments = append(newTrack.instruments, curInstrument)
	}
	return *newTrack
}

// DecodeFile decodes the drum machine file found at the provided path
// and returns a pointer to a parsed pattern which is the entry point to the
// rest of the data.
func DecodeFile(path string) (*Pattern, error) {
	fileContents, err := ioutil.ReadFile(path)
	checkError(err)

	// decode
	p := &Pattern{}
	*p = parseTrackToStruct(fileContents)

	return p, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2020 Tigera, Inc. 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.

// This boilerplate code is based on proxiers in k8s.io/kubernetes/pkg/proxy to
// allow reuse of the rest of the proxy package without change

package proxy

import (
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	discovery "k8s.io/api/discovery/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/selection"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/record"
	k8sp "k8s.io/kubernetes/pkg/proxy"
	"k8s.io/kubernetes/pkg/proxy/apis"
	"k8s.io/kubernetes/pkg/proxy/config"
	"k8s.io/kubernetes/pkg/proxy/healthcheck"
	"k8s.io/kubernetes/pkg/util/async"
)

// Proxy watches for updates of Services and Endpoints, maintains their mapping
// and programs it into the dataplane
type Proxy interface {
	// Stop stops the proxy and waits for its exit
	Stop()
}

// DPSyncerState groups the information passed to the DPSyncer's Apply
type DPSyncerState struct {
	SvcMap       k8sp.ServiceMap
	EpsMap       k8sp.EndpointsMap
	StaleUDPEps  []k8sp.ServiceEndpoint
	StaleUDPSvcs sets.String
}

// DPSyncer is an interface representing the dataplane syncer that applies the
// observed changes to the dataplane
type DPSyncer interface {
	Apply(state DPSyncerState) error
	Stop()
}

type proxy struct {
	initState

	hostname string

	k8s kubernetes.Interface

	epsChanges *k8sp.EndpointChangeTracker
	svcChanges *k8sp.ServiceChangeTracker

	svcMap k8sp.ServiceMap
	epsMap k8sp.EndpointsMap

	endpointSlicesEnabled bool

	dpSyncer DPSyncer
	// executes periodic the dataplane updates
	runner *async.BoundedFrequencyRunner
	// ensures that only one invocation runs at any time
	runnerLck sync.Mutex
	// sets the minimal distance between to sync to avoid overloading the
	// dataplane in case of frequent changes
	minDPSyncPeriod time.Duration

	// how often to fully sync with k8s - 0 is never
	syncPeriod time.Duration

	// event recorder to update node events
	recorder        record.EventRecorder
	svcHealthServer healthcheck.ServiceHealthServer
	healthzServer   healthcheck.ProxierHealthUpdater

	stopCh   chan struct{}
	stopWg   sync.WaitGroup
	stopOnce sync.Once
}

type stoppableRunner interface {
	Run(stopCh <-chan struct{})
}

// New returns a new Proxy for the given k8s interface
func New(k8s kubernetes.Interface, dp DPSyncer, hostname string, opts ...Option) (Proxy, error) {
	if k8s == nil {
		return nil, errors.Errorf("no k8s client")
	}

	if dp == nil {
		return nil, errors.Errorf("no dataplane syncer")
	}

	p := &proxy{
		k8s:      k8s,
		dpSyncer: dp,
		hostname: hostname,
		svcMap:   make(k8sp.ServiceMap),
		epsMap:   make(k8sp.EndpointsMap),

		recorder: new(loggerRecorder),

		minDPSyncPeriod: 30 * time.Second, // XXX revisit the default

		stopCh: make(chan struct{}),
	}

	for _, o := range opts {
		if err := o(p); err != nil {
			return nil, errors.WithMessage(err, "applying option")
		}
	}

	// We need to create the runner first as once we start getting updates, they
	// will kick it
	p.runner = async.NewBoundedFrequencyRunner("dp-sync-runner",
		p.invokeDPSyncer, p.minDPSyncPeriod, time.Hour /* XXX might be infinite? */, 1)

	p.svcHealthServer = healthcheck.NewServiceHealthServer(p.hostname, p.recorder)
	isIPv6 := false
	p.epsChanges = k8sp.NewEndpointChangeTracker(p.hostname,
		nil, // change if you want to provide more ctx
		&isIPv6,
		p.recorder,
		p.endpointSlicesEnabled,
	)
	p.svcChanges = k8sp.NewServiceChangeTracker(nil, &isIPv6, p.recorder)

	noProxyName, err := labels.NewRequirement(apis.LabelServiceProxyName, selection.DoesNotExist, nil)
	if err != nil {
		return nil, errors.Errorf("noProxyName selector: %s", err)
	}

	noHeadlessEndpoints, err := labels.NewRequirement(v1.IsHeadlessService, selection.DoesNotExist, nil)
	if err != nil {
		return nil, errors.Errorf("noHeadlessEndpoints selector: %s", err)
	}

	labelSelector := labels.NewSelector()
	labelSelector = labelSelector.Add(*noProxyName, *noHeadlessEndpoints)

	informerFactory := informers.NewSharedInformerFactoryWithOptions(k8s, p.syncPeriod,
		informers.WithTweakListOptions(func(options *metav1.ListOptions) {
			options.LabelSelector = labelSelector.String()
		}))

	svcConfig := config.NewServiceConfig(
		informerFactory.Core().V1().Services(),
		p.syncPeriod,
	)
	svcConfig.RegisterEventHandler(p)

	var epsRunner stoppableRunner

	if p.endpointSlicesEnabled {
		epsConfig := config.NewEndpointSliceConfig(informerFactory.Discovery().V1beta1().EndpointSlices(), p.syncPeriod)
		epsConfig.RegisterEventHandler(p)
		epsRunner = epsConfig
	} else {
		epsConfig := config.NewEndpointsConfig(informerFactory.Core().V1().Endpoints(), p.syncPeriod)
		epsConfig.RegisterEventHandler(p)
		epsRunner = epsConfig
	}

	p.startRoutine(func() { p.runner.Loop(p.stopCh) })
	p.startRoutine(func() { epsRunner.Run(p.stopCh) })
	p.startRoutine(func() { informerFactory.Start(p.stopCh) })
	p.startRoutine(func() { svcConfig.Run(p.stopCh) })

	return p, nil
}

func (p *proxy) Stop() {
	p.stopOnce.Do(func() {
		p.dpSyncer.Stop()
		close(p.stopCh)
		p.stopWg.Wait()
	})
}

func (p *proxy) startRoutine(f func()) {
	p.stopWg.Add(1)
	go func() {
		defer p.stopWg.Done()
		f()
	}()
}

func (p *proxy) syncDP() {
	p.runner.Run()
}

func (p *proxy) forceSyncDP() {
	p.invokeDPSyncer()
}

func (p *proxy) invokeDPSyncer() {
	if !p.isInitialized() {
		return
	}

	p.runnerLck.Lock()
	defer p.runnerLck.Unlock()

	svcUpdateResult := k8sp.UpdateServiceMap(p.svcMap, p.svcChanges)
	epsUpdateResult := p.epsMap.Update(p.epsChanges)

	staleUDPSvcs := svcUpdateResult.UDPStaleClusterIP

	// merge stale UDP services
	for _, svcPortName := range epsUpdateResult.StaleServiceNames {
		if svcInfo, ok := p.svcMap[svcPortName]; ok && svcInfo != nil && svcInfo.Protocol() == v1.ProtocolUDP {
			log.Infof("Stale %s service %v -> %s",
				strings.ToLower(string(svcInfo.Protocol())), svcPortName, svcInfo.ClusterIP().String())
			staleUDPSvcs.Insert(svcInfo.ClusterIP().String())
			for _, extIP := range svcInfo.ExternalIPStrings() {
				staleUDPSvcs.Insert(extIP)
			}
		}
	}

	if err := p.svcHealthServer.SyncServices(svcUpdateResult.HCServiceNodePorts); err != nil {
		log.WithError(err).Error("Error syncing healthcheck services")
	}
	if err := p.svcHealthServer.SyncEndpoints(epsUpdateResult.HCEndpointsLocalIPSize); err != nil {
		log.WithError(err).Error("Error syncing healthcheck endpoints")
	}
	err := p.dpSyncer.Apply(DPSyncerState{
		SvcMap:       p.svcMap,
		EpsMap:       p.epsMap,
		StaleUDPSvcs: staleUDPSvcs,
	})

	if err != nil {
		log.WithError(err).Errorf("applying changes failed")
		// TODO log the error or panic as the best might be to restart
		// completely to wipe out the loaded bpf maps
	}

	// XXX perhaps in a different thread that runs regularly
	if p.healthzServer != nil {
		p.healthzServer.Updated()
	}
}

func (p *proxy) OnServiceAdd(svc *v1.Service) {
	p.OnServiceUpdate(nil, svc)
}

func (p *proxy) OnServiceUpdate(old, curr *v1.Service) {
	if p.svcChanges.Update(old, curr) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnServiceDelete(svc *v1.Service) {
	p.OnServiceUpdate(svc, nil)
}

func (p *proxy) OnServiceSynced() {
	p.setSvcsSynced()
	p.forceSyncDP()
}

func (p *proxy) OnEndpointsAdd(eps *v1.Endpoints) {
	p.OnEndpointsUpdate(nil, eps)
}

func (p *proxy) OnEndpointsUpdate(old, curr *v1.Endpoints) {
	if p.epsChanges.Update(old, curr) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointsDelete(eps *v1.Endpoints) {
	p.OnEndpointsUpdate(eps, nil)
}

func (p *proxy) OnEndpointsSynced() {
	p.setEpsSynced()
	p.forceSyncDP()
}

func (p *proxy) OnEndpointSliceAdd(eps *discovery.EndpointSlice) {
	if p.epsChanges.EndpointSliceUpdate(eps, false) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointSliceUpdate(_, eps *discovery.EndpointSlice) {
	if p.epsChanges.EndpointSliceUpdate(eps, false) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointSliceDelete(eps *discovery.EndpointSlice) {
	if p.epsChanges.EndpointSliceUpdate(eps, true) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointSlicesSynced() {
	p.setEpsSynced()
	p.forceSyncDP()
}

type initState struct {
	lck        sync.RWMutex
	svcsSynced bool
	epsSynced  bool
}

func (is *initState) isInitialized() bool {
	is.lck.RLock()
	defer is.lck.RUnlock()
	return is.svcsSynced && is.epsSynced
}

func (is *initState) setSvcsSynced() {
	is.lck.Lock()
	defer is.lck.Unlock()
	is.svcsSynced = true
}

func (is *initState) setEpsSynced() {
	is.lck.Lock()
	defer is.lck.Unlock()
	is.epsSynced = true
}

type loggerRecorder struct{}

func (r *loggerRecorder) Event(object runtime.Object, eventtype, reason, message string) {
}

func (r *loggerRecorder) Eventf(object runtime.Object, eventtype, reason,
	messageFmt string, args ...interface{}) {
}

func (r *loggerRecorder) PastEventf(object runtime.Object, timestamp metav1.Time, eventtype,
	reason, messageFmt string, args ...interface{}) {
}

func (r *loggerRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string,
	eventtype, reason, messageFmt string, args ...interface{}) {
}
<commit_msg>bpf/proxy: remove a stale comment<commit_after>// Copyright (c) 2017-2020 Tigera, Inc. 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.

// This boilerplate code is based on proxiers in k8s.io/kubernetes/pkg/proxy to
// allow reuse of the rest of the proxy package without change

package proxy

import (
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
	discovery "k8s.io/api/discovery/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/selection"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/record"
	k8sp "k8s.io/kubernetes/pkg/proxy"
	"k8s.io/kubernetes/pkg/proxy/apis"
	"k8s.io/kubernetes/pkg/proxy/config"
	"k8s.io/kubernetes/pkg/proxy/healthcheck"
	"k8s.io/kubernetes/pkg/util/async"
)

// Proxy watches for updates of Services and Endpoints, maintains their mapping
// and programs it into the dataplane
type Proxy interface {
	// Stop stops the proxy and waits for its exit
	Stop()
}

// DPSyncerState groups the information passed to the DPSyncer's Apply
type DPSyncerState struct {
	SvcMap       k8sp.ServiceMap
	EpsMap       k8sp.EndpointsMap
	StaleUDPEps  []k8sp.ServiceEndpoint
	StaleUDPSvcs sets.String
}

// DPSyncer is an interface representing the dataplane syncer that applies the
// observed changes to the dataplane
type DPSyncer interface {
	Apply(state DPSyncerState) error
	Stop()
}

type proxy struct {
	initState

	hostname string

	k8s kubernetes.Interface

	epsChanges *k8sp.EndpointChangeTracker
	svcChanges *k8sp.ServiceChangeTracker

	svcMap k8sp.ServiceMap
	epsMap k8sp.EndpointsMap

	endpointSlicesEnabled bool

	dpSyncer DPSyncer
	// executes periodic the dataplane updates
	runner *async.BoundedFrequencyRunner
	// ensures that only one invocation runs at any time
	runnerLck sync.Mutex
	// sets the minimal distance between to sync to avoid overloading the
	// dataplane in case of frequent changes
	minDPSyncPeriod time.Duration

	// how often to fully sync with k8s - 0 is never
	syncPeriod time.Duration

	// event recorder to update node events
	recorder        record.EventRecorder
	svcHealthServer healthcheck.ServiceHealthServer
	healthzServer   healthcheck.ProxierHealthUpdater

	stopCh   chan struct{}
	stopWg   sync.WaitGroup
	stopOnce sync.Once
}

type stoppableRunner interface {
	Run(stopCh <-chan struct{})
}

// New returns a new Proxy for the given k8s interface
func New(k8s kubernetes.Interface, dp DPSyncer, hostname string, opts ...Option) (Proxy, error) {
	if k8s == nil {
		return nil, errors.Errorf("no k8s client")
	}

	if dp == nil {
		return nil, errors.Errorf("no dataplane syncer")
	}

	p := &proxy{
		k8s:      k8s,
		dpSyncer: dp,
		hostname: hostname,
		svcMap:   make(k8sp.ServiceMap),
		epsMap:   make(k8sp.EndpointsMap),

		recorder: new(loggerRecorder),

		minDPSyncPeriod: 30 * time.Second, // XXX revisit the default

		stopCh: make(chan struct{}),
	}

	for _, o := range opts {
		if err := o(p); err != nil {
			return nil, errors.WithMessage(err, "applying option")
		}
	}

	// We need to create the runner first as once we start getting updates, they
	// will kick it
	p.runner = async.NewBoundedFrequencyRunner("dp-sync-runner",
		p.invokeDPSyncer, p.minDPSyncPeriod, time.Hour /* XXX might be infinite? */, 1)

	p.svcHealthServer = healthcheck.NewServiceHealthServer(p.hostname, p.recorder)
	isIPv6 := false
	p.epsChanges = k8sp.NewEndpointChangeTracker(p.hostname,
		nil, // change if you want to provide more ctx
		&isIPv6,
		p.recorder,
		p.endpointSlicesEnabled,
	)
	p.svcChanges = k8sp.NewServiceChangeTracker(nil, &isIPv6, p.recorder)

	noProxyName, err := labels.NewRequirement(apis.LabelServiceProxyName, selection.DoesNotExist, nil)
	if err != nil {
		return nil, errors.Errorf("noProxyName selector: %s", err)
	}

	noHeadlessEndpoints, err := labels.NewRequirement(v1.IsHeadlessService, selection.DoesNotExist, nil)
	if err != nil {
		return nil, errors.Errorf("noHeadlessEndpoints selector: %s", err)
	}

	labelSelector := labels.NewSelector()
	labelSelector = labelSelector.Add(*noProxyName, *noHeadlessEndpoints)

	informerFactory := informers.NewSharedInformerFactoryWithOptions(k8s, p.syncPeriod,
		informers.WithTweakListOptions(func(options *metav1.ListOptions) {
			options.LabelSelector = labelSelector.String()
		}))

	svcConfig := config.NewServiceConfig(
		informerFactory.Core().V1().Services(),
		p.syncPeriod,
	)
	svcConfig.RegisterEventHandler(p)

	var epsRunner stoppableRunner

	if p.endpointSlicesEnabled {
		epsConfig := config.NewEndpointSliceConfig(informerFactory.Discovery().V1beta1().EndpointSlices(), p.syncPeriod)
		epsConfig.RegisterEventHandler(p)
		epsRunner = epsConfig
	} else {
		epsConfig := config.NewEndpointsConfig(informerFactory.Core().V1().Endpoints(), p.syncPeriod)
		epsConfig.RegisterEventHandler(p)
		epsRunner = epsConfig
	}

	p.startRoutine(func() { p.runner.Loop(p.stopCh) })
	p.startRoutine(func() { epsRunner.Run(p.stopCh) })
	p.startRoutine(func() { informerFactory.Start(p.stopCh) })
	p.startRoutine(func() { svcConfig.Run(p.stopCh) })

	return p, nil
}

func (p *proxy) Stop() {
	p.stopOnce.Do(func() {
		p.dpSyncer.Stop()
		close(p.stopCh)
		p.stopWg.Wait()
	})
}

func (p *proxy) startRoutine(f func()) {
	p.stopWg.Add(1)
	go func() {
		defer p.stopWg.Done()
		f()
	}()
}

func (p *proxy) syncDP() {
	p.runner.Run()
}

func (p *proxy) forceSyncDP() {
	p.invokeDPSyncer()
}

func (p *proxy) invokeDPSyncer() {
	if !p.isInitialized() {
		return
	}

	p.runnerLck.Lock()
	defer p.runnerLck.Unlock()

	svcUpdateResult := k8sp.UpdateServiceMap(p.svcMap, p.svcChanges)
	epsUpdateResult := p.epsMap.Update(p.epsChanges)

	staleUDPSvcs := svcUpdateResult.UDPStaleClusterIP

	// merge stale UDP services
	for _, svcPortName := range epsUpdateResult.StaleServiceNames {
		if svcInfo, ok := p.svcMap[svcPortName]; ok && svcInfo != nil && svcInfo.Protocol() == v1.ProtocolUDP {
			log.Infof("Stale %s service %v -> %s",
				strings.ToLower(string(svcInfo.Protocol())), svcPortName, svcInfo.ClusterIP().String())
			staleUDPSvcs.Insert(svcInfo.ClusterIP().String())
			for _, extIP := range svcInfo.ExternalIPStrings() {
				staleUDPSvcs.Insert(extIP)
			}
		}
	}

	if err := p.svcHealthServer.SyncServices(svcUpdateResult.HCServiceNodePorts); err != nil {
		log.WithError(err).Error("Error syncing healthcheck services")
	}
	if err := p.svcHealthServer.SyncEndpoints(epsUpdateResult.HCEndpointsLocalIPSize); err != nil {
		log.WithError(err).Error("Error syncing healthcheck endpoints")
	}
	err := p.dpSyncer.Apply(DPSyncerState{
		SvcMap:       p.svcMap,
		EpsMap:       p.epsMap,
		StaleUDPSvcs: staleUDPSvcs,
	})

	if err != nil {
		log.WithError(err).Errorf("applying changes failed")
		// TODO log the error or panic as the best might be to restart
		// completely to wipe out the loaded bpf maps
	}

	if p.healthzServer != nil {
		p.healthzServer.Updated()
	}
}

func (p *proxy) OnServiceAdd(svc *v1.Service) {
	p.OnServiceUpdate(nil, svc)
}

func (p *proxy) OnServiceUpdate(old, curr *v1.Service) {
	if p.svcChanges.Update(old, curr) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnServiceDelete(svc *v1.Service) {
	p.OnServiceUpdate(svc, nil)
}

func (p *proxy) OnServiceSynced() {
	p.setSvcsSynced()
	p.forceSyncDP()
}

func (p *proxy) OnEndpointsAdd(eps *v1.Endpoints) {
	p.OnEndpointsUpdate(nil, eps)
}

func (p *proxy) OnEndpointsUpdate(old, curr *v1.Endpoints) {
	if p.epsChanges.Update(old, curr) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointsDelete(eps *v1.Endpoints) {
	p.OnEndpointsUpdate(eps, nil)
}

func (p *proxy) OnEndpointsSynced() {
	p.setEpsSynced()
	p.forceSyncDP()
}

func (p *proxy) OnEndpointSliceAdd(eps *discovery.EndpointSlice) {
	if p.epsChanges.EndpointSliceUpdate(eps, false) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointSliceUpdate(_, eps *discovery.EndpointSlice) {
	if p.epsChanges.EndpointSliceUpdate(eps, false) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointSliceDelete(eps *discovery.EndpointSlice) {
	if p.epsChanges.EndpointSliceUpdate(eps, true) && p.isInitialized() {
		p.syncDP()
	}
}

func (p *proxy) OnEndpointSlicesSynced() {
	p.setEpsSynced()
	p.forceSyncDP()
}

type initState struct {
	lck        sync.RWMutex
	svcsSynced bool
	epsSynced  bool
}

func (is *initState) isInitialized() bool {
	is.lck.RLock()
	defer is.lck.RUnlock()
	return is.svcsSynced && is.epsSynced
}

func (is *initState) setSvcsSynced() {
	is.lck.Lock()
	defer is.lck.Unlock()
	is.svcsSynced = true
}

func (is *initState) setEpsSynced() {
	is.lck.Lock()
	defer is.lck.Unlock()
	is.epsSynced = true
}

type loggerRecorder struct{}

func (r *loggerRecorder) Event(object runtime.Object, eventtype, reason, message string) {
}

func (r *loggerRecorder) Eventf(object runtime.Object, eventtype, reason,
	messageFmt string, args ...interface{}) {
}

func (r *loggerRecorder) PastEventf(object runtime.Object, timestamp metav1.Time, eventtype,
	reason, messageFmt string, args ...interface{}) {
}

func (r *loggerRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string,
	eventtype, reason, messageFmt string, args ...interface{}) {
}
<|endoftext|>


<commit_before>package chunker_test

import (
	"strconv"
	"testing"

	"github.com/restic/restic/chunker"
)

var polAddTests = []struct {
	x, y chunker.Pol
	sum  chunker.Pol
}{
	{23, 16, 23 ^ 16},
	{0x9a7e30d1e855e0a0, 0x670102a1f4bcd414, 0xfd7f32701ce934b4},
	{0x9a7e30d1e855e0a0, 0x9a7e30d1e855e0a0, 0},
}

func TestPolAdd(t *testing.T) {
	for _, test := range polAddTests {
		equals(t, test.sum, test.x.Add(test.y))
		equals(t, test.sum, test.y.Add(test.x))
	}
}

func parseBin(s string) chunker.Pol {
	i, err := strconv.ParseUint(s, 2, 64)
	if err != nil {
		panic(err)
	}

	return chunker.Pol(i)
}

var polMulTests = []struct {
	x, y chunker.Pol
	res  chunker.Pol
}{
	{1, 2, 2},
	{
		parseBin("1101"),
		parseBin("10"),
		parseBin("11010"),
	},
	{
		parseBin("1101"),
		parseBin("11"),
		parseBin("10111"),
	},
	{
		0x40000000,
		0x40000000,
		0x1000000000000000,
	},
	{
		parseBin("1010"),
		parseBin("100100"),
		parseBin("101101000"),
	},
	{
		parseBin("100"),
		parseBin("11"),
		parseBin("1100"),
	},
	{
		parseBin("11"),
		parseBin("110101"),
		parseBin("1011111"),
	},
	{
		parseBin("10011"),
		parseBin("110101"),
		parseBin("1100001111"),
	},
}

func TestPolMul(t *testing.T) {
	for i, test := range polMulTests {
		m := test.x.Mul(test.y)
		assert(t, test.res == m,
			"TestPolMul failed for test %d: %v * %v: want %v, got %v",
			i, test.x, test.y, test.res, m)
		m = test.y.Mul(test.x)
		assert(t, test.res == test.y.Mul(test.x),
			"TestPolMul failed for %d: %v * %v: want %v, got %v",
			i, test.x, test.y, test.res, m)
	}
}

func TestPolMulOverflow(t *testing.T) {
	defer func() {
		// try to recover overflow error
		err := recover()

		if e, ok := err.(string); ok && e == "multiplication would overflow uint64" {
			return
		} else {
			t.Logf("invalid error raised: %v", err)
			// re-raise error if not overflow
			panic(err)
		}
	}()

	x := chunker.Pol(1 << 63)
	x.Mul(2)
	t.Fatal("overflow test did not panic")
}

var polDivTests = []struct {
	x, y chunker.Pol
	res  chunker.Pol
}{
	{10, 50, 0},
	{0, 1, 0},
	{
		parseBin("101101000"), // 0x168
		parseBin("1010"),      // 0xa
		parseBin("100100"),    // 0x24
	},
	{2, 2, 1},
	{
		0x8000000000000000,
		0x8000000000000000,
		1,
	},
	{
		parseBin("1100"),
		parseBin("100"),
		parseBin("11"),
	},
	{
		parseBin("1100001111"),
		parseBin("10011"),
		parseBin("110101"),
	},
}

func TestPolDiv(t *testing.T) {
	for i, test := range polDivTests {
		m := test.x.Div(test.y)
		assert(t, test.res == m,
			"TestPolDiv failed for test %d: %v * %v: want %v, got %v",
			i, test.x, test.y, test.res, m)
	}
}

var polModTests = []struct {
	x, y chunker.Pol
	res  chunker.Pol
}{
	{10, 50, 10},
	{0, 1, 0},
	{
		parseBin("101101001"),
		parseBin("1010"),
		parseBin("1"),
	},
	{2, 2, 0},
	{
		0x8000000000000000,
		0x8000000000000000,
		0,
	},
	{
		parseBin("1100"),
		parseBin("100"),
		parseBin("0"),
	},
	{
		parseBin("1100001111"),
		parseBin("10011"),
		parseBin("0"),
	},
}

func TestPolModt(t *testing.T) {
	for _, test := range polModTests {
		equals(t, test.res, test.x.Mod(test.y))
	}
}

func BenchmarkPolDivMod(t *testing.B) {
	f := chunker.Pol(0x2482734cacca49)
	g := chunker.Pol(0x3af4b284899)

	for i := 0; i < t.N; i++ {
		g.DivMod(f)
	}
}

func BenchmarkPolDeg(t *testing.B) {
	f := chunker.Pol(0x3af4b284899)
	d := f.Deg()
	if d != 41 {
		t.Fatalf("BenchmalPolDeg: Wrong degree %d returned, expected %d",
			d, 41)
	}

	for i := 0; i < t.N; i++ {
		f.Deg()
	}
}

func TestRandomPolynomial(t *testing.T) {
	_, err := chunker.RandomPolynomial()
	ok(t, err)
}

func BenchmarkRandomPolynomial(t *testing.B) {
	for i := 0; i < t.N; i++ {
		_, err := chunker.RandomPolynomial()
		ok(t, err)
	}
}

func TestExpandPolynomial(t *testing.T) {
	pol := chunker.Pol(0x3DA3358B4DC173)
	s := pol.Expand()
	equals(t, "x^53+x^52+x^51+x^50+x^48+x^47+x^45+x^41+x^40+x^37+x^36+x^34+x^32+x^31+x^27+x^25+x^24+x^22+x^19+x^18+x^16+x^15+x^14+x^8+x^6+x^5+x^4+x+1", s)
}

var polIrredTests = []struct {
	f     chunker.Pol
	irred bool
}{
	{0x38f1e565e288df, false},
	{0x3DA3358B4DC173, true},
	{0x30a8295b9d5c91, false},
	{0x255f4350b962cb, false},
	{0x267f776110a235, false},
	{0x2f4dae10d41227, false},
	{0x2482734cacca49, true},
	{0x312daf4b284899, false},
	{0x29dfb6553d01d1, false},
	{0x3548245eb26257, false},
	{0x3199e7ef4211b3, false},
	{0x362f39017dae8b, false},
	{0x200d57aa6fdacb, false},
	{0x35e0a4efa1d275, false},
	{0x2ced55b026577f, false},
	{0x260b012010893d, false},
	{0x2df29cbcd59e9d, false},
	{0x3f2ac7488bd429, false},
	{0x3e5cb1711669fb, false},
	{0x226d8de57a9959, false},
	{0x3c8de80aaf5835, false},
	{0x2026a59efb219b, false},
	{0x39dfa4d13fb231, false},
	{0x3143d0464b3299, false},
}

func TestPolIrreducible(t *testing.T) {
	for _, test := range polIrredTests {
		assert(t, test.f.Irreducible() == test.irred,
			"Irreducibility test for Polynomial %v failed: got %v, wanted %v",
			test.f, test.f.Irreducible(), test.irred)
	}
}

var polGCDTests = []struct {
	f1  chunker.Pol
	f2  chunker.Pol
	gcd chunker.Pol
}{
	{10, 50, 2},
	{0, 1, 1},
	{
		parseBin("101101001"),
		parseBin("1010"),
		parseBin("1"),
	},
	{2, 2, 2},
	{
		parseBin("1010"),
		parseBin("11"),
		parseBin("11"),
	},
	{
		0x8000000000000000,
		0x8000000000000000,
		0x8000000000000000,
	},
	{
		parseBin("1100"),
		parseBin("101"),
		parseBin("11"),
	},
	{
		parseBin("1100001111"),
		parseBin("10011"),
		parseBin("10011"),
	},
	{
		0x3DA3358B4DC173,
		0x3DA3358B4DC173,
		0x3DA3358B4DC173,
	},
	{
		0x3DA3358B4DC173,
		0x230d2259defd,
		1,
	},
	{
		0x230d2259defd,
		0x51b492b3eff2,
		parseBin("10011"),
	},
}

func TestPolGCD(t *testing.T) {
	for i, test := range polGCDTests {
		gcd := test.f1.GCD(test.f2)
		assert(t, test.gcd == gcd,
			"GCD test %d (%+v) failed: got %v, wanted %v",
			i, test, gcd, test.gcd)
		gcd = test.f2.GCD(test.f1)
		assert(t, test.gcd == gcd,
			"GCD test %d (%+v) failed: got %v, wanted %v",
			i, test, gcd, test.gcd)
	}
}

var polMulModTests = []struct {
	f1  chunker.Pol
	f2  chunker.Pol
	g   chunker.Pol
	mod chunker.Pol
}{
	{
		0x1230,
		0x230,
		0x55,
		0x22,
	},
	{
		0x0eae8c07dbbb3026,
		0xd5d6db9de04771de,
		0xdd2bda3b77c9,
		0x425ae8595b7a,
	},
}

func TestPolMulMod(t *testing.T) {
	for i, test := range polMulModTests {
		mod := test.f1.MulMod(test.f2, test.g)
		assert(t, mod == test.mod,
			"MulMod test %d (%+v) failed: got %v, wanted %v",
			i, test, mod, test.mod)
	}
}
<commit_msg>Add more benchmarks<commit_after>package chunker_test

import (
	"strconv"
	"testing"

	"github.com/restic/restic/chunker"
)

var polAddTests = []struct {
	x, y chunker.Pol
	sum  chunker.Pol
}{
	{23, 16, 23 ^ 16},
	{0x9a7e30d1e855e0a0, 0x670102a1f4bcd414, 0xfd7f32701ce934b4},
	{0x9a7e30d1e855e0a0, 0x9a7e30d1e855e0a0, 0},
}

func TestPolAdd(t *testing.T) {
	for _, test := range polAddTests {
		equals(t, test.sum, test.x.Add(test.y))
		equals(t, test.sum, test.y.Add(test.x))
	}
}

func parseBin(s string) chunker.Pol {
	i, err := strconv.ParseUint(s, 2, 64)
	if err != nil {
		panic(err)
	}

	return chunker.Pol(i)
}

var polMulTests = []struct {
	x, y chunker.Pol
	res  chunker.Pol
}{
	{1, 2, 2},
	{
		parseBin("1101"),
		parseBin("10"),
		parseBin("11010"),
	},
	{
		parseBin("1101"),
		parseBin("11"),
		parseBin("10111"),
	},
	{
		0x40000000,
		0x40000000,
		0x1000000000000000,
	},
	{
		parseBin("1010"),
		parseBin("100100"),
		parseBin("101101000"),
	},
	{
		parseBin("100"),
		parseBin("11"),
		parseBin("1100"),
	},
	{
		parseBin("11"),
		parseBin("110101"),
		parseBin("1011111"),
	},
	{
		parseBin("10011"),
		parseBin("110101"),
		parseBin("1100001111"),
	},
}

func TestPolMul(t *testing.T) {
	for i, test := range polMulTests {
		m := test.x.Mul(test.y)
		assert(t, test.res == m,
			"TestPolMul failed for test %d: %v * %v: want %v, got %v",
			i, test.x, test.y, test.res, m)
		m = test.y.Mul(test.x)
		assert(t, test.res == test.y.Mul(test.x),
			"TestPolMul failed for %d: %v * %v: want %v, got %v",
			i, test.x, test.y, test.res, m)
	}
}

func TestPolMulOverflow(t *testing.T) {
	defer func() {
		// try to recover overflow error
		err := recover()

		if e, ok := err.(string); ok && e == "multiplication would overflow uint64" {
			return
		} else {
			t.Logf("invalid error raised: %v", err)
			// re-raise error if not overflow
			panic(err)
		}
	}()

	x := chunker.Pol(1 << 63)
	x.Mul(2)
	t.Fatal("overflow test did not panic")
}

var polDivTests = []struct {
	x, y chunker.Pol
	res  chunker.Pol
}{
	{10, 50, 0},
	{0, 1, 0},
	{
		parseBin("101101000"), // 0x168
		parseBin("1010"),      // 0xa
		parseBin("100100"),    // 0x24
	},
	{2, 2, 1},
	{
		0x8000000000000000,
		0x8000000000000000,
		1,
	},
	{
		parseBin("1100"),
		parseBin("100"),
		parseBin("11"),
	},
	{
		parseBin("1100001111"),
		parseBin("10011"),
		parseBin("110101"),
	},
}

func TestPolDiv(t *testing.T) {
	for i, test := range polDivTests {
		m := test.x.Div(test.y)
		assert(t, test.res == m,
			"TestPolDiv failed for test %d: %v * %v: want %v, got %v",
			i, test.x, test.y, test.res, m)
	}
}

var polModTests = []struct {
	x, y chunker.Pol
	res  chunker.Pol
}{
	{10, 50, 10},
	{0, 1, 0},
	{
		parseBin("101101001"),
		parseBin("1010"),
		parseBin("1"),
	},
	{2, 2, 0},
	{
		0x8000000000000000,
		0x8000000000000000,
		0,
	},
	{
		parseBin("1100"),
		parseBin("100"),
		parseBin("0"),
	},
	{
		parseBin("1100001111"),
		parseBin("10011"),
		parseBin("0"),
	},
}

func TestPolModt(t *testing.T) {
	for _, test := range polModTests {
		equals(t, test.res, test.x.Mod(test.y))
	}
}

func BenchmarkPolDivMod(t *testing.B) {
	f := chunker.Pol(0x2482734cacca49)
	g := chunker.Pol(0x3af4b284899)

	for i := 0; i < t.N; i++ {
		g.DivMod(f)
	}
}

func BenchmarkPolDiv(t *testing.B) {
	f := chunker.Pol(0x2482734cacca49)
	g := chunker.Pol(0x3af4b284899)

	for i := 0; i < t.N; i++ {
		g.Div(f)
	}
}

func BenchmarkPolMod(t *testing.B) {
	f := chunker.Pol(0x2482734cacca49)
	g := chunker.Pol(0x3af4b284899)

	for i := 0; i < t.N; i++ {
		g.Mod(f)
	}
}

func BenchmarkPolDeg(t *testing.B) {
	f := chunker.Pol(0x3af4b284899)
	d := f.Deg()
	if d != 41 {
		t.Fatalf("BenchmalPolDeg: Wrong degree %d returned, expected %d",
			d, 41)
	}

	for i := 0; i < t.N; i++ {
		f.Deg()
	}
}

func TestRandomPolynomial(t *testing.T) {
	_, err := chunker.RandomPolynomial()
	ok(t, err)
}

func BenchmarkRandomPolynomial(t *testing.B) {
	for i := 0; i < t.N; i++ {
		_, err := chunker.RandomPolynomial()
		ok(t, err)
	}
}

func TestExpandPolynomial(t *testing.T) {
	pol := chunker.Pol(0x3DA3358B4DC173)
	s := pol.Expand()
	equals(t, "x^53+x^52+x^51+x^50+x^48+x^47+x^45+x^41+x^40+x^37+x^36+x^34+x^32+x^31+x^27+x^25+x^24+x^22+x^19+x^18+x^16+x^15+x^14+x^8+x^6+x^5+x^4+x+1", s)
}

var polIrredTests = []struct {
	f     chunker.Pol
	irred bool
}{
	{0x38f1e565e288df, false},
	{0x3DA3358B4DC173, true},
	{0x30a8295b9d5c91, false},
	{0x255f4350b962cb, false},
	{0x267f776110a235, false},
	{0x2f4dae10d41227, false},
	{0x2482734cacca49, true},
	{0x312daf4b284899, false},
	{0x29dfb6553d01d1, false},
	{0x3548245eb26257, false},
	{0x3199e7ef4211b3, false},
	{0x362f39017dae8b, false},
	{0x200d57aa6fdacb, false},
	{0x35e0a4efa1d275, false},
	{0x2ced55b026577f, false},
	{0x260b012010893d, false},
	{0x2df29cbcd59e9d, false},
	{0x3f2ac7488bd429, false},
	{0x3e5cb1711669fb, false},
	{0x226d8de57a9959, false},
	{0x3c8de80aaf5835, false},
	{0x2026a59efb219b, false},
	{0x39dfa4d13fb231, false},
	{0x3143d0464b3299, false},
}

func TestPolIrreducible(t *testing.T) {
	for _, test := range polIrredTests {
		assert(t, test.f.Irreducible() == test.irred,
			"Irreducibility test for Polynomial %v failed: got %v, wanted %v",
			test.f, test.f.Irreducible(), test.irred)
	}
}

var polGCDTests = []struct {
	f1  chunker.Pol
	f2  chunker.Pol
	gcd chunker.Pol
}{
	{10, 50, 2},
	{0, 1, 1},
	{
		parseBin("101101001"),
		parseBin("1010"),
		parseBin("1"),
	},
	{2, 2, 2},
	{
		parseBin("1010"),
		parseBin("11"),
		parseBin("11"),
	},
	{
		0x8000000000000000,
		0x8000000000000000,
		0x8000000000000000,
	},
	{
		parseBin("1100"),
		parseBin("101"),
		parseBin("11"),
	},
	{
		parseBin("1100001111"),
		parseBin("10011"),
		parseBin("10011"),
	},
	{
		0x3DA3358B4DC173,
		0x3DA3358B4DC173,
		0x3DA3358B4DC173,
	},
	{
		0x3DA3358B4DC173,
		0x230d2259defd,
		1,
	},
	{
		0x230d2259defd,
		0x51b492b3eff2,
		parseBin("10011"),
	},
}

func TestPolGCD(t *testing.T) {
	for i, test := range polGCDTests {
		gcd := test.f1.GCD(test.f2)
		assert(t, test.gcd == gcd,
			"GCD test %d (%+v) failed: got %v, wanted %v",
			i, test, gcd, test.gcd)
		gcd = test.f2.GCD(test.f1)
		assert(t, test.gcd == gcd,
			"GCD test %d (%+v) failed: got %v, wanted %v",
			i, test, gcd, test.gcd)
	}
}

var polMulModTests = []struct {
	f1  chunker.Pol
	f2  chunker.Pol
	g   chunker.Pol
	mod chunker.Pol
}{
	{
		0x1230,
		0x230,
		0x55,
		0x22,
	},
	{
		0x0eae8c07dbbb3026,
		0xd5d6db9de04771de,
		0xdd2bda3b77c9,
		0x425ae8595b7a,
	},
}

func TestPolMulMod(t *testing.T) {
	for i, test := range polMulModTests {
		mod := test.f1.MulMod(test.f2, test.g)
		assert(t, mod == test.mod,
			"MulMod test %d (%+v) failed: got %v, wanted %v",
			i, test, mod, test.mod)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"sync"
	"time"

	"github.com/nsf/termbox-go"
	"github.com/rcrowley/go-metrics"
)

var (
	global_lastkeypress int64
	metricsFilter       metrics.Timer
)

func getRoot() string {
	if len(flag.Args()) == 0 {
		return "."
	} else {
		return flag.Arg(0)
	}
}

// hf --cmd=emacs ~/go/src/github.com/hugows/ happy
var cmd = flag.String("cmd", "vim", "command to run")

// var termkey *TermboxEventWrapper

// strings.Replace(tw.Text, " ", "+", -1)

func runCmdWithArgs(f string) {
	cmd := exec.Command(*cmd, f)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

const pauseAfterKeypress = (500 * time.Millisecond)

func main() {
	flag.Parse()

	var rview ResultsView

	root := getRoot()
	fi, err := os.Stat(root)
	if err != nil {
		fmt.Println(err)
		return
	}

	if !fi.IsDir() {
		fmt.Println(root, "is NOT a folder")
		return
	}

	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	termbox.SetInputMode(termbox.InputEsc)

	fileChan := walkFiles(getRoot())
	// fileChan := make(chan string, 1000)

	// go func() {
	// 	count := 0
	// 	// prefix := "brasilbrasilbrasilbrasilbrasil"
	// 	prefix := "brasilalemonalemonalemonalemonalemon"

	// 	for i := 0; i < 10000; i++ {
	// 		fileChan <- fmt.Sprintf("%s%d", prefix, count)
	// 		count += 1
	// 	}
	// }()

	resultset := new(ResultSet)

	// for filename := range fileChan {
	// results.Insert(<-fileChan)
	// }

	// 	a, b := score(filexname, flag.Arg(1))
	// 	if a >= 0 && a < 100 {

	// 		if first {
	// 			runcmd := exec.Command(*cmd, filename)
	// 			runcmd.Stdin = os.Stdin
	// 			runcmd.Stdout = os.Stdout
	// 			err := runcmd.Run()
	// 			if err != nil {
	// 				log.Fatal(err)
	// 			}
	// 			first = false
	// 		}

	// 		fmt.Printf("%30s %4d %v\n", filename, a, b)
	// 	}
	// }

	var timeLastUser time.Time
	// resultsQueue := make([]string, 0, 100)
	w, h := termbox.Size()
	modeline := NewModeline(0, h-1, w)
	cmdline := new(CommandLine)

	// termkey = NewTermboxEventWrapper()

	modeline.Draw(&rview)
	cmdline.Draw(0, h-2, w)
	rview.SetSize(0, 0, w, h-2)
	// cmdline.Update(rview.GetSelected())
	// rview.CopyAll()
	// rview.Update()
	// rview.Draw()
	termbox.Flush()

	termboxEventChan := make(chan termbox.Event)
	newFileCh := make(chan bool, 10000)
	newInputCh := make(chan bool)
	// resultCh := make(chan ResultSet, 1000)

	// go resultset.FilterManager(inputCh, resultCh)

	// throttle := time.NewTicker(time.Millisecond * 500)
	go func() {
		for {
			termboxEventChan <- termbox.PollEvent()
		}
	}()

	// dirty := false

	// go func() {
	// 	for {
	// 		filtered := <-resultCh
	// 		// dirty = false
	// 		rview.Update(filtered.results)
	// 		cmdline.Update(rview.GetSelected())

	// 		modeline.Draw(&rview)
	// 		cmdline.Draw(0, h-2, w)
	// 		rview.Draw()
	// 		termbox.Flush()
	// 	}
	// }()
	var mutex = &sync.Mutex{}

	go func() {
		REAL_SOON_NOW := time.Millisecond * 15
		sched := time.NewTimer(REAL_SOON_NOW)
		count := 0

		for {
			select {
			case <-newFileCh:
				count += 1
				if count < 100 {
					sched.Reset(REAL_SOON_NOW)
				}
			case <-sched.C:
				mutex.Lock()
				filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
				rview.Update(filtered.results)
				cmdline.Update(rview.GetSelected())
				mutex.Unlock()
				count = 0
				modeline.Draw(&rview)
				cmdline.Draw(0, h-2, w)
				rview.Draw()
				termbox.Flush()
			}
		}
	}()

	go func() {
		for {
			<-newInputCh
			mutex.Lock()
			filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
			rview.Update(filtered.results)
			cmdline.Update(rview.GetSelected())
			mutex.Unlock()
			modeline.Draw(&rview)
			cmdline.Draw(0, h-2, w)
			rview.Draw()
			termbox.Flush()
		}
	}()

	// func (rs *ResultSet) AsyncFilter(dirty <-chan bool, resultCh chan<- ResultSet) {
	// 	for {
	// 		<-dirty
	// 		result
	// 		res, _ := rs.Filter(when, userinput)
	// 		resultCh <- res
	// 	}
	// }

	timer := time.NewTimer(1 * time.Hour)

	metricsFilter = metrics.NewTimer()
	metrics.Register("Filter", metricsFilter)

	// go metrics.Log(metrics.DefaultRegistry, 60e8, log.New(os.Stderr, "metrics: ", log.Lmicroseconds))

	// Command name is:
	// os.Args[0]

	// var r string
	timeLastUser = time.Now().Add(-1 * time.Hour)
	// dirty := false
	// ticker := time.NewTicker(time.Millisecond * 1000)

	for {
		select {
		case <-timer.C:
			resultset.FlushQueue()
			// filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
			// rview.Update(filtered.results)
			timer = time.NewTimer(1 * time.Hour)
		// case <-ticker.C:
		// redraw
		// if dirty {
		// 	// go resultset.AsyncFilter(global_lastkeypress, modeline.Contents(), resultCh)
		// 	filtered, cancelled := resultset.Filter(global_lastkeypress, modeline.Contents())
		// 	if !cancelled {
		// 		rview.Update(filtered.results)
		// 		cmdline.Update(rview.GetSelected())
		// 		dirty = false
		// 	}
		// }
		case filename, ok := <-fileChan:
			if ok {
				// if not paused anymore
				if time.Since(timeLastUser) > pauseAfterKeypress {
					modeline.Unpause()
					resultset.Insert(filename)
					newFileCh <- true

					// dirty = true
					// resultset.AsyncFilter(global_lastkeypress, modeline.Contents(), resultCh)

					// filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
					// rview.Update(filtered.results)
					// cmdline.Update(rview.GetSelected())
				} else {
					modeline.Pause()
					resultset.Queue(filename)
				}
			} else {
				fileChan = nil
			}

		case ev := <-termboxEventChan:
			if ev.Type == termbox.EventKey {
				timeLastUser = time.Now()
				global_lastkeypress = 0 //timeLastUser.UnixNano()
			}

			if fileChan != nil {
				timer.Reset(pauseAfterKeypress)
			} else {
				modeline.Unpause()
			}

			switch ev.Type {
			case termbox.EventKey:
				switch ev.Key {
				case termbox.KeyEsc, termbox.KeyCtrlC:
					termbox.Close()
					return
				case termbox.KeyEnter:
					termbox.Close()
					// runCmdWithArgs(rview.FormatSelected())
					return
				case termbox.KeyCtrlT:
					rview.ToggleMarkAll()
				case termbox.KeyArrowUp, termbox.KeyCtrlP:
					cmdline.Update(rview.SelectPrevious())
				case termbox.KeyArrowDown, termbox.KeyCtrlN:
					cmdline.Update(rview.SelectNext())
				case termbox.KeyArrowLeft, termbox.KeyCtrlB:
					modeline.input.MoveCursorOneRuneBackward()
				case termbox.KeyArrowRight, termbox.KeyCtrlF:
					modeline.input.MoveCursorOneRuneForward()
				case termbox.KeyBackspace, termbox.KeyBackspace2:
					modeline.input.DeleteRuneBackward()
					newInputCh <- true
				case termbox.KeyDelete, termbox.KeyCtrlD:
					modeline.input.DeleteRuneForward()
					newInputCh <- true
				case termbox.KeySpace:
					rview.ToggleMark()
				case termbox.KeyCtrlK:
					modeline.input.DeleteTheRestOfTheLine()
					newInputCh <- true
				case termbox.KeyHome, termbox.KeyCtrlA:
					modeline.input.MoveCursorToBeginningOfTheLine()
				case termbox.KeyEnd, termbox.KeyCtrlE:
					modeline.input.MoveCursorToEndOfTheLine()
				default:
					if ev.Ch != 0 {
						modeline.input.InsertRune(ev.Ch)
						newInputCh <- true
					}
				}
			case termbox.EventError:
				panic(ev.Err)
			}

			// fmt.Println(modeline.Contents())
		}

		modeline.Draw(&rview)
		cmdline.Draw(0, h-2, w)
		rview.Draw()
		termbox.Flush()
	}

}
<commit_msg>remove drawing from multiple threads<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"time"

	"github.com/nsf/termbox-go"
	"github.com/rcrowley/go-metrics"
)

var (
	global_lastkeypress int64
	metricsFilter       metrics.Timer
)

func getRoot() string {
	if len(flag.Args()) == 0 {
		return "."
	} else {
		return flag.Arg(0)
	}
}

// hf --cmd=emacs ~/go/src/github.com/hugows/ happy
var cmd = flag.String("cmd", "vim", "command to run")

// var termkey *TermboxEventWrapper

// strings.Replace(tw.Text, " ", "+", -1)

func runCmdWithArgs(f string) {
	cmd := exec.Command(*cmd, f)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}

const pauseAfterKeypress = (500 * time.Millisecond)

func main() {
	flag.Parse()

	var rview ResultsView

	root := getRoot()
	fi, err := os.Stat(root)
	if err != nil {
		fmt.Println(err)
		return
	}

	if !fi.IsDir() {
		fmt.Println(root, "is NOT a folder")
		return
	}

	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	termbox.SetInputMode(termbox.InputEsc)

	fileChan := walkFiles(getRoot())
	// fileChan := make(chan string, 1000)

	// go func() {
	// 	count := 0
	// 	// prefix := "brasilbrasilbrasilbrasilbrasil"
	// 	prefix := "brasilalemonalemonalemonalemonalemon"

	// 	for i := 0; i < 10000; i++ {
	// 		fileChan <- fmt.Sprintf("%s%d", prefix, count)
	// 		count += 1
	// 	}
	// }()

	resultset := new(ResultSet)

	// for filename := range fileChan {
	// results.Insert(<-fileChan)
	// }

	// 	a, b := score(filexname, flag.Arg(1))
	// 	if a >= 0 && a < 100 {

	// 		if first {
	// 			runcmd := exec.Command(*cmd, filename)
	// 			runcmd.Stdin = os.Stdin
	// 			runcmd.Stdout = os.Stdout
	// 			err := runcmd.Run()
	// 			if err != nil {
	// 				log.Fatal(err)
	// 			}
	// 			first = false
	// 		}

	// 		fmt.Printf("%30s %4d %v\n", filename, a, b)
	// 	}
	// }

	var timeLastUser time.Time
	// resultsQueue := make([]string, 0, 100)
	w, h := termbox.Size()
	modeline := NewModeline(0, h-1, w)
	cmdline := new(CommandLine)

	// termkey = NewTermboxEventWrapper()

	modeline.Draw(&rview)
	cmdline.Draw(0, h-2, w)
	rview.SetSize(0, 0, w, h-2)
	// cmdline.Update(rview.GetSelected())
	// rview.CopyAll()
	// rview.Update()
	// rview.Draw()
	termbox.Flush()

	termboxEventChan := make(chan termbox.Event)
	newFileCh := make(chan bool, 10000)
	forceDrawCh := make(chan bool, 100)
	newInputCh := make(chan bool)
	// resultCh := make(chan ResultSet, 1000)

	// go resultset.FilterManager(inputCh, resultCh)

	// throttle := time.NewTicker(time.Millisecond * 500)
	go func() {
		for {
			termboxEventChan <- termbox.PollEvent()
		}
	}()

	// dirty := false

	// go func() {
	// 	for {
	// 		filtered := <-resultCh
	// 		// dirty = false
	// 		rview.Update(filtered.results)
	// 		cmdline.Update(rview.GetSelected())

	// 		modeline.Draw(&rview)
	// 		cmdline.Draw(0, h-2, w)
	// 		rview.Draw()
	// 		termbox.Flush()
	// 	}
	// }()
	// var mutex = &sync.Mutex{}

	go func() {
		REAL_SOON_NOW := time.Millisecond * 15
		sched := time.NewTimer(REAL_SOON_NOW)
		count := 0

		for {
			select {
			case <-newFileCh:
				count += 1
				if count < 100 {
					sched.Reset(REAL_SOON_NOW)
				}
			case <-sched.C:
				// mutex.Lock()
				filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
				rview.Update(filtered.results)
				cmdline.Update(rview.GetSelected())
				count = 0
				forceDrawCh <- true
			}
		}
	}()

	go func() {
		for {
			<-newInputCh
			// mutex.Lock()
			filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
			rview.Update(filtered.results)
			cmdline.Update(rview.GetSelected())
			forceDrawCh <- true
		}
	}()

	// func (rs *ResultSet) AsyncFilter(dirty <-chan bool, resultCh chan<- ResultSet) {
	// 	for {
	// 		<-dirty
	// 		result
	// 		res, _ := rs.Filter(when, userinput)
	// 		resultCh <- res
	// 	}
	// }

	timer := time.NewTimer(1 * time.Hour)

	metricsFilter = metrics.NewTimer()
	metrics.Register("Filter", metricsFilter)

	// go metrics.Log(metrics.DefaultRegistry, 60e8, log.New(os.Stderr, "metrics: ", log.Lmicroseconds))

	// Command name is:
	// os.Args[0]

	// var r string
	timeLastUser = time.Now().Add(-1 * time.Hour)
	// dirty := false
	// ticker := time.NewTicker(time.Millisecond * 1000)

	for {
		select {
		case <-forceDrawCh:
			/* redraw */
		case <-timer.C:
			resultset.FlushQueue()
			// filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
			// rview.Update(filtered.results)
			timer = time.NewTimer(1 * time.Hour)
		// case <-ticker.C:
		// redraw
		// if dirty {
		// 	// go resultset.AsyncFilter(global_lastkeypress, modeline.Contents(), resultCh)
		// 	filtered, cancelled := resultset.Filter(global_lastkeypress, modeline.Contents())
		// 	if !cancelled {
		// 		rview.Update(filtered.results)
		// 		cmdline.Update(rview.GetSelected())
		// 		dirty = false
		// 	}
		// }
		case filename, ok := <-fileChan:
			if ok {
				// if not paused anymore
				if time.Since(timeLastUser) > pauseAfterKeypress {
					modeline.Unpause()
					resultset.Insert(filename)
					newFileCh <- true

					// dirty = true
					// resultset.AsyncFilter(global_lastkeypress, modeline.Contents(), resultCh)

					// filtered := resultset.Filter(global_lastkeypress, modeline.Contents())
					// rview.Update(filtered.results)
					// cmdline.Update(rview.GetSelected())
				} else {
					modeline.Pause()
					resultset.Queue(filename)
				}
			} else {
				fileChan = nil
			}

		case ev := <-termboxEventChan:
			if ev.Type == termbox.EventKey {
				timeLastUser = time.Now()
				global_lastkeypress = 0 //timeLastUser.UnixNano()
			}

			if fileChan != nil {
				timer.Reset(pauseAfterKeypress)
			} else {
				modeline.Unpause()
			}

			switch ev.Type {
			case termbox.EventKey:
				switch ev.Key {
				case termbox.KeyEsc, termbox.KeyCtrlC:
					termbox.Close()
					return
				case termbox.KeyEnter:
					termbox.Close()
					// runCmdWithArgs(rview.FormatSelected())
					return
				case termbox.KeyCtrlT:
					rview.ToggleMarkAll()
				case termbox.KeyArrowUp, termbox.KeyCtrlP:
					cmdline.Update(rview.SelectPrevious())
				case termbox.KeyArrowDown, termbox.KeyCtrlN:
					cmdline.Update(rview.SelectNext())
				case termbox.KeyArrowLeft, termbox.KeyCtrlB:
					modeline.input.MoveCursorOneRuneBackward()
				case termbox.KeyArrowRight, termbox.KeyCtrlF:
					modeline.input.MoveCursorOneRuneForward()
				case termbox.KeyBackspace, termbox.KeyBackspace2:
					modeline.input.DeleteRuneBackward()
					newInputCh <- true
				case termbox.KeyDelete, termbox.KeyCtrlD:
					modeline.input.DeleteRuneForward()
					newInputCh <- true
				case termbox.KeySpace:
					rview.ToggleMark()
				case termbox.KeyCtrlK:
					modeline.input.DeleteTheRestOfTheLine()
					newInputCh <- true
				case termbox.KeyHome, termbox.KeyCtrlA:
					modeline.input.MoveCursorToBeginningOfTheLine()
				case termbox.KeyEnd, termbox.KeyCtrlE:
					modeline.input.MoveCursorToEndOfTheLine()
				default:
					if ev.Ch != 0 {
						modeline.input.InsertRune(ev.Ch)
						newInputCh <- true
					}
				}
			case termbox.EventError:
				panic(ev.Err)
			}

			// fmt.Println(modeline.Contents())
		}

		modeline.Draw(&rview)
		cmdline.Draw(0, h-2, w)
		rview.Draw()
		termbox.Flush()
	}

}
<|endoftext|>


<commit_before>package app

import (
	"flag"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"testing"

	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
	"github.com/weaveworks/scope/test/fixture"
)

var (
	benchReportPath = flag.String("bench-report-path", "", "report file, or dir with files, to use for benchmarking (relative to this package)")
)

func readReportFiles(path string) ([]report.Report, error) {
	reports := []report.Report{}
	if err := filepath.Walk(path,
		func(p string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.IsDir() {
				return nil
			}
			rpt, err := report.MakeFromFile(p)
			if err != nil {
				return err
			}
			reports = append(reports, rpt)
			return nil
		}); err != nil {
		return nil, err
	}
	return reports, nil
}

func BenchmarkReportUnmarshal(b *testing.B) {
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := readReportFiles(*benchReportPath); err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkReportMerge(b *testing.B) {
	reports, err := readReportFiles(*benchReportPath)
	if err != nil {
		b.Fatal(err)
	}
	merger := NewSmartMerger()

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		merger.Merge(reports)
	}
}

func BenchmarkReportUpgrade(b *testing.B) {
	reports, err := readReportFiles(*benchReportPath)
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		for _, r := range reports {
			r.Upgrade()
		}
	}
}

func benchmarkRender(b *testing.B, f func(report.Report)) {
	r := fixture.Report
	if *benchReportPath != "" {
		reports, err := readReportFiles(*benchReportPath)
		if err != nil {
			b.Fatal(err)
		}
		r = NewSmartMerger().Merge(reports)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		render.ResetCache()
		b.StartTimer()
		f(r)
	}
}

func benchmarkRenderTopology(b *testing.B, topologyID string) {
	benchmarkRender(b, func(report report.Report) {
		renderer, filter, err := topologyRegistry.RendererForTopology(topologyID, url.Values{}, report)
		if err != nil {
			b.Fatal(err)
		}
		render.Render(report, renderer, filter)
	})
}

func BenchmarkRenderList(b *testing.B) {
	benchmarkRender(b, func(report report.Report) {
		request := &http.Request{
			Form: url.Values{},
		}
		topologyRegistry.renderTopologies(report, request)
	})
}

func BenchmarkRenderHosts(b *testing.B) {
	benchmarkRenderTopology(b, "hosts")
}

func BenchmarkRenderControllers(b *testing.B) {
	benchmarkRenderTopology(b, "kube-controllers")
}

func BenchmarkRenderPods(b *testing.B) {
	benchmarkRenderTopology(b, "pods")
}

func BenchmarkRenderContainers(b *testing.B) {
	benchmarkRenderTopology(b, "containers")
}

func BenchmarkRenderProcesses(b *testing.B) {
	benchmarkRenderTopology(b, "processes")
}
<commit_msg>cosmetic: more logical function order<commit_after>package app

import (
	"flag"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"testing"

	"github.com/weaveworks/scope/render"
	"github.com/weaveworks/scope/report"
	"github.com/weaveworks/scope/test/fixture"
)

var (
	benchReportPath = flag.String("bench-report-path", "", "report file, or dir with files, to use for benchmarking (relative to this package)")
)

func readReportFiles(path string) ([]report.Report, error) {
	reports := []report.Report{}
	if err := filepath.Walk(path,
		func(p string, info os.FileInfo, err error) error {
			if err != nil {
				return err
			}
			if info.IsDir() {
				return nil
			}
			rpt, err := report.MakeFromFile(p)
			if err != nil {
				return err
			}
			reports = append(reports, rpt)
			return nil
		}); err != nil {
		return nil, err
	}
	return reports, nil
}

func BenchmarkReportUnmarshal(b *testing.B) {
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := readReportFiles(*benchReportPath); err != nil {
			b.Fatal(err)
		}
	}
}

func BenchmarkReportUpgrade(b *testing.B) {
	reports, err := readReportFiles(*benchReportPath)
	if err != nil {
		b.Fatal(err)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		for _, r := range reports {
			r.Upgrade()
		}
	}
}

func BenchmarkReportMerge(b *testing.B) {
	reports, err := readReportFiles(*benchReportPath)
	if err != nil {
		b.Fatal(err)
	}
	merger := NewSmartMerger()

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		merger.Merge(reports)
	}
}

func benchmarkRender(b *testing.B, f func(report.Report)) {
	r := fixture.Report
	if *benchReportPath != "" {
		reports, err := readReportFiles(*benchReportPath)
		if err != nil {
			b.Fatal(err)
		}
		r = NewSmartMerger().Merge(reports)
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		render.ResetCache()
		b.StartTimer()
		f(r)
	}
}

func benchmarkRenderTopology(b *testing.B, topologyID string) {
	benchmarkRender(b, func(report report.Report) {
		renderer, filter, err := topologyRegistry.RendererForTopology(topologyID, url.Values{}, report)
		if err != nil {
			b.Fatal(err)
		}
		render.Render(report, renderer, filter)
	})
}

func BenchmarkRenderList(b *testing.B) {
	benchmarkRender(b, func(report report.Report) {
		request := &http.Request{
			Form: url.Values{},
		}
		topologyRegistry.renderTopologies(report, request)
	})
}

func BenchmarkRenderHosts(b *testing.B) {
	benchmarkRenderTopology(b, "hosts")
}

func BenchmarkRenderControllers(b *testing.B) {
	benchmarkRenderTopology(b, "kube-controllers")
}

func BenchmarkRenderPods(b *testing.B) {
	benchmarkRenderTopology(b, "pods")
}

func BenchmarkRenderContainers(b *testing.B) {
	benchmarkRenderTopology(b, "containers")
}

func BenchmarkRenderProcesses(b *testing.B) {
	benchmarkRenderTopology(b, "processes")
}
<|endoftext|>


<commit_before>package handlers

import (
        "fmt"
	middleware "github.com/go-openapi/runtime/middleware"

	"github.com/redhatanalytics/oshinko-rest/restapi/operations/clusters"
	serverapi "github.com/openshift/origin/pkg/cmd/server/api"
	odc "github.com/redhatanalytics/oshinko-rest/helpers/deploymentconfigs"
	ocon "github.com/redhatanalytics/oshinko-rest/helpers/containers"
	opt "github.com/redhatanalytics/oshinko-rest/helpers/podtemplates"
	osv "github.com/redhatanalytics/oshinko-rest/helpers/services"
	_ "github.com/openshift/origin/pkg/api/install"

	"strconv"
)

func sparkMasterURL(name string, port *osv.OServicePort) string {
	return "spark://" + name + ":" + strconv.Itoa(port.ServicePort.Port)
}

func sparkWorker(namespace string,
                 image string,
                 replicas int, masterurl string) *odc.ODeploymentConfig {

	// Create the basic deployment config
	dc := odc.DeploymentConfig(
		"spark-worker",
		namespace).TriggerOnConfigChange().RollingStrategy().Replicas(replicas)

	// We will use a "name" label with the name of the deployment config
	// as a selector for the pods controlled by this deployment.
	// Set the selector on the deployment config ...
	dc = dc.PodSelector("name", dc.Name)

	// ... and create a pod template spec with the matching label
	pt := opt.PodTemplateSpec().SetLabels(dc.GetPodSelectors())

	// Create a container with the correct start command
	cont := ocon.Container(
		dc.Name,
		image).Command("/start-worker", masterurl)

	// Finally, assign the container to the pod template spec and
	// assign the pod template spec to the deployment config
	return dc.PodTemplateSpec(pt.Containers(cont))
}

func sparkMaster(namespace string, image string) *odc.ODeploymentConfig {

	// Create the basic deployment config
	// dc.Name will be spark-master-<suffix>
	dc := odc.DeploymentConfig(
		"spark-master",
		namespace).TriggerOnConfigChange().RollingStrategy()

	// We will use a "name" label with the name of the deployment config
	// as a selector for the pods controlled by this deployment.
	// Set the selector on the deployment config ...
	dc = dc.PodSelector("name", dc.Name)

	// ... and create a pod template spec with the matching label
	pt := opt.PodTemplateSpec().SetLabels(dc.GetPodSelectors())

	// Create a container with the correct ports and start command
	masterp := ocon.ContainerPort("spark-master", 7077)
	webp := ocon.ContainerPort("spark-webui", 8080)
	cont := ocon.Container(
		dc.Name,
		image).Command("/start-master",
		dc.Name).Ports(masterp, webp)

	// Finally, assign the container to the pod template spec and
	// assign the pod template spec to the deployment config
	return dc.PodTemplateSpec(pt.Containers(cont))
}

func Service(name string, port int, mylabels, podlabels map[string]string) (*osv.OService, *osv.OServicePort) {
	p := osv.ServicePort(port).TargetPort(port)
	return osv.Service(name).SetLabels(mylabels).PodSelectors(podlabels).Ports(p), p
}

// CreateClusterResponse create a cluster and return the representation
func CreateClusterResponse(params clusters.CreateClusterParams) middleware.Responder {
	// create a cluster here
	// INFO(elmiko) my thinking on creating clusters is that we should use a
	// label on the items we create with kubernetes so that we can get them
	// all with a request.
	// in addition to labels for general identification, we should then use
	// annotations on objects to help further refine what we are dealing with.

	// kube rest client
	client, _, err := serverapi.GetKubeClient("/home/tmckay/.kube/config")
	if err != nil {
		// handle error
	}

	// openshift rest client
	osclient, _, err := serverapi.GetOpenShiftClient("/home/tmckay/.kube/config")
	if err != nil {
		//handle error
	}

	// deployment config client
	dcc := osclient.DeploymentConfigs("spark")

	// Make master deployment config
	// Ignoring master-count for now, leave it defaulted at 1
	masterdc := sparkMaster("spark", "172.30.122.181:5000/spark/openshift-spark")

	// Make master services
	mastersv, masterp := Service(masterdc.Name,
		masterdc.FindPort("spark-master"),
		masterdc.GetPodSelectors(), masterdc.GetPodSelectors())

	websv, _ := Service(masterdc.Name + "webui",
		masterdc.FindPort("spark-webui"),
		masterdc.GetPodSelectors(),
		masterdc.GetPodSelectors())

	// Make worker deployment config
	masterurl := sparkMasterURL(mastersv.Name, masterp)
	workerdc := sparkWorker(
		"spark",
		"172.30.122.181:5000/spark/openshift-spark",
		*params.Cluster.WorkerCount, masterurl)

	// Launch all of the objects
	_, err = dcc.Create(&masterdc.DeploymentConfig)
        if err != nil {
            fmt.Println(err)
        }
	dcc.Create(&workerdc.DeploymentConfig)
	client.Services("spark").Create(&mastersv.Service)
	client.Services("spark").Create(&websv.Service)

	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.CreateCluster has not yet been implemented")

	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// DeleteClusterResponse delete a cluster
func DeleteClusterResponse(params clusters.DeleteSingleClusterParams) middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.DeleteSingleCluster has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// FindClustersResponse find a cluster and return its representation
func FindClustersResponse() middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.FindClusters has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// FindSingleClusterResponse find a cluster and return its representation
func FindSingleClusterResponse(clusters.FindSingleClusterParams) middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.FindSingleCluster has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// UpdateSingleClusterResponse update a cluster and return the new representation
func UpdateSingleClusterResponse(params clusters.UpdateSingleClusterParams) middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.UpdateSingleCluster has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}
<commit_msg>Initial checkin for cluster creation, needs a lot of work<commit_after>package handlers

import (
	"fmt"
	middleware "github.com/go-openapi/runtime/middleware"

	_ "github.com/openshift/origin/pkg/api/install"
	serverapi "github.com/openshift/origin/pkg/cmd/server/api"
	ocon "github.com/redhatanalytics/oshinko-rest/helpers/containers"
	odc "github.com/redhatanalytics/oshinko-rest/helpers/deploymentconfigs"
	opt "github.com/redhatanalytics/oshinko-rest/helpers/podtemplates"
	osv "github.com/redhatanalytics/oshinko-rest/helpers/services"
	"github.com/redhatanalytics/oshinko-rest/restapi/operations/clusters"

	"strconv"
)

func sparkMasterURL(name string, port *osv.OServicePort) string {
	return "spark://" + name + ":" + strconv.Itoa(port.ServicePort.Port)
}

func sparkWorker(namespace string,
	image string,
	replicas int, masterurl string) *odc.ODeploymentConfig {

	// Create the basic deployment config
	dc := odc.DeploymentConfig(
		"spark-worker",
		namespace).TriggerOnConfigChange().RollingStrategy().Replicas(replicas)

	// We will use a "name" label with the name of the deployment config
	// as a selector for the pods controlled by this deployment.
	// Set the selector on the deployment config ...
	dc = dc.PodSelector("name", dc.Name)

	// ... and create a pod template spec with the matching label
	pt := opt.PodTemplateSpec().SetLabels(dc.GetPodSelectors())

	// Create a container with the correct start command
	cont := ocon.Container(
		dc.Name,
		image).Command("/start-worker", masterurl)

	// Finally, assign the container to the pod template spec and
	// assign the pod template spec to the deployment config
	return dc.PodTemplateSpec(pt.Containers(cont))
}

func sparkMaster(namespace string, image string) *odc.ODeploymentConfig {

	// Create the basic deployment config
	// dc.Name will be spark-master-<suffix>
	dc := odc.DeploymentConfig(
		"spark-master",
		namespace).TriggerOnConfigChange().RollingStrategy()

	// We will use a "name" label with the name of the deployment config
	// as a selector for the pods controlled by this deployment.
	// Set the selector on the deployment config ...
	dc = dc.PodSelector("name", dc.Name)

	// ... and create a pod template spec with the matching label
	pt := opt.PodTemplateSpec().SetLabels(dc.GetPodSelectors())

	// Create a container with the correct ports and start command
	masterp := ocon.ContainerPort("spark-master", 7077)
	webp := ocon.ContainerPort("spark-webui", 8080)
	cont := ocon.Container(
		dc.Name,
		image).Command("/start-master",
		dc.Name).Ports(masterp, webp)

	// Finally, assign the container to the pod template spec and
	// assign the pod template spec to the deployment config
	return dc.PodTemplateSpec(pt.Containers(cont))
}

func Service(name string, port int, mylabels, podlabels map[string]string) (*osv.OService, *osv.OServicePort) {
	p := osv.ServicePort(port).TargetPort(port)
	return osv.Service(name).SetLabels(mylabels).PodSelectors(podlabels).Ports(p), p
}

// CreateClusterResponse create a cluster and return the representation
func CreateClusterResponse(params clusters.CreateClusterParams) middleware.Responder {
	// create a cluster here
	// INFO(elmiko) my thinking on creating clusters is that we should use a
	// label on the items we create with kubernetes so that we can get them
	// all with a request.
	// in addition to labels for general identification, we should then use
	// annotations on objects to help further refine what we are dealing with.

	// kube rest client
	client, _, err := serverapi.GetKubeClient("/home/tmckay/.kube/config")
	if err != nil {
		// handle error
	}

	// openshift rest client
	osclient, _, err := serverapi.GetOpenShiftClient("/home/tmckay/.kube/config")
	if err != nil {
		//handle error
	}

	// deployment config client
	dcc := osclient.DeploymentConfigs("spark")

	// Make master deployment config
	// Ignoring master-count for now, leave it defaulted at 1
	masterdc := sparkMaster("spark", "172.30.122.181:5000/spark/openshift-spark")

	// Make master services
	mastersv, masterp := Service(masterdc.Name,
		masterdc.FindPort("spark-master"),
		masterdc.GetPodSelectors(), masterdc.GetPodSelectors())

	websv, _ := Service(masterdc.Name+"webui",
		masterdc.FindPort("spark-webui"),
		masterdc.GetPodSelectors(),
		masterdc.GetPodSelectors())

	// Make worker deployment config
	masterurl := sparkMasterURL(mastersv.Name, masterp)
	workerdc := sparkWorker(
		"spark",
		"172.30.122.181:5000/spark/openshift-spark",
		*params.Cluster.WorkerCount, masterurl)

	// Launch all of the objects
	_, err = dcc.Create(&masterdc.DeploymentConfig)
	if err != nil {
		fmt.Println(err)
	}
	dcc.Create(&workerdc.DeploymentConfig)
	client.Services("spark").Create(&mastersv.Service)
	client.Services("spark").Create(&websv.Service)

	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.CreateCluster has not yet been implemented")

	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// DeleteClusterResponse delete a cluster
func DeleteClusterResponse(params clusters.DeleteSingleClusterParams) middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.DeleteSingleCluster has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// FindClustersResponse find a cluster and return its representation
func FindClustersResponse() middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.FindClusters has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// FindSingleClusterResponse find a cluster and return its representation
func FindSingleClusterResponse(clusters.FindSingleClusterParams) middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.FindSingleCluster has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}

// UpdateSingleClusterResponse update a cluster and return the new representation
func UpdateSingleClusterResponse(params clusters.UpdateSingleClusterParams) middleware.Responder {
	payload := makeSingleErrorResponse(501, "Not Implemented",
		"operation clusters.UpdateSingleCluster has not yet been implemented")
	return clusters.NewCreateClusterDefault(501).WithPayload(payload)
}
<|endoftext|>