<commit_before>package shell

import (
	"bufio"
	"common"
	"exec"
	"os"
	"strings"
)

func Shell(call []string) os.Error {
	var in *bufio.Reader
	if len(call) > 2 {
		call = call[0:1]
	}
	if len(call) == 2 {
		f, e := os.Open(call[1])
		if e != nil {
			return e
		}
		defer f.Close()
		in = bufio.NewReader(f)
	} else {
		in = bufio.NewReader(os.Stdin)
	}

	var e os.Error
	var line string
	for e == nil {
		print("> ")
		line, e = getNextLine(in)
		if e != nil {
			return e
		}
		if isComment(line) {
			continue
		}
		params, ce := parameterize(line)
		if ce != nil {
			common.DumpError(ce)
			continue
		}
		ce = execute(params)
		if ce != nil {
			common.DumpError(ce)
			continue
		}
	}
	return nil
}

func isComment(line string) bool {
	line = strings.TrimSpace(line)
	return strings.HasPrefix(line, "#")
}

func execute(cmd []string) os.Error {
	if isBuiltIn(cmd[0]) {
		builtin := Builtins[cmd[0]]
		return builtin(cmd)
	} else {
		cmd := exec.Command(cmd[0], cmd[1:]...)
		cmd.Stdout = os.Stdout
		cmd.Stdin = os.Stdin
		cmd.Stderr = os.Stderr
		e := cmd.Run()
		return e
	}
	return nil
}

func isBuiltIn(cmd string) bool {
	_, ok := Builtins[cmd]
	return ok
}
<commit_msg>Shell: Bugfix: Crash on empty line<commit_after>package shell

import (
	"bufio"
	"common"
	"exec"
	"os"
	"strings"
)

func Shell(call []string) os.Error {
	var in *bufio.Reader
	if len(call) > 2 {
		call = call[0:1]
	}
	if len(call) == 2 {
		f, e := os.Open(call[1])
		if e != nil {
			return e
		}
		defer f.Close()
		in = bufio.NewReader(f)
	} else {
		in = bufio.NewReader(os.Stdin)
	}

	var e os.Error
	var line string
	for e == nil {
		print("> ")
		line, e = getNextLine(in)
		if e != nil {
			return e
		}
		if isComment(line) {
			continue
		}
		params, ce := parameterize(line)
		if ce != nil {
			common.DumpError(ce)
			continue
		}
		ce = execute(params)
		if ce != nil {
			common.DumpError(ce)
			continue
		}
	}
	return nil
}

func isComment(line string) bool {
	line = strings.TrimSpace(line)
	return strings.HasPrefix(line, "#")
}

func execute(cmd []string) os.Error {
	if len(cmd) == 0 {
		return nil
	}
	if isBuiltIn(cmd[0]) {
		builtin := Builtins[cmd[0]]
		return builtin(cmd)
	} else {
		cmd := exec.Command(cmd[0], cmd[1:]...)
		cmd.Stdout = os.Stdout
		cmd.Stdin = os.Stdin
		cmd.Stderr = os.Stderr
		e := cmd.Run()
		return e
	}
	return nil
}

func isBuiltIn(cmd string) bool {
	_, ok := Builtins[cmd]
	return ok
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/xyproto/browserspeak"
	"github.com/xyproto/genericsite"
	"github.com/xyproto/instapage"
	"github.com/xyproto/siteengines"
	"github.com/xyproto/web"
)

const JQUERY_VERSION = "2.0.0"

func hello(val string) string {
	return instapage.Message("root page", "hello: "+val)
}

func helloHandle(ctx *web.Context, name string) string {
	return "Hello, " + name
}

func notFound2(ctx *web.Context, val string) {
	ctx.ResponseWriter.WriteHeader(404)
	ctx.ResponseWriter.Write([]byte(browserspeak.NotFound(ctx, val)))
}

func ServeEngines(userState *genericsite.UserState, mainMenuEntries genericsite.MenuEntries) {
	// The user engine
	userEngine := siteengines.NewUserEngine(userState)
	userEngine.ServePages()

	// The admin engine
	adminEngine := siteengines.NewAdminEngine(userState)
	adminEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// TODO: Move this one to roboticoverlords instead
	// The dynamic IP webpage (returns an *IPState)
	ipEngine := siteengines.NewIPEngine(userState)
	ipEngine.ServePages()

	// The chat system (see also the menu entry in ArchBaseCP)
	chatEngine := siteengines.NewChatEngine(userState)
	chatEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Wiki engine
	wikiEngine := siteengines.NewWikiEngine(userState)
	wikiEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Blog engine
	//blogEngine := NewBlogEngine(userState)
	//blogEngine.ServePages(ArchBaseCP, mainMenuEntries)
}

// TODO: One database per site
func main() {

	// UserState with a Redis Connection Pool
	userState := genericsite.NewUserState()
	defer userState.Close()

	// The archlinux.no webpage,
	mainMenuEntries := ServeArchlinuxNo(userState, "/js/jquery-"+JQUERY_VERSION+".min.js")

	ServeEngines(userState, mainMenuEntries)

	// Compilation errors, vim-compatible filename
	web.Get("/error", browserspeak.GenerateErrorHandle("errors.err"))
	web.Get("/errors", browserspeak.GenerateErrorHandle("errors.err"))

	// Various .php and .asp urls that showed up in the log
	genericsite.ServeForFun()

	// TODO: Incorporate this check into web.go, to only return
	// stuff in the header when the HEAD method is requested:
	// if ctx.Request.Method == "HEAD" { return }
	// See also: curl -I

	// Serve on port 3000 for the Nginx instance to use
	web.Run("0.0.0.0:3000")
}
<commit_msg>Custom domain<commit_after>package main

import (
	"github.com/xyproto/browserspeak"
	"github.com/xyproto/genericsite"
	"github.com/xyproto/instapage"
	"github.com/xyproto/siteengines"
	"github.com/xyproto/web"
)

const JQUERY_VERSION = "2.0.0"

func hello(val string) string {
	return instapage.Message("root page", "hello: "+val)
}

func helloHandle(ctx *web.Context, name string) string {
	return "Hello, " + name
}

func notFound2(ctx *web.Context, val string) {
	ctx.ResponseWriter.WriteHeader(404)
	ctx.ResponseWriter.Write([]byte(browserspeak.NotFound(ctx, val)))
}

func ServeEngines(userState *genericsite.UserState, mainMenuEntries genericsite.MenuEntries) {
	// The user engine
	userEngine := siteengines.NewUserEngine(userState)
	userEngine.ServePages("archlinux.no")

	// The admin engine
	adminEngine := siteengines.NewAdminEngine(userState)
	adminEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// TODO: Move this one to roboticoverlords instead
	// The dynamic IP webpage (returns an *IPState)
	ipEngine := siteengines.NewIPEngine(userState)
	ipEngine.ServePages()

	// The chat system (see also the menu entry in ArchBaseCP)
	chatEngine := siteengines.NewChatEngine(userState)
	chatEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Wiki engine
	wikiEngine := siteengines.NewWikiEngine(userState)
	wikiEngine.ServePages(ArchBaseCP, mainMenuEntries)

	// Blog engine
	//blogEngine := NewBlogEngine(userState)
	//blogEngine.ServePages(ArchBaseCP, mainMenuEntries)
}

// TODO: One database per site
func main() {

	// UserState with a Redis Connection Pool
	userState := genericsite.NewUserState()
	defer userState.Close()

	// The archlinux.no webpage,
	mainMenuEntries := ServeArchlinuxNo(userState, "/js/jquery-"+JQUERY_VERSION+".min.js")

	ServeEngines(userState, mainMenuEntries)

	// Compilation errors, vim-compatible filename
	web.Get("/error", browserspeak.GenerateErrorHandle("errors.err"))
	web.Get("/errors", browserspeak.GenerateErrorHandle("errors.err"))

	// Various .php and .asp urls that showed up in the log
	genericsite.ServeForFun()

	// TODO: Incorporate this check into web.go, to only return
	// stuff in the header when the HEAD method is requested:
	// if ctx.Request.Method == "HEAD" { return }
	// See also: curl -I

	// Serve on port 3000 for the Nginx instance to use
	web.Run("0.0.0.0:3000")
}
<|endoftext|>


<commit_before>package main

const (
	DefaultCacheDir = "/var/risu/cache"
)
<commit_msg>Remove const.go and integrate to risu.go<commit_after><|endoftext|>


<commit_before>package main

const NGINX_BUILD_VERSION = "0.2.0"

// nginx
const (
	NGINX_VERSION             = "1.7.9"
	NGINX_DOWNLOAD_URL_PREFIX = "http://nginx.org/download"
)

// pcre
const (
	PCRE_VERSION             = "8.36"
	PCRE_DOWNLOAD_URL_PREFIX = "http://ftp.csx.cam.ac.uk/pub/software/programming/pcre"
)

// openssl
const (
	OPENSSL_VERSION             = "1.0.1k"
	OPENSSL_DOWNLOAD_URL_PREFIX = "http://www.openssl.org/source"
)

// zlib
const (
	ZLIB_VERSION             = "1.2.8"
	ZLIB_DOWNLOAD_URL_PREFIX = "http://zlib.net"
)

// openResty
const (
	OPENRESTY_VERSION             = "1.7.7.1"
	OPENRESTY_DOWNLOAD_URL_PREFIX = "http://openresty.org/download"
)

// component enumerations
const (
	COMPONENT_NGINX = iota
	COMPONENT_OPENRESTY
	COMPONENT_PCRE
	COMPONENT_OPENSSL
	COMPONENT_ZLIB
	COMPONENT_MAX
)
<commit_msg>bumped version to 0.2.1.<commit_after>package main

const NGINX_BUILD_VERSION = "0.2.1"

// nginx
const (
	NGINX_VERSION             = "1.7.9"
	NGINX_DOWNLOAD_URL_PREFIX = "http://nginx.org/download"
)

// pcre
const (
	PCRE_VERSION             = "8.36"
	PCRE_DOWNLOAD_URL_PREFIX = "http://ftp.csx.cam.ac.uk/pub/software/programming/pcre"
)

// openssl
const (
	OPENSSL_VERSION             = "1.0.1k"
	OPENSSL_DOWNLOAD_URL_PREFIX = "http://www.openssl.org/source"
)

// zlib
const (
	ZLIB_VERSION             = "1.2.8"
	ZLIB_DOWNLOAD_URL_PREFIX = "http://zlib.net"
)

// openResty
const (
	OPENRESTY_VERSION             = "1.7.7.1"
	OPENRESTY_DOWNLOAD_URL_PREFIX = "http://openresty.org/download"
)

// component enumerations
const (
	COMPONENT_NGINX = iota
	COMPONENT_OPENRESTY
	COMPONENT_PCRE
	COMPONENT_OPENSSL
	COMPONENT_ZLIB
	COMPONENT_MAX
)
<|endoftext|>


<commit_before>package prifi

/*
* This is the internal part of the API. As probably the prifi-service will
* not have an external API, this will not have any API-functions.
 */

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"strconv"
	"errors"

	"github.com/dedis/cothority/app/lib/config"
	"github.com/dedis/cothority/log"
	"github.com/dedis/cothority/network"
	"github.com/dedis/cothority/sda"
	"github.com/lbarman/prifi_dev/sda/protocols"
)

// ServiceName is the name to refer to the Template service from another
// package.
const ServiceName = "PrifiService"

var serviceID sda.ServiceID

// Register Service with SDA
func init() {
	sda.RegisterNewService(ServiceName, newService)
	serviceID = sda.ServiceFactory.ServiceID(ServiceName)
	network.RegisterPacketType(ConnectionResponse{})
}

type WaitQueue struct {
	nTrustee int
	nClient int
}

// This struct contains the state of the service
type Service struct {
	// We need to embed the ServiceProcessor, so that incoming messages
	// are correctly handled.
	*sda.ServiceProcessor
	group *config.Group
	Storage *Storage
	path    string
	role prifi.PriFiRole
	identityMap *map[network.Address]prifi.PriFiIdentity
	relayIdentity *network.ServerIdentity
	waitQueue *WaitQueue
	prifiWrapper *prifi.PriFiSDAWrapper
	isPrifiRunning bool
}

// This structure will be saved, on the contrary of the 'Service'-structure
// which has per-service information stored
type Storage struct {
	TrusteeID string
}

type ConnectionRequest struct {
	Role prifi.PriFiRole
}
type DisconnectionRequest struct {}
type ConnectionResponse struct {
	Status bool
}

/*
func (s *Service) HandleISM(from *network.ServerIdentity, msg *sda.InterServiceMessage) (network.Body, error) {
	log.Info(">>> Message received ! <<<")
	return ConnectionResponse{true}, nil
}
*/

// HandleConnection receives connection requests from other nodes.
// It decides when another PriFi protocol should be started.
func (s *Service) HandleConnection(from *network.ServerIdentity, req *ConnectionRequest) (network.Body, error) {
	log.Info(">>>Received connection request<<<")

	if s.role != prifi.Relay {
		return nil, errors.New("This host is not the relay.")
	}

	// No integrity checks are performed here for simplicity.
	// If a client sends a connection request with a role which
	// is not it's own or sends multiple connection requests,
	// this will be detected when the PriFi protocol attempts to start.
	switch req.Role {
	case prifi.Client: s.waitQueue.nClient++
	case prifi.Trustee: s.waitQueue.nTrustee++
	default: log.Error("Connection request from invalid node, ignoring")
	}

	if s.waitQueue.nClient >= 2 && s.waitQueue.nTrustee >= 1 {
		if s.isPrifiRunning {
			s.stopPriFi()
		}

		s.startPriFi()
	}

	return &ConnectionResponse{true}, nil
}

// HandleDisconnection receives disconnection requests.
// It must stop the current PriFi protocol.
func (s *Service) HandleDisconnection(from *network.ServerIdentity, req *DisconnectionRequest) (network.Body, error) {
	// TODO: This one will be a bit more complicated
	return &ConnectionResponse{true}, nil
}

// StartTrustee has to take a configuration and start the necessary
// protocols to enable the trustee-mode.
func (s *Service) StartTrustee(group *config.Group) error {
	log.Info("Service", s, "running in trustee mode")
	s.role = prifi.Trustee
	s.readGroup(group)

	// Inform the relay that we want to join the protocol
	err := s.sendConnectionRequest()
	if err != nil {
		log.Error("Connection failed:", err)
	}

	return nil
}

// StartRelay has to take a configuration and start the necessary
// protocols to enable the relay-mode.
func (s *Service) StartRelay(group *config.Group) error {
	log.Info("Service", s, "running in relay mode")
	s.role = prifi.Relay
	s.readGroup(group)
	s.waitQueue = &WaitQueue{0, 0}

	return nil
}

// StartClient has to take a configuration and start the necessary
// protocols to enable the client-mode.
func (s *Service) StartClient(group *config.Group) error {
	log.Info("Service", s, "running in client mode")
	s.role = prifi.Client
	s.readGroup(group)

	// Inform the relay that we want to join the protocol
	err := s.sendConnectionRequest()
	if err != nil {
		log.Error("Connection failed:", err)
	}

	return nil
}

// NewProtocol is called on all nodes of a Tree (except the root, since it is
// the one starting the protocol) so it's the Service that will be called to
// generate the PI on all others node.
// If you use CreateProtocolSDA, this will not be called, as the SDA will
// instantiate the protocol on its own. If you need more control at the
// instantiation of the protocol, use CreateProtocolService, and you can
// give some extra-configuration to your protocol in here.
func (s *Service) NewProtocol(tn *sda.TreeNodeInstance, conf *sda.GenericConfig) (sda.ProtocolInstance, error) {
	log.Lvl5("Setting node configuration from service")

	pi, err := prifi.NewPriFiSDAWrapperProtocol(tn)
	if err != nil {
		return nil, err
	}

	// Assert that pi has type PriFiSDAWrapper
	wrapper := pi.(*prifi.PriFiSDAWrapper)

	wrapper.SetConfig(&prifi.PriFiSDAWrapperConfig{
		Identities: *s.identityMap,
		Role: s.role,
	})

	return wrapper, nil
}

// saves the actual identity
func (s *Service) save() {
	log.Lvl3("Saving service")
	b, err := network.MarshalRegisteredType(s.Storage)
	if err != nil {
		log.Error("Couldn't marshal service:", err)
	} else {
		err = ioutil.WriteFile(s.path+"/prifi.bin", b, 0660)
		if err != nil {
			log.Error("Couldn't save file:", err)
		}
	}
}

// Tries to load the configuration and updates if a configuration
// is found, else it returns an error.
func (s *Service) tryLoad() error {
	configFile := s.path + "/identity.bin"
	b, err := ioutil.ReadFile(configFile)
	if err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("Error while reading %s: %s", configFile, err)
	}
	if len(b) > 0 {
		_, msg, err := network.UnmarshalRegistered(b)
		if err != nil {
			return fmt.Errorf("Couldn't unmarshal: %s", err)
		}
		log.Lvl3("Successfully loaded")
		s.Storage = msg.(*Storage)
	}
	return nil
}

// newService receives the context and a path where it can write its
// configuration, if desired. As we don't know when the service will exit,
// we need to save the configuration on our own from time to time.
func newService(c *sda.Context, path string) sda.Service {
	log.Lvl4("Calling newService")
	s := &Service{
		ServiceProcessor: sda.NewServiceProcessor(c),
		path:             path,
		isPrifiRunning:   false,
	}
	if err := s.tryLoad(); err != nil {
		log.Error(err)
	}
	if err:= s.RegisterMessage(/*s.HandleConnection, s.HandleDisconnection, */s.HandleISM); err != nil {
		log.Fatal("Could not register handlers:", err)
	}
	return s
}

// parseDescription extracts a PriFiIdentity from a string
func parseDescription(description string) (*prifi.PriFiIdentity, error) {
	desc := strings.Split(description, " ")
	if len(desc) == 1 && desc[0] == "relay" {
		return &prifi.PriFiIdentity{
			Role: prifi.Relay,
			Id: 0,
		}, nil
	} else if len(desc) == 2 {
		id, err := strconv.Atoi(desc[1]); if err != nil {
			return nil, errors.New("Unable to parse id:")
		} else {
			pid := prifi.PriFiIdentity{
				Id: id,
			}
			if desc[0] == "client" {
				pid.Role = prifi.Client
			} else if  desc[0] == "trustee" {
				pid.Role = prifi.Trustee
			} else {
				return nil, errors.New("Invalid role.")
			}
			return &pid, nil
		}
	} else {
		return nil, errors.New("Invalid description.")
	}
}

// mapIdentities reads the group configuration to assign PriFi roles
// to server addresses and returns them with the server
// identity of the relay.
func mapIdentities(group *config.Group) (map[network.Address]prifi.PriFiIdentity, network.ServerIdentity) {
	m := make(map[network.Address]prifi.PriFiIdentity)
	var relay network.ServerIdentity

	// Read the description of the nodes in the config file to assign them PriFi roles.
	nodeList := group.Roster.List
	for i := 0; i < len(nodeList); i++ {
		si := nodeList[i]
		id, err := parseDescription(group.GetDescription(si))
		if err != nil {
			log.Info("Cannot parse node description, skipping:", err)
		} else {
			m[si.Address] = *id
			if id.Role == prifi.Relay {
				relay = *si
			}
		}
	}

	// Check that there is exactly one relay and at least one trustee and client
	t, c, r := 0, 0, 0

	for _, v := range m {
		switch v.Role {
		case prifi.Relay: r++
		case prifi.Client: c++
		case prifi.Trustee: t++
		}
	}

	if !(t > 0 && c > 0 && r == 1) {
		log.Fatal("Config file does not contain exactly one relay and at least one trustee and client.")
	}

	return m, relay
}

// readGroup reads the group description and sets up the Service struct fields
// accordingly. It *MUST* be called first when the node is started.
func (s *Service) readGroup(group *config.Group) {
	ids, relayId := mapIdentities(group)
	s.identityMap = &ids
	s.relayIdentity = &relayId
	s.group = group
}

// sendConnectionRequest sends a connection request to the relay.
// It is called by the client and trustee services at startup to
// announce themselves to the relay.
func (s *Service) sendConnectionRequest() error {
	// TODO: This should be modified to use ISM messages
	msg := &ConnectionRequest{s.role}
	err := s.SendISM(s.relayIdentity, msg)
	return err
}

/*client := sda.NewClient(ServiceName)
s.ServerIdentity()
reply, err := client.Send(s.relayIdentity, &ConnectionRequest{s.role})
if e := network.ErrMsg(reply, err); e != nil {
	return e
} else {
	res := reply.Msg.(ConnectionResponse)

	if res.Status {
		return nil
	} else {
		return errors.New("Connection request refused by the relay.")
	}
}
return err*/

// startPriFi starts a PriFi protocol. It is called
// by the relay as soon as enough participants are
// ready (one trustee and two clients).
func (s *Service) startPriFi() {
	if s.role != prifi.Relay {
		log.Error("Trying to start PriFi protocol from a non-relay node.")
		return;
	}

	var wrapper *prifi.PriFiSDAWrapper

	// Start the PriFi protocol on a flat tree with the relay as root
	tree := s.group.Roster.GenerateNaryTreeWithRoot(100, s.relayIdentity)
	pi, err := s.CreateProtocolService(prifi.ProtocolName, tree)

	if err != nil {
		log.Fatal("Unable to start Prifi protocol:", err)
	}

	// Assert that pi has type PriFiSDAWrapper
	wrapper = pi.(*prifi.PriFiSDAWrapper)
	s.prifiWrapper = wrapper

	wrapper.SetConfig(&prifi.PriFiSDAWrapperConfig{
		Identities: *s.identityMap,
		Role: prifi.Relay,
	})
	wrapper.Start()

	s.isPrifiRunning = true;
}

func (s *Service) stopPriFi() {
	if s.role != prifi.Relay {
		log.Error("Trying to stop PriFi protocol from a non-relay node.")
		return;
	}

	if !s.isPrifiRunning || s.prifiWrapper == nil {
		log.Error("Trying to stop PriFi protocol but it has not started.")
		return;
	}

	s.prifiWrapper.Stop()
	s.prifiWrapper = nil
	s.isPrifiRunning = false;
}
<commit_msg>Fixed compile errors<commit_after>package prifi

/*
* This is the internal part of the API. As probably the prifi-service will
* not have an external API, this will not have any API-functions.
 */

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"strconv"
	"errors"

	"github.com/dedis/cothority/app/lib/config"
	"github.com/dedis/cothority/log"
	"github.com/dedis/cothority/network"
	"github.com/dedis/cothority/sda"
	"github.com/lbarman/prifi_dev/sda/protocols"
)

// ServiceName is the name to refer to the Template service from another
// package.
const ServiceName = "PrifiService"

var serviceID sda.ServiceID

// Register Service with SDA
func init() {
	sda.RegisterNewService(ServiceName, newService)
	serviceID = sda.ServiceFactory.ServiceID(ServiceName)
	network.RegisterPacketType(ConnectionResponse{})
}

type WaitQueue struct {
	nTrustee int
	nClient int
}

// This struct contains the state of the service
type Service struct {
	// We need to embed the ServiceProcessor, so that incoming messages
	// are correctly handled.
	*sda.ServiceProcessor
	group *config.Group
	Storage *Storage
	path    string
	role prifi.PriFiRole
	identityMap *map[network.Address]prifi.PriFiIdentity
	relayIdentity *network.ServerIdentity
	waitQueue *WaitQueue
	prifiWrapper *prifi.PriFiSDAWrapper
	isPrifiRunning bool
}

// This structure will be saved, on the contrary of the 'Service'-structure
// which has per-service information stored
type Storage struct {
	TrusteeID string
}

type ConnectionRequest struct {
	Role prifi.PriFiRole
}
type DisconnectionRequest struct {}
type ConnectionResponse struct {
	Status bool
}

/*
func (s *Service) HandleISM(from *network.ServerIdentity, msg *sda.InterServiceMessage) (network.Body, error) {
	log.Info(">>> Message received ! <<<")
	return ConnectionResponse{true}, nil
}
*/

// HandleConnection receives connection requests from other nodes.
// It decides when another PriFi protocol should be started.
func (s *Service) HandleConnection(from *network.ServerIdentity, req *ConnectionRequest) (network.Body, error) {
	log.Info(">>>Received connection request<<<")

	if s.role != prifi.Relay {
		return nil, errors.New("This host is not the relay.")
	}

	// No integrity checks are performed here for simplicity.
	// If a client sends a connection request with a role which
	// is not it's own or sends multiple connection requests,
	// this will be detected when the PriFi protocol attempts to start.
	switch req.Role {
	case prifi.Client: s.waitQueue.nClient++
	case prifi.Trustee: s.waitQueue.nTrustee++
	default: log.Error("Connection request from invalid node, ignoring")
	}

	if s.waitQueue.nClient >= 2 && s.waitQueue.nTrustee >= 1 {
		if s.isPrifiRunning {
			s.stopPriFi()
		}

		s.startPriFi()
	}

	return &ConnectionResponse{true}, nil
}

// HandleDisconnection receives disconnection requests.
// It must stop the current PriFi protocol.
func (s *Service) HandleDisconnection(from *network.ServerIdentity, req *DisconnectionRequest) (network.Body, error) {
	// TODO: This one will be a bit more complicated
	return &ConnectionResponse{true}, nil
}

// StartTrustee has to take a configuration and start the necessary
// protocols to enable the trustee-mode.
func (s *Service) StartTrustee(group *config.Group) error {
	log.Info("Service", s, "running in trustee mode")
	s.role = prifi.Trustee
	s.readGroup(group)

	// Inform the relay that we want to join the protocol
	err := s.sendConnectionRequest()
	if err != nil {
		log.Error("Connection failed:", err)
	}

	return nil
}

// StartRelay has to take a configuration and start the necessary
// protocols to enable the relay-mode.
func (s *Service) StartRelay(group *config.Group) error {
	log.Info("Service", s, "running in relay mode")
	s.role = prifi.Relay
	s.readGroup(group)
	s.waitQueue = &WaitQueue{0, 0}

	return nil
}

// StartClient has to take a configuration and start the necessary
// protocols to enable the client-mode.
func (s *Service) StartClient(group *config.Group) error {
	log.Info("Service", s, "running in client mode")
	s.role = prifi.Client
	s.readGroup(group)

	// Inform the relay that we want to join the protocol
	err := s.sendConnectionRequest()
	if err != nil {
		log.Error("Connection failed:", err)
	}

	return nil
}

// NewProtocol is called on all nodes of a Tree (except the root, since it is
// the one starting the protocol) so it's the Service that will be called to
// generate the PI on all others node.
// If you use CreateProtocolSDA, this will not be called, as the SDA will
// instantiate the protocol on its own. If you need more control at the
// instantiation of the protocol, use CreateProtocolService, and you can
// give some extra-configuration to your protocol in here.
func (s *Service) NewProtocol(tn *sda.TreeNodeInstance, conf *sda.GenericConfig) (sda.ProtocolInstance, error) {
	log.Lvl5("Setting node configuration from service")

	pi, err := prifi.NewPriFiSDAWrapperProtocol(tn)
	if err != nil {
		return nil, err
	}

	// Assert that pi has type PriFiSDAWrapper
	wrapper := pi.(*prifi.PriFiSDAWrapper)

	wrapper.SetConfig(&prifi.PriFiSDAWrapperConfig{
		Identities: *s.identityMap,
		Role: s.role,
	})

	return wrapper, nil
}

// saves the actual identity
func (s *Service) save() {
	log.Lvl3("Saving service")
	b, err := network.MarshalRegisteredType(s.Storage)
	if err != nil {
		log.Error("Couldn't marshal service:", err)
	} else {
		err = ioutil.WriteFile(s.path+"/prifi.bin", b, 0660)
		if err != nil {
			log.Error("Couldn't save file:", err)
		}
	}
}

// Tries to load the configuration and updates if a configuration
// is found, else it returns an error.
func (s *Service) tryLoad() error {
	configFile := s.path + "/identity.bin"
	b, err := ioutil.ReadFile(configFile)
	if err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("Error while reading %s: %s", configFile, err)
	}
	if len(b) > 0 {
		_, msg, err := network.UnmarshalRegistered(b)
		if err != nil {
			return fmt.Errorf("Couldn't unmarshal: %s", err)
		}
		log.Lvl3("Successfully loaded")
		s.Storage = msg.(*Storage)
	}
	return nil
}

// newService receives the context and a path where it can write its
// configuration, if desired. As we don't know when the service will exit,
// we need to save the configuration on our own from time to time.
func newService(c *sda.Context, path string) sda.Service {
	log.Lvl4("Calling newService")
	s := &Service{
		ServiceProcessor: sda.NewServiceProcessor(c),
		path:             path,
		isPrifiRunning:   false,
	}
	if err := s.tryLoad(); err != nil {
		log.Error(err)
	}
	if err:= s.RegisterMessages(s.HandleConnection, s.HandleDisconnection/*, s.HandleISM*/); err != nil {
		log.Fatal("Could not register handlers:", err)
	}
	return s
}

// parseDescription extracts a PriFiIdentity from a string
func parseDescription(description string) (*prifi.PriFiIdentity, error) {
	desc := strings.Split(description, " ")
	if len(desc) == 1 && desc[0] == "relay" {
		return &prifi.PriFiIdentity{
			Role: prifi.Relay,
			Id: 0,
		}, nil
	} else if len(desc) == 2 {
		id, err := strconv.Atoi(desc[1]); if err != nil {
			return nil, errors.New("Unable to parse id:")
		} else {
			pid := prifi.PriFiIdentity{
				Id: id,
			}
			if desc[0] == "client" {
				pid.Role = prifi.Client
			} else if  desc[0] == "trustee" {
				pid.Role = prifi.Trustee
			} else {
				return nil, errors.New("Invalid role.")
			}
			return &pid, nil
		}
	} else {
		return nil, errors.New("Invalid description.")
	}
}

// mapIdentities reads the group configuration to assign PriFi roles
// to server addresses and returns them with the server
// identity of the relay.
func mapIdentities(group *config.Group) (map[network.Address]prifi.PriFiIdentity, network.ServerIdentity) {
	m := make(map[network.Address]prifi.PriFiIdentity)
	var relay network.ServerIdentity

	// Read the description of the nodes in the config file to assign them PriFi roles.
	nodeList := group.Roster.List
	for i := 0; i < len(nodeList); i++ {
		si := nodeList[i]
		id, err := parseDescription(group.GetDescription(si))
		if err != nil {
			log.Info("Cannot parse node description, skipping:", err)
		} else {
			m[si.Address] = *id
			if id.Role == prifi.Relay {
				relay = *si
			}
		}
	}

	// Check that there is exactly one relay and at least one trustee and client
	t, c, r := 0, 0, 0

	for _, v := range m {
		switch v.Role {
		case prifi.Relay: r++
		case prifi.Client: c++
		case prifi.Trustee: t++
		}
	}

	if !(t > 0 && c > 0 && r == 1) {
		log.Fatal("Config file does not contain exactly one relay and at least one trustee and client.")
	}

	return m, relay
}

// readGroup reads the group description and sets up the Service struct fields
// accordingly. It *MUST* be called first when the node is started.
func (s *Service) readGroup(group *config.Group) {
	ids, relayId := mapIdentities(group)
	s.identityMap = &ids
	s.relayIdentity = &relayId
	s.group = group
}

// sendConnectionRequest sends a connection request to the relay.
// It is called by the client and trustee services at startup to
// announce themselves to the relay.
func (s *Service) sendConnectionRequest() error {
	// TODO: This should be modified to use ISM messages
	msg := &ConnectionRequest{s.role}
	err := s.SendISM(s.relayIdentity, msg)
	return err
}

/*client := sda.NewClient(ServiceName)
s.ServerIdentity()
reply, err := client.Send(s.relayIdentity, &ConnectionRequest{s.role})
if e := network.ErrMsg(reply, err); e != nil {
	return e
} else {
	res := reply.Msg.(ConnectionResponse)

	if res.Status {
		return nil
	} else {
		return errors.New("Connection request refused by the relay.")
	}
}
return err*/

// startPriFi starts a PriFi protocol. It is called
// by the relay as soon as enough participants are
// ready (one trustee and two clients).
func (s *Service) startPriFi() {
	if s.role != prifi.Relay {
		log.Error("Trying to start PriFi protocol from a non-relay node.")
		return;
	}

	var wrapper *prifi.PriFiSDAWrapper

	// Start the PriFi protocol on a flat tree with the relay as root
	tree := s.group.Roster.GenerateNaryTreeWithRoot(100, s.relayIdentity)
	pi, err := s.CreateProtocolService(prifi.ProtocolName, tree)

	if err != nil {
		log.Fatal("Unable to start Prifi protocol:", err)
	}

	// Assert that pi has type PriFiSDAWrapper
	wrapper = pi.(*prifi.PriFiSDAWrapper)
	s.prifiWrapper = wrapper

	wrapper.SetConfig(&prifi.PriFiSDAWrapperConfig{
		Identities: *s.identityMap,
		Role: prifi.Relay,
	})
	wrapper.Start()

	s.isPrifiRunning = true;
}

func (s *Service) stopPriFi() {
	if s.role != prifi.Relay {
		log.Error("Trying to stop PriFi protocol from a non-relay node.")
		return;
	}

	if !s.isPrifiRunning || s.prifiWrapper == nil {
		log.Error("Trying to stop PriFi protocol but it has not started.")
		return;
	}

	s.prifiWrapper.Stop()
	s.prifiWrapper = nil
	s.isPrifiRunning = false;
}
<|endoftext|>


<commit_before>package dsalg

type AVLTreeNode struct {
	leftChild, rightChild *AVLTreeNode
	value                 interface{}
	count                 int
	// The height of **this** node counting from the left / the right.
	// The height of a non-existing (nil) node is defined to be -1.
	// The height of a leaf node is 0.
	leftHeight, rightHeight int
}

func (node *AVLTreeNode) LeftChild() *AVLTreeNode {
	return node.leftChild
}

func (node *AVLTreeNode) RightChild() *AVLTreeNode {
	return node.rightChild
}

func (node *AVLTreeNode) Value() interface{} {
	return node.value
}

func (node *AVLTreeNode) Count() int {
	return node.count
}

// Height returns the height of this node, i.e. the maximum of its left height and right height.
// A nil node has a height of -1, while a leaf node has a height of 0.
func (node *AVLTreeNode) Height() int {
	if node == nil {
		return -1
	}
	return max(node.leftHeight, node.rightHeight)
}

// UpdateHeight updates the height of this node.
// TODO: Benchmark to see whether this or the next implementation is faster
/*
func (node *AVLTreeNode) UpdateHeight(d direction) {
	if node == nil {
		return
	}
	if d == nil || d == left {
		node.leftHeight = node.leftChild.Height() + 1
	}
	if d == nil || d == right {
		node.rightHeight = node.rightChild.Height() + 1
	}
}
*/

func (node *AVLTreeNode) UpdateHeight() {
	node.leftHeight = node.leftChild.Height() + 1
	node.rightHeight = node.rightChild.Height() + 1
}

/*
Left Rotation
-------------
.     P       .       Q     .
.    / \      .      / \    .
.   A   Q    ==>    P   C   .
.      / \    .    / \      .
.     B   C   .   A   B     .
*/
func (node *AVLTreeNode) rotateLeft() *AVLTreeNode {
	newRoot := node.rightChild
	node.rightChild, node.rightChild.leftChild = node.rightChild.leftChild, node
	newRoot.leftChild.UpdateHeight()
	newRoot.UpdateHeight()
	return newRoot
}

/*
Right Rotation
--------------
.       P     .     Q       .
.      / \    .    / \      .
.     Q   C  ==>  A   P     .
.    / \      .      / \    .
.   A   B     .     B   C   .
*/
func (node *AVLTreeNode) rotateRight() *AVLTreeNode {
	newRoot := node.leftChild
	node.leftChild, node.leftChild.rightChild = node.leftChild.rightChild, node
	newRoot.rightChild.UpdateHeight()
	newRoot.UpdateHeight()
	return newRoot
}

// LL Single Rotation
func (node *AVLTreeNode) rotateLL() *AVLTreeNode {
	return node.rotateRight()
}

// RR Single Rotation
func (node *AVLTreeNode) rotateRR() *AVLTreeNode {
	return node.rotateLeft()
}

// LR Double Rotation
func (node *AVLTreeNode) rotateLR() *AVLTreeNode {
	node.leftChild = node.leftChild.rotateLeft()
	return node.rotateRight()
}

// RL Double Rotation
func (node *AVLTreeNode) rotateRL() *AVLTreeNode {
	node.rightChild = node.rightChild.rotateRight()
	return node.rotateLeft()
}

// v: The value to be inserted
// less: The comparison function for the values
// Returns:
// (1) The pointer to the new root of the subtree rooted at "node" after insertion
// (2) The pointer to the node containing the value "v"
// (3) Whether a new node is allocated
// (4) The direction of the recursive call to "insert"
func (node *AVLTreeNode) insert(v interface{}, less func(interface{}, interface{}) bool) (*AVLTreeNode, *AVLTreeNode, bool, direction) {
	if node == nil {
		newNode := &AVLTreeNode{value: v, count: 1}
		return newNode, newNode, true, nil
	}
	if less(v, node.value) {
		newRoot, targetNode, isCreated, dir := node.leftChild.insert(v, less)
		node.leftChild = newRoot
		if !isCreated {
			return node, targetNode, false, left
		}
		node.UpdateHeight()
		if node.leftHeight-node.rightHeight <= 1 {
			return node, targetNode, true, left
		}
		if dir == left {
			return node.rotateLL(), targetNode, true, left
		} else if dir == right {
			return node.rotateLR(), targetNode, true, left
		} else {
			panic("Dirction is nil")
		}
	} else if less(node.value, v) {
		newRoot, targetNode, isCreated, dir := node.rightChild.insert(v, less)
		node.rightChild = newRoot
		if !isCreated {
			return node, targetNode, false, right
		}
		node.UpdateHeight()
		if node.rightHeight-node.leftHeight <= 1 {
			return node, targetNode, true, right
		}
		if dir == left {
			return node.rotateRL(), targetNode, true, right
		} else if dir == right {
			return node.rotateRR(), targetNode, true, right
		} else {
			panic("Dirction is nil")
		}
	} else {
		node.count++
		return node, node, false, nil
	}
}

func (node *AVLTreeNode) TraversePreOrder(consumer func(interface{})) {
	if node == nil {
		return
	}
	for i := 0; i < node.count; i++ {
		consumer(node.value)
	}
	node.leftChild.TraversePreOrder(consumer)
	node.rightChild.TraversePreOrder(consumer)
}

func (node *AVLTreeNode) TraverseInOrder(consumer func(interface{})) {
	if node == nil {
		return
	}
	node.leftChild.TraverseInOrder(consumer)
	for i := 0; i < node.count; i++ {
		consumer(node.value)
	}
	node.rightChild.TraverseInOrder(consumer)
}

func (node *AVLTreeNode) TraversePostOrder(consumer func(interface{})) {
	if node == nil {
		return
	}
	node.leftChild.TraversePostOrder(consumer)
	node.rightChild.TraversePostOrder(consumer)
	for i := 0; i < node.count; i++ {
		consumer(node.value)
	}
}

func (node *AVLTreeNode) Clone() *AVLTreeNode {
	if node == nil {
		return nil
	}
	return &AVLTreeNode{
		node.leftChild.Clone(),
		node.rightChild.Clone(),
		node.value,
		node.count,
		node.leftHeight,
		node.rightHeight,
	}
}

type AVLTree struct {
	less func(interface{}, interface{}) bool
	root *AVLTreeNode
	len  int
	cap  int
}

func NewAVLTree(less func(interface{}, interface{}) bool) *AVLTree {
	return &AVLTree{less: less}
}

func NewIntAVLTree() *AVLTree {
	return &AVLTree{less: IntLess}
}

func NewFloat64AVLTree() *AVLTree {
	return &AVLTree{less: Float64Less}
}

func NewStringAVLTree() *AVLTree {
	return &AVLTree{less: StringLess}
}

func (tree *AVLTree) Insert(v interface{}) *AVLTreeNode {
	newRoot, targetNode, isCreated, _ := tree.root.insert(v, tree.less)
	tree.root = newRoot
	tree.len++
	if isCreated {
		tree.cap++
	}
	return targetNode
}

func (tree *AVLTree) TraversePreOrder(consumer func(interface{})) {
	tree.root.TraversePreOrder(consumer)
}

func (tree *AVLTree) TraverseInOrder(consumer func(interface{})) {
	tree.root.TraverseInOrder(consumer)
}

func (tree *AVLTree) TraversePostOrder(consumer func(interface{})) {
	tree.root.TraversePostOrder(consumer)
}

func (tree *AVLTree) Clone() *AVLTree {
	return &AVLTree{
		tree.less,
		tree.root.Clone(),
		tree.len,
		tree.cap,
	}
}

func (tree *AVLTree) Len() int {
	return tree.len
}

func (tree *AVLTree) Cap() int {
	return tree.cap
}

func (tree *AVLTree) IsEmpty() bool {
	return tree.len == 0
}

func (tree *AVLTree) IsFull() bool {
	return false
}
<commit_msg>Dirty commit<commit_after>package dsalg

// AVLTreeNode is a node of an AVL tree.
type AVLTreeNode struct {
	// Left child and right child pointers in the AVL tree.
	childL, childR *AVLTreeNode

	// The value stored with this node.
	value interface{}

	// The height of this node counting from the left / the right.
	// The height of a non-existing (nil) node is defined to be -1.
	// The height of a leaf node is 0.
	heightL, heightR int
}

func NewAVLTreeNode(childL, childR *AVLTreeNode, v interface{}) *AVLTreeNode {
	return &AVLTreeNode{
		childL,
		childR,
		v,
		childL.Height() + 1,
		childR.Height() + 1,
	}
}

// LeftChild returns the left child of this node or nil.
func (node *AVLTreeNode) LeftChild() *AVLTreeNode {
	return node.childL
}

// RightChild returns the right child of this node or nil.
func (node *AVLTreeNode) RightChild() *AVLTreeNode {
	return node.childR
}

// Value returns the value stored with this node.
func (node *AVLTreeNode) Value() interface{} {
	return node.value
}

// LeftHeight returns the left height of this node.
func (node *AVLTreeNode) LeftHeight() int {
	return node.heightL
}

// RightHeight returns the right height of this node.
func (node *AVLTreeNode) RightHeight() int {
	return node.heightR
}

// Height returns the height of this node,
// i.e. the maximum of its left height and right height.
// The height of a non-existing (nil) node is defined to be -1,
// while the height of a leaf node is 0.
func (node *AVLTreeNode) Height() int {
	if node == nil {
		return -1
	}
	return max(node.heightL, node.heightR)
}

// TODO: Benchmark to see whether this or the next implementation is faster
/*
// UpdateHeight updates the heights of this node.
func (node *AVLTreeNode) UpdateHeight(d direction) {
	if node == nil {
		return
	}
	if d == none || d == left {
		node.heightL = node.childL.Height() + 1
	}
	if d == none || d == right {
		node.heightR = node.childR.Height() + 1
	}
}
*/

// UpdateHeight updates the heights of this node.
func (node *AVLTreeNode) UpdateHeight() {
	node.heightL = node.childL.Height() + 1
	node.heightR = node.childR.Height() + 1
}

/*
rotateLeft performs a left rotation with this node being the root of the rotation.
It returns the new root of the subtree (the pivot).

Left Rotation
-------------
.     R       .       P     .
.    / \      .      / \    .
.   A   P    ==>    R   C   .
.      / \    .    / \      .
.     B   C   .   A   B     .
*/
func (root *AVLTreeNode) rotateLeft() *AVLTreeNode {
	pivot := root.childR
	root.childR, pivot.childL = pivot.childL, root
	pivot.childL.UpdateHeight()
	pivot.UpdateHeight()
	return pivot
}

/*
rotateRight performs a right rotation with this node being the root of the rotation.
It returns the new root of the subtree (the pivot).

Right Rotation
--------------
.       R     .     P       .
.      / \    .    / \      .
.     P   C  ==>  A   R     .
.    / \      .      / \    .
.   A   B     .     B   C   .
*/
func (root *AVLTreeNode) rotateRight() *AVLTreeNode {
	pivot := root.childL
	root.childL, pivot.childR = pivot.childR, root
	pivot.childR.UpdateHeight()
	pivot.UpdateHeight()
	return pivot
}

/*
rotateLL performs an LL-rotation with this node being the root of the rotation.
It returns the new root of the subtree (the pivot of the rotation).

LL Single Rotation
------------------
.         R     .                   .
.        / \    .         P         .
.       P   D   .      +-/ \-+      .
.      / \     ==>    Q       R     .
.     Q   C     .    / \     / \    .
.    / \        .   A   B   C   D   .
.   A   B       .                   .
*/
func (root *AVLTreeNode) rotateLL() *AVLTreeNode {
	return root.rotateRight()
}

/*
rotateRR performs an RR-rotation with this node being the root of the rotation.
It returns the new root of the subtree (the pivot of the rotation).

RR Single Rotation
------------------
.     R         .                   .
.    / \        .         P         .
.   A   P       .      +-/ \-+      .
.      / \     ==>    R       Q     .
.     B   Q     .    / \     / \    .
.        / \    .   A   B   C   D   .
.       C   D   .                   .
*/
func (root *AVLTreeNode) rotateRR() *AVLTreeNode {
	return root.rotateLeft()
}

/*
rotateLR performs an LR-rotation with this node being the root of the rotation.
It returns the new root of the subtree.

LR Double Rotation
------------------
.       R     .         R     .                   .
.      / \    .        / \    .         Q         .
.     P   D   .       Q   D   .      +-/ \-+      .
.    / \     ==>     / \     ==>    P       R     .
.   A   Q     .     P   C     .    / \     / \    .
.      / \    .    / \        .   A   B   C   D   .
.     B   C   .   A   B       .                   .
*/
func (root *AVLTreeNode) rotateLR() *AVLTreeNode {
	root.childL = root.childL.rotateLeft()
	return root.rotateRight()
}

/*
rotateRL performs an RL-rotation with this node being the root of the rotation.
It returns the new root of the subtree.

RL Double Rotation
------------------
.     R       .         R     .                   .
.    / \      .        / \    .         Q         .
.   A   P     .       Q   D   .      +-/ \-+      .
.      / \   ==>     / \     ==>    P       R     .
.     Q   D   .     P   C     .    / \     / \    .
.    / \      .    / \        .   A   B   C   D   .
.   B   C     .   A   B       .                   .
*/
func (root *AVLTreeNode) rotateRL() *AVLTreeNode {
	root.childR = root.childR.rotateRight()
	return root.rotateLeft()
}

func (root *AVLTreeNode) balance() *AVLTreeNode {
	if root.heightL-root.heightR > 1 {
		pivot := root.childL
		if pivot.heightL < pivot.heightR {
			// LR
			root.childL = pivot.rotateLeft()
		}
		// LL
		return root.rotateRight()
	} else if root.heightR-root.heightL > 1 {
		pivot := root.childR
		if pivot.heightR < pivot.heightL {
			// RL
			root.childR = pivot.rotateRight()
		}
		// RR
		return root.rotateLeft()
	} else {
		return root
	}
}

// v: The value to be inserted
// less: The comparison function for the values
// Returns:
// (1) The new root of the subtree rooted at this node after insertion;
// (2) The node being inserted (containing the value "v");
// (3) The height of the subtree, or -1 if new node is not created;
// (4) Whether a new node is allocated;
// (5) The direction of the recursive call to "insert".
func (node *AVLTreeNode) insert(v interface{}, less func(interface{}, interface{}) bool) (*AVLTreeNode, *AVLTreeNode, int, flags) {
	if node == nil {
		newNode := &AVLTreeNode{value: v}
		return newNode, newNode, 0, NodeCreated | DirNone
	}
	if less(v, node.value) {
		// Insert
		newChild, targetNode, newHeight, flags := node.childL.insert(v, less)
		node.childL = newChild
		if flags&NodeCreated == 0 {
			return node, targetNode, -1, DirLeft
		}
		// Update Height
		node.heightL = newHeight + 1
		// Check Height
		if node.heightL-node.heightR <= 1 {
			return node, targetNode, node.Height(), NodeCreated | DirLeft
		}
		// Balance
		if flags&DirRight != 0 {
			// LR
			node.childL = newChild.rotateLeft()
		}
		// LL
		newRoot := node.rotateRight()
		return newRoot, targetNode, newRoot.Height(), NodeCreated | DirLeft
	} else if less(node.value, v) {
		// Insert
		newChild, targetNode, newHeight, flags := node.childR.insert(v, less)
		node.childR = newChild
		if flags&NodeCreated == 0 {
			return node, targetNode, -1, DirRight
		}
		// Update Height
		node.heightR = newHeight + 1
		// Check Height
		if node.heightR-node.heightL <= 1 {
			return node, targetNode, node.Height(), NodeCreated | DirRight
		}
		// Balance
		if flags&DirLeft != 0 {
			// RL
			node.childR = newChild.rotateRight()
		}
		// RR
		newRoot := node.rotateLeft()
		return newRoot, targetNode, newRoot.Height(), NodeCreated | DirRight
	} else {
		return node, node, -1, DirNone
	}
}

// Returns:
// (1) The new root of the subtree rooted at this node after deletion
// (2) The node being deleted (containing the maximum value of the subtree)
func (node *AVLTreeNode) deleteMaximum() (*AVLTreeNode, *AVLTreeNode) {
	if node == nil {
		return nil, nil
	}
	if node.childR == nil {
		return node.childL, node
	}
	newRoot, targetNode := node.childR.deleteMaximum()
	node.childR = newRoot
	node.UpdateHeight()
	if node.heightL-node.heightR <= 1 {
		return node, targetNode
	}
	if node.childL.heightL > node.childL.heightR {
		return node.rotateLL(), targetNode
	} else {
		return node.rotateLR(), targetNode
	}
}

// Returns:
// (1) The new root of the subtree rooted at this node after deletion
// (2) The node being deleted (containing the minimum value of the subtree)
func (node *AVLTreeNode) deleteMinimum() (*AVLTreeNode, *AVLTreeNode) {
	if node == nil {
		return nil, nil
	}
	if node.childL == nil {
		return node.childR, node
	}
	newRoot, targetNode := node.childL.deleteMinimum()
	node.childL = newRoot
	node.UpdateHeight()
	if node.heightR-node.heightL <= 1 {
		return node, targetNode
	}
	if node.childR.heightL > node.childR.heightR {
		return node.rotateRL(), targetNode
	} else {
		return node.rotateRR(), targetNode
	}
}

func (node *AVLTreeNode) delete(v interface{}, less func(interface{}, interface{}) bool) (*AVLTreeNode, *AVLTreeNode, bool, bool) {
	if node == nil {
		return nil, nil, false, false
	}
	if less(v, node.value) {
		newRoot, targetNode, isFound, isDeleted := node.childL.delete(v, less)
		if !isFound {
			return node, nil, false, false
		}
		if !isDeleted {
			return node, targetNode, true, false
		}
		node.childL = newRoot
		node.UpdateHeight()
		if node.heightR-node.heightL <= 1 {
			return node, targetNode, true, true
		}
		if node.childR.heightL > node.childR.heightR {
			return node.rotateRL(), targetNode, true, true
		} else {
			return node.rotateRR(), targetNode, true, true
		}
	} else if less(node.value, v) {
		newRoot, targetNode, isFound, isDeleted := node.childR.delete(v, less)
		if !isFound {
			return node, nil, false, false
		}
		if !isDeleted {
			return node, targetNode, true, false
		}
		node.childR = newRoot
		if node.heightL-node.heightR <= 1 {
			return node, targetNode, true, true
		}
		if node.childL.heightL > node.childL.heightR {
			return node.rotateLL(), targetNode, true, true
		} else {
			return node.rotateLR(), targetNode, true, true
		}
		/*
			} else if node.count > 1 {
				node.count--
				return node, node, true, false
		*/
	} else if node.heightL > node.heightR {
		newRoot, maximumNode := node.childL.deleteMaximum()
		maximumNode.childL = newRoot
		maximumNode.childR = node.childR
		maximumNode.UpdateHeight()
		if maximumNode.heightR-maximumNode.heightL <= 1 {
			return maximumNode, node, true, true
		}
		if maximumNode.childR.heightL > maximumNode.childR.heightR {
			return maximumNode.rotateRL(), node, true, true
		} else {
			return maximumNode.rotateRR(), node, true, true
		}
	} else {
		newRoot, minimumNode := node.childR.deleteMinimum()
		minimumNode.childR = newRoot
		minimumNode.childL = node.childL
		minimumNode.UpdateHeight()
		if minimumNode.heightL-minimumNode.heightR <= 1 {
			return minimumNode, node, true, true
		}
		if minimumNode.childL.heightL > minimumNode.childL.heightR {
			return minimumNode.rotateLL(), node, true, true
		} else {
			return minimumNode.rotateLR(), node, true, true
		}
	}
}

func (node *AVLTreeNode) TraversePreOrder(consumer func(interface{})) {
	if node == nil {
		return
	}
	consumer(node.value)
	node.childL.TraversePreOrder(consumer)
	node.childR.TraversePreOrder(consumer)
}

func (node *AVLTreeNode) TraverseInOrder(consumer func(interface{})) {
	if node == nil {
		return
	}
	node.childL.TraverseInOrder(consumer)
	consumer(node.value)
	node.childR.TraverseInOrder(consumer)
}

func (node *AVLTreeNode) TraversePostOrder(consumer func(interface{})) {
	if node == nil {
		return
	}
	node.childL.TraversePostOrder(consumer)
	node.childR.TraversePostOrder(consumer)
	consumer(node.value)
}

func (node *AVLTreeNode) Clone() *AVLTreeNode {
	if node == nil {
		return nil
	}
	return &AVLTreeNode{
		node.childL.Clone(),
		node.childR.Clone(),
		node.value,
		node.heightL,
		node.heightR,
	}
}

type AVLTree struct {
	less func(interface{}, interface{}) bool
	root *AVLTreeNode
	len  int
	cap  int
}

func NewAVLTree(less func(interface{}, interface{}) bool) *AVLTree {
	return &AVLTree{less: less}
}

func NewIntAVLTree() *AVLTree {
	return &AVLTree{less: IntLess}
}

func NewFloat64AVLTree() *AVLTree {
	return &AVLTree{less: Float64Less}
}

func NewStringAVLTree() *AVLTree {
	return &AVLTree{less: StringLess}
}

func (tree *AVLTree) Insert(v interface{}) *AVLTreeNode {
	newRoot, targetNode, _, flags := tree.root.insert(v, tree.less)
	tree.root = newRoot
	tree.len++
	if flags&NodeCreated != 0 {
		tree.cap++
	}
	return targetNode
}

func (tree *AVLTree) TraversePreOrder(consumer func(interface{})) {
	tree.root.TraversePreOrder(consumer)
}

func (tree *AVLTree) TraverseInOrder(consumer func(interface{})) {
	tree.root.TraverseInOrder(consumer)
}

func (tree *AVLTree) TraversePostOrder(consumer func(interface{})) {
	tree.root.TraversePostOrder(consumer)
}

func (tree *AVLTree) Clone() *AVLTree {
	return &AVLTree{
		tree.less,
		tree.root.Clone(),
		tree.len,
		tree.cap,
	}
}

func (tree *AVLTree) Len() int {
	return tree.len
}

func (tree *AVLTree) Cap() int {
	return tree.cap
}

func (tree *AVLTree) IsEmpty() bool {
	return tree.len == 0
}

func (tree *AVLTree) IsFull() bool {
	return false
}
<|endoftext|>


<commit_before>// Package assert provides a number of functions for making assertions in
// tests.
package assert

import (
	"math"
	"reflect"
	"runtime"
	"testing"
)

const (
	epsilon = 1e-8
)

// Equal asserts that two objects are equal.
func Equal(actual, expected interface{}, t *testing.T) {
	var kind reflect.Kind

	if a, e := reflect.TypeOf(actual), reflect.TypeOf(expected); a == nil || e == nil {
		if a != nil || e != nil {
			goto error
		}
		return
	}

	kind = reflect.TypeOf(actual).Kind()

	if kind != reflect.TypeOf(expected).Kind() {
		goto error
	}

	switch kind {
	case reflect.Slice, reflect.Struct, reflect.Ptr:
		if !reflect.DeepEqual(actual, expected) {
			goto error
		}
	default:
		if actual != expected {
			goto error
		}
	}

	return

error:
	raise(t, "got %v (%T) instead of %v (%T)", actual, actual, expected, expected)
}

// AlmostEqual asserts that the absolute difference between two float64 values
// or between the corresponding elements of two []float64 slices is not more
// than a predefined small constant, which is 1e-8.
func AlmostEqual(actual, expected interface{}, t *testing.T) {
	var result bool

	if reflect.TypeOf(actual).Kind() == reflect.Slice {
		result = almostEqual(actual.([]float64), expected.([]float64))
	} else {
		result = almostEqual([]float64{actual.(float64)}, []float64{expected.(float64)})
	}

	if !result {
		raise(t, "got %v instead of %v", actual, expected)
	}
}

// Success asserts that the error is nil.
func Success(err error, t *testing.T) {
	if err != nil {
		raise(t, "got an error '%v'", err)
	}
}

// Success asserts that the error is not nil.
func Failure(err error, t *testing.T) {
	if err == nil {
		raise(t, "expected an error")
	}
}

func almostEqual(actual, expected []float64) bool {
	if len(actual) != len(expected) {
		return false
	}

	for i := range actual {
		if math.Abs(actual[i]-expected[i]) > epsilon {
			return false
		}
	}

	return true
}

func raise(t *testing.T, format string, args ...interface{}) {
	if _, file, line, ok := runtime.Caller(2); ok {
		t.Errorf("%s:%d", file, line)
	}
	t.Fatalf(format, args...)
}
<commit_msg>Love UTF-8!<commit_after>// Package assert provides a number of functions for making assertions in
// tests.
package assert

import (
	"math"
	"reflect"
	"runtime"
	"testing"
)

const (
	ε = 1e-8
)

// Equal asserts that two objects are equal.
func Equal(actual, expected interface{}, t *testing.T) {
	var kind reflect.Kind

	if a, e := reflect.TypeOf(actual), reflect.TypeOf(expected); a == nil || e == nil {
		if a != nil || e != nil {
			goto error
		}
		return
	}

	kind = reflect.TypeOf(actual).Kind()

	if kind != reflect.TypeOf(expected).Kind() {
		goto error
	}

	switch kind {
	case reflect.Slice, reflect.Struct, reflect.Ptr:
		if !reflect.DeepEqual(actual, expected) {
			goto error
		}
	default:
		if actual != expected {
			goto error
		}
	}

	return

error:
	raise(t, "got %v (%T) instead of %v (%T)", actual, actual, expected, expected)
}

// AlmostEqual asserts that the absolute difference between two float64 values
// or between the corresponding elements of two []float64 slices is not more
// than a predefined small constant, which is 1e-8.
func AlmostEqual(actual, expected interface{}, t *testing.T) {
	var result bool

	if reflect.TypeOf(actual).Kind() == reflect.Slice {
		result = almostEqual(actual.([]float64), expected.([]float64))
	} else {
		result = almostEqual([]float64{actual.(float64)}, []float64{expected.(float64)})
	}

	if !result {
		raise(t, "got %v instead of %v", actual, expected)
	}
}

// Success asserts that the error is nil.
func Success(err error, t *testing.T) {
	if err != nil {
		raise(t, "got an error '%v'", err)
	}
}

// Success asserts that the error is not nil.
func Failure(err error, t *testing.T) {
	if err == nil {
		raise(t, "expected an error")
	}
}

func almostEqual(actual, expected []float64) bool {
	if len(actual) != len(expected) {
		return false
	}

	for i := range actual {
		if math.Abs(actual[i]-expected[i]) > ε {
			return false
		}
	}

	return true
}

func raise(t *testing.T, format string, args ...interface{}) {
	if _, file, line, ok := runtime.Caller(2); ok {
		t.Errorf("%s:%d", file, line)
	}
	t.Fatalf(format, args...)
}
<|endoftext|>


<commit_before>package interceptor

import (
	"time"

	"golang.org/x/net/context"

	"github.com/sirupsen/logrus"
	"github.com/namely/mjolnir/logger"
	uuid "github.com/satori/go.uuid"
	"google.golang.org/grpc"
)

// Logger returns an interceptor that will set on the context a *logrus.Entry
// that will automatically be tagged with the request_id UUIDv4.
// It will log the start and end of the request including the duration of
// the call as well.
func Logger(l *logrus.Logger) grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		ctx = addLoggerToContext(l, ctx)
		entry := logger.FromContext(ctx)

		// regex to change /service.Service/Endpt -> Endpt
		name := logger.FormatServiceEndpoint.ReplaceAllString(info.FullMethod, "")

		entry.WithField("endpoint", name).Info("processing rpc")

		start := time.Now()
		out, err := handler(ctx, req)
		if err != nil {
			if ferr, ok := err.(ErrorFielder); ok {
				fields := ferr.Fields()
				entry.WithError(ferr).WithFields(*fields).WithField(
					"core.duration", float64(time.Since(start)) / float64(time.Millisecond),
				).Error("rpc endpoint " + name + " failed")
			} else {
				entry.WithError(err).WithField(
					"core.duration", float64(time.Since(start)) / float64(time.Millisecond),
				).Error("rpc endpoint " + name + " failed")
			}
			return nil, ErrGrpcInternalError
		}

		entry.WithFields(logrus.Fields{
			"endpoint":    name,
			"pb_response": out,
			"core.duration":    float64(time.Since(start)) / float64(time.Millisecond),
		}).Info("finished rpc")

		return out, err
	}
}

func addLoggerToContext(l *logrus.Logger, ctx context.Context) context.Context {
	entry := l.WithField("request_id", uuid.NewV4().String())
	return logger.SetEntry(ctx, entry)
}
<commit_msg>core-963 only override fielderrors, else return standard err (#14)<commit_after>package interceptor

import (
	"time"

	"golang.org/x/net/context"

	"github.com/sirupsen/logrus"
	"github.com/namely/mjolnir/logger"
	uuid "github.com/satori/go.uuid"
	"google.golang.org/grpc"
)

// Logger returns an interceptor that will set on the context a *logrus.Entry
// that will automatically be tagged with the request_id UUIDv4.
// It will log the start and end of the request including the duration of
// the call as well.
func Logger(l *logrus.Logger) grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		ctx = addLoggerToContext(l, ctx)
		entry := logger.FromContext(ctx)

		// regex to change /service.Service/Endpt -> Endpt
		name := logger.FormatServiceEndpoint.ReplaceAllString(info.FullMethod, "")

		entry.WithField("endpoint", name).Info("processing rpc")

		start := time.Now()
		out, err := handler(ctx, req)
		if err != nil {
			if ferr, ok := err.(ErrorFielder); ok {
				fields := ferr.Fields()
				entry.WithError(ferr).WithFields(*fields).WithField(
					"core.duration", float64(time.Since(start)) / float64(time.Millisecond),
				).Error("rpc endpoint " + name + " failed")
				return nil, ErrGrpcInternalError
			}

			entry.WithError(err).WithField(
				"core.duration", float64(time.Since(start)) / float64(time.Millisecond),
			).Error("rpc endpoint " + name + " failed")
			return nil, err
		}

		entry.WithFields(logrus.Fields{
			"endpoint":    name,
			"pb_response": out,
			"core.duration":    float64(time.Since(start)) / float64(time.Millisecond),
		}).Info("finished rpc")

		return out, err
	}
}

func addLoggerToContext(l *logrus.Logger, ctx context.Context) context.Context {
	entry := l.WithField("request_id", uuid.NewV4().String())
	return logger.SetEntry(ctx, entry)
}
<|endoftext|>


<commit_before>package schedule

import (
	"github.com/graniticio/granitic/ioc"
	"github.com/graniticio/granitic/logging"
	"time"
)

func NewInvocationManager(t *Task) *invocationManager {

	im := new(invocationManager)
	im.Task = t
	im.scheduled = new(invocationQueue)
	im.running = new(invocationQueue)
	im.State = ioc.StoppedState
	return im

}

type invocationManager struct {
	Task      *Task
	Interval  *interval
	scheduled *invocationQueue
	running   *invocationQueue
	State     ioc.ComponentState
	Log       logging.Logger
}

func (im *invocationManager) Start() {

	im.State = ioc.StartingState

	im.setFirstInvocation()

	im.State = ioc.RunningState

	for im.State != ioc.StoppedState && im.State != ioc.StoppingState {
		//Pop tasks from the schedule queue as long as we're not stopping

		next := im.scheduled.Peek()

		if next != nil {
			runAt := next.runAt

			now := time.Now()

			if runAt == now || runAt.Before(now) {
				im.scheduled.Dequeue()

				if im.State == ioc.RunningState {
					im.running.Enqueue(next)

					go im.runTask(next)
				}
			}

		}

	}
}

func (im *invocationManager) runTask(i *invocation) {

	i.startedAt = time.Now()

	updates := make(chan TaskStatusUpdate)

	im.Log.LogDebugf("Executing %s", im.Task.FullName())

	err := im.Task.logic.ExecuteTask(updates)

	if err != nil {
		im.Log.LogErrorf("Problem executing task %s (invocation %d started at %v): %s", im.Task.FullName(), i.counter, i.startedAt, err.Error())
	}

	close(updates)

}

func (im *invocationManager) setFirstInvocation() {

	interval := im.Interval

	i := new(invocation)
	i.counter = 1

	if interval.Mode == OFFSET_FROM_START {
		i.runAt = time.Now().Add(interval.OffsetFromStart)
	} else {
		i.runAt = interval.ActualStart
	}

	im.scheduled.Enqueue(i)

}

func (im *invocationManager) PrepareToStop() {
	im.State = ioc.StoppingState
}
<commit_msg>Scheduled tasks<commit_after>package schedule

import (
	"fmt"
	"github.com/graniticio/granitic/ioc"
	"github.com/graniticio/granitic/logging"
	"time"
)

func NewInvocationManager(t *Task) *invocationManager {

	im := new(invocationManager)
	im.Task = t
	im.scheduled = new(invocationQueue)
	im.running = new(invocationQueue)
	im.State = ioc.StoppedState
	return im

}

type invocationManager struct {
	Task      *Task
	Interval  *interval
	scheduled *invocationQueue
	running   *invocationQueue
	State     ioc.ComponentState
	Log       logging.Logger
}

func (im *invocationManager) Start() {

	im.State = ioc.StartingState

	im.setFirstInvocation()

	im.State = ioc.RunningState

	for im.State != ioc.StoppedState && im.State != ioc.StoppingState {
		//Pop tasks from the schedule queue as long as we're not stopping

		first := im.scheduled.Peek()

		if first != nil {
			runAt := first.runAt

			now := time.Now()

			if runAt == now || runAt.Before(now) {
				im.scheduled.Dequeue()

				if im.State == ioc.RunningState {
					im.running.Enqueue(first)

					go im.runTask(first)
				}

				im.addNextInvocation(first)
			}

		}

		waitTime := im.determineWait()

		fmt.Println(waitTime)

		time.Sleep(waitTime)
	}
}

func (im *invocationManager) runTask(i *invocation) {

	i.startedAt = time.Now()

	if im.Log.IsLevelEnabled(logging.Trace) {
		im.Log.LogTracef("Accuracy: %v", i.startedAt.Sub(i.runAt))
	}

	updates := make(chan TaskStatusUpdate)

	im.Log.LogDebugf("Executing %s", im.Task.FullName())

	err := im.Task.logic.ExecuteTask(updates)

	if err != nil {
		im.Log.LogErrorf("Problem executing task %s (invocation %d started at %v): %s", im.Task.FullName(), i.counter, i.startedAt, err.Error())
	}

	close(updates)

}
func (im *invocationManager) determineWait() time.Duration {

	next := im.scheduled.Peek()

	if next == nil {
		return time.Second
	} else {

		untilNext := next.runAt.Sub(time.Now())

		if untilNext < time.Second {
			return untilNext
		} else {
			return time.Second
		}

	}

}

func (im *invocationManager) setFirstInvocation() {

	interval := im.Interval

	i := new(invocation)
	i.counter = 1

	if interval.Mode == OFFSET_FROM_START {
		i.runAt = time.Now().Add(interval.OffsetFromStart)
	} else {
		i.runAt = interval.ActualStart
	}

	im.scheduled.Enqueue(i)

}

func (im *invocationManager) addNextInvocation(previous *invocation) time.Time {

	interval := im.Interval

	i := new(invocation)
	i.runAt = previous.runAt.Add(interval.Frequency)

	im.scheduled.Enqueue(i)

	return i.runAt

}

func (im *invocationManager) PrepareToStop() {
	im.State = ioc.StoppingState
}
<|endoftext|>


<commit_before>package proxmox

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type ConfigQemu struct {
	Name         string  `json:"name"`
	Description  string  `json:"desc"`
	Memory       int     `json:"memory"`
	DiskSize     float64 `json:"diskGB"`
	Storage      string  `json:"storage"`
	QemuOs       string  `json:"os"`
	QemuCores    int     `json:"cores"`
	QemuSockets  int     `json:"sockets"`
	QemuIso      string  `json:"iso"`
	QemuNicModel string  `json:"nic"`
	QemuBrige    string  `json:"bridge"`
	QemuVlanTag  int     `json:"vlan"`
	FullClone    *int    `json:"fullclone"`
}

func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
	vmr.SetVmType("qemu")
	network := config.QemuNicModel + ",bridge=" + config.QemuBrige
	if config.QemuVlanTag > 0 {
		network = network + ",tag=" + strconv.Itoa(config.QemuVlanTag)
	}

	params := map[string]string{
		"vmid":        strconv.Itoa(vmr.vmId),
		"name":        config.Name,
		"ide2":        config.QemuIso + ",media=cdrom",
		"ostype":      config.QemuOs,
		"virtio0":     config.Storage + ":" + strconv.FormatFloat(config.DiskSize, 'f', -1, 64),
		"sockets":     strconv.Itoa(config.QemuSockets),
		"cores":       strconv.Itoa(config.QemuCores),
		"cpu":         "host",
		"memory":      strconv.Itoa(config.Memory),
		"net0":        network,
		"description": config.Description,
	}

	_, err = client.CreateQemuVm(vmr.node, params)
	return
}

/*

CloneVm
Example: Request

nodes/proxmox1-xx/qemu/1012/clone

newid:145
name:tf-clone1
target:proxmox1-xx
full:1
storage:xxx

*/
func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) (err error) {
	vmr.SetVmType("qemu")
	fullclone := "1"
	if config.FullClone != nil {
		fullclone = strconv.Itoa(*config.FullClone)
	}
	params := map[string]string{
		"newid":   strconv.Itoa(vmr.vmId),
		"target":  vmr.node,
		"name":    config.Name,
		"storage": config.Storage,
		"full":    fullclone,
	}
	_, err = client.CloneQemuVm(sourceVmr, params)
	if err != nil {
		return
	}
	return config.UpdateConfig(vmr, client)
}

func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
	network := config.QemuNicModel + ",bridge=" + config.QemuBrige
	if config.QemuVlanTag > 0 {
		network = network + ",tag=" + strconv.Itoa(config.QemuVlanTag)
	}
	configParams := map[string]string{
		"sockets":     strconv.Itoa(config.QemuSockets),
		"cores":       strconv.Itoa(config.QemuCores),
		"memory":      strconv.Itoa(config.Memory),
		"net0":        network,
		"description": config.Description,
	}
	_, err = client.SetVmConfig(vmr, configParams)
	return err
}

func NewConfigQemuFromJson(io io.Reader) (config *ConfigQemu, err error) {
	config = &ConfigQemu{QemuVlanTag: -1}
	err = json.NewDecoder(io).Decode(config)
	if err != nil {
		log.Fatal(err)
		return nil, err
	}
	log.Println(config)
	return
}

var rxStorage = regexp.MustCompile("(.*?):.*?,size=(\\d+)G")
var rxIso = regexp.MustCompile("(.*?),media")
var rxNetwork = regexp.MustCompile("(.*?)=.*?,bridge=([^,]+)(?:,tag=)?(.*)")

func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err error) {
	var vmConfig map[string]interface{}
	for ii := 0; ii < 3; ii++ {
		vmConfig, err = client.GetVmConfig(vmr)
		if err != nil {
			log.Fatal(err)
			return nil, err
		}
		// this can happen:
		// {"data":{"lock":"clone","digest":"eb54fb9d9f120ba0c3bdf694f73b10002c375c38","description":" qmclone temporary file\n"}})
		if vmConfig["lock"] == nil {
			break
		} else {
			time.Sleep(8 * time.Second)
		}
	}

	if vmConfig["lock"] != nil {
		return nil, errors.New("vm locked, could not obtain config")
	}

	// vmConfig Sample: map[ cpu:host
	// net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0
	// ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048
	// smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1
	// name:terraform-ubuntu1404-template bootdisk:virtio0
	// virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G
	// description:Base image
	// cores:2 ostype:l26

	fullclone := 1
	if vmConfig["fullclone"] != nil {
		fullclone = int(vmConfig["fullclone"].(float64))
	}
	description := ""
	if vmConfig["description"] != nil {
		description = vmConfig["description"].(string)
	}
	config = &ConfigQemu{
		Name:        vmConfig["name"].(string),
		Description: strings.TrimSpace(description),
		QemuOs:      vmConfig["ostype"].(string),
		Memory:      int(vmConfig["memory"].(float64)),
		QemuCores:   int(vmConfig["cores"].(float64)),
		QemuSockets: int(vmConfig["sockets"].(float64)),
		QemuVlanTag: -1,
		FullClone:   &fullclone,
	}

	if vmConfig["virtio0"] == nil {
		return nil, errors.New("virtio0 (required) not found in current config")
	}

	storageMatch := rxStorage.FindStringSubmatch(vmConfig["virtio0"].(string))
	config.Storage = storageMatch[1]
	config.DiskSize, _ = strconv.ParseFloat(storageMatch[2], 64)

	if vmConfig["ide2"] != nil {
		isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string))
		config.QemuIso = isoMatch[1]
	}

	if vmConfig["net0"] == nil {
		return nil, errors.New("net0 (required) not found in current config")
	}

	netMatch := rxNetwork.FindStringSubmatch(vmConfig["net0"].(string))
	config.QemuNicModel = netMatch[1]
	config.QemuBrige = netMatch[2]
	if netMatch[3] != "" {
		config.QemuVlanTag, _ = strconv.Atoi(netMatch[3])
	}

	return
}

// Useful waiting for ISO install to complete
func WaitForShutdown(vmr *VmRef, client *Client) (err error) {
	for ii := 0; ii < 100; ii++ {
		vmState, err := client.GetVmState(vmr)
		if err != nil {
			log.Print("Wait error:")
			log.Println(err)
		} else if vmState["status"] == "stopped" {
			return nil
		}
		time.Sleep(5 * time.Second)
	}
	return errors.New("Not shutdown within wait time")
}

// This is because proxmox create/config API won't let us make usernet devices
func SshForwardUsernet(vmr *VmRef, client *Client) (sshPort string, err error) {
	vmState, err := client.GetVmState(vmr)
	if err != nil {
		return "", err
	}
	if vmState["status"] == "stopped" {
		return "", errors.New("VM must be running first")
	}
	sshPort = strconv.Itoa(vmr.VmId() + 22000)
	_, err = client.MonitorCmd(vmr, "netdev_add user,id=net1,hostfwd=tcp::"+sshPort+"-:22")
	if err != nil {
		return "", err
	}
	_, err = client.MonitorCmd(vmr, "device_add virtio-net-pci,id=net1,netdev=net1,addr=0x13")
	if err != nil {
		return "", err
	}
	return
}

// device_del net1
// netdev_del net1
func RemoveSshForwardUsernet(vmr *VmRef, client *Client) (err error) {
	vmState, err := client.GetVmState(vmr)
	if err != nil {
		return err
	}
	if vmState["status"] == "stopped" {
		return errors.New("VM must be running first")
	}
	_, err = client.MonitorCmd(vmr, "device_del net1")
	if err != nil {
		return err
	}
	_, err = client.MonitorCmd(vmr, "netdev_del net1")
	if err != nil {
		return err
	}
	return nil
}

func MaxVmId(client *Client) (max int, err error) {
	resp, err := client.GetVmList()
	vms := resp["data"].([]interface{})
	max = 0
	for vmii := range vms {
		vm := vms[vmii].(map[string]interface{})
		vmid := int(vm["vmid"].(float64))
		if vmid > max {
			max = vmid
		}
	}
	return
}

func SendKeysString(vmr *VmRef, client *Client, keys string) (err error) {
	vmState, err := client.GetVmState(vmr)
	if err != nil {
		return err
	}
	if vmState["status"] == "stopped" {
		return errors.New("VM must be running first")
	}
	for _, r := range keys {
		c := string(r)
		lower := strings.ToLower(c)
		if c != lower {
			c = "shift-" + lower
		} else {
			switch c {
			case "!":
				c = "shift-1"
			case "@":
				c = "shift-2"
			case "#":
				c = "shift-3"
			case "$":
				c = "shift-4"
			case "%%":
				c = "shift-5"
			case "^":
				c = "shift-6"
			case "&":
				c = "shift-7"
			case "*":
				c = "shift-8"
			case "(":
				c = "shift-9"
			case ")":
				c = "shift-0"
			case "_":
				c = "shift-minus"
			case "+":
				c = "shift-equal"
			case " ":
				c = "spc"
			case "/":
				c = "slash"
			case "\\":
				c = "backslash"
			case ",":
				c = "comma"
			case "-":
				c = "minus"
			case "=":
				c = "equal"
			case ".":
				c = "dot"
			case "?":
				c = "shift-slash"
			}
		}
		_, err = client.MonitorCmd(vmr, "sendkey "+c)
		if err != nil {
			return err
		}
		time.Sleep(100)
	}
	return nil
}
<commit_msg>Added the possibility to read the macaddress from the proxmox configuration<commit_after>package proxmox

import (
	"encoding/json"
	"errors"
	"io"
	"log"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type ConfigQemu struct {
	Name         string  `json:"name"`
	Description  string  `json:"desc"`
	Memory       int     `json:"memory"`
	DiskSize     float64 `json:"diskGB"`
	Storage      string  `json:"storage"`
	QemuOs       string  `json:"os"`
	QemuCores    int     `json:"cores"`
	QemuSockets  int     `json:"sockets"`
	QemuIso      string  `json:"iso"`
	QemuNicModel string  `json:"nic"`
	QemuBrige    string  `json:"bridge"`
	QemuVlanTag  int     `json:"vlan"`
	QemuMacAddr  string  `json:"mac"`
	FullClone    *int    `json:"fullclone"`
}

func (config ConfigQemu) CreateVm(vmr *VmRef, client *Client) (err error) {
	vmr.SetVmType("qemu")
	network := config.QemuNicModel + ",bridge=" + config.QemuBrige
	if config.QemuMacAddr != "" {
		network = network + ",macaddr=" + config.QemuMacAddr
	}
	if config.QemuVlanTag > 0 {
		network = network + ",tag=" + strconv.Itoa(config.QemuVlanTag)
	}

	params := map[string]string{
		"vmid":        strconv.Itoa(vmr.vmId),
		"name":        config.Name,
		"ide2":        config.QemuIso + ",media=cdrom",
		"ostype":      config.QemuOs,
		"virtio0":     config.Storage + ":" + strconv.FormatFloat(config.DiskSize, 'f', -1, 64),
		"sockets":     strconv.Itoa(config.QemuSockets),
		"cores":       strconv.Itoa(config.QemuCores),
		"cpu":         "host",
		"memory":      strconv.Itoa(config.Memory),
		"net0":        network,
		"description": config.Description,
	}

	_, err = client.CreateQemuVm(vmr.node, params)
	return
}

/*

CloneVm
Example: Request

nodes/proxmox1-xx/qemu/1012/clone

newid:145
name:tf-clone1
target:proxmox1-xx
full:1
storage:xxx

*/
func (config ConfigQemu) CloneVm(sourceVmr *VmRef, vmr *VmRef, client *Client) (err error) {
	vmr.SetVmType("qemu")
	fullclone := "1"
	if config.FullClone != nil {
		fullclone = strconv.Itoa(*config.FullClone)
	}
	params := map[string]string{
		"newid":   strconv.Itoa(vmr.vmId),
		"target":  vmr.node,
		"name":    config.Name,
		"storage": config.Storage,
		"full":    fullclone,
	}
	_, err = client.CloneQemuVm(sourceVmr, params)
	if err != nil {
		return
	}
	return config.UpdateConfig(vmr, client)
}

func (config ConfigQemu) UpdateConfig(vmr *VmRef, client *Client) (err error) {
	network := config.QemuNicModel + ",bridge=" + config.QemuBrige
	if config.QemuMacAddr != "" {
		network = network + ",macaddr=" + config.QemuMacAddr
	}
	if config.QemuVlanTag > 0 {
		network = network + ",tag=" + strconv.Itoa(config.QemuVlanTag)
	}
	configParams := map[string]string{
		"sockets":     strconv.Itoa(config.QemuSockets),
		"cores":       strconv.Itoa(config.QemuCores),
		"memory":      strconv.Itoa(config.Memory),
		"net0":        network,
		"description": config.Description,
	}
	_, err = client.SetVmConfig(vmr, configParams)
	return err
}

func NewConfigQemuFromJson(io io.Reader) (config *ConfigQemu, err error) {
	config = &ConfigQemu{QemuVlanTag: -1}
	err = json.NewDecoder(io).Decode(config)
	if err != nil {
		log.Fatal(err)
		return nil, err
	}
	log.Println(config)
	return
}

var rxStorage = regexp.MustCompile("(.*?):.*?,size=(\\d+)G")
var rxIso = regexp.MustCompile("(.*?),media")
var rxNetwork = regexp.MustCompile("(.*?)=(.*?),bridge=([^,]+)(?:,tag=)?(.*)")

func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err error) {
	var vmConfig map[string]interface{}
	for ii := 0; ii < 3; ii++ {
		vmConfig, err = client.GetVmConfig(vmr)
		if err != nil {
			log.Fatal(err)
			return nil, err
		}
		// this can happen:
		// {"data":{"lock":"clone","digest":"eb54fb9d9f120ba0c3bdf694f73b10002c375c38","description":" qmclone temporary file\n"}})
		if vmConfig["lock"] == nil {
			break
		} else {
			time.Sleep(8 * time.Second)
		}
	}

	if vmConfig["lock"] != nil {
		return nil, errors.New("vm locked, could not obtain config")
	}

	// vmConfig Sample: map[ cpu:host
	// net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0
	// ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048
	// smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1
	// name:terraform-ubuntu1404-template bootdisk:virtio0
	// virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G
	// description:Base image
	// cores:2 ostype:l26

	name := ""
	if _, is_set := vmConfig["name"]; is_set {
		name = vmConfig["name"].(string)
	}
	description := ""
	if _, is_set := vmConfig["description"]; is_set {
		description = vmConfig["description"].(string)
	}
	ostype := ""
	if _, is_set := vmConfig["ostype"]; is_set {
		ostype = vmConfig["ostype"].(string)
	}
	memory := 0.0
	if _, is_set := vmConfig["memory"]; is_set {
		memory = vmConfig["memory"].(float64)
	}
	cores := 0.0
	if _, is_set := vmConfig["cores"]; is_set {
		cores = vmConfig["cores"].(float64)
	}
	sockets := 0.0
	if _, is_set := vmConfig["sockets"]; is_set {
		sockets = vmConfig["sockets"].(float64)
	}
	config = &ConfigQemu{
		Name:        name,
		Description: strings.TrimSpace(description),
		QemuOs:      ostype,
		Memory:      int(memory),
		QemuCores:   int(cores),
		QemuSockets: int(sockets),
		QemuVlanTag: -1,
	}

	if vmConfig["virtio0"] == nil {
		return nil, errors.New("virtio0 (required) not found in current config")
	}

	storageMatch := rxStorage.FindStringSubmatch(vmConfig["virtio0"].(string))
	config.Storage = storageMatch[1]
	config.DiskSize, _ = strconv.ParseFloat(storageMatch[2], 64)

	if vmConfig["ide2"] != nil {
		isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string))
		config.QemuIso = isoMatch[1]
	}

	if vmConfig["net0"] == nil {
		return nil, errors.New("net0 (required) not found in current config")
	}

	netMatch := rxNetwork.FindStringSubmatch(vmConfig["net0"].(string))
	config.QemuNicModel = netMatch[1]
	config.QemuMacAddr = netMatch[2]
	config.QemuBrige = netMatch[3]
	if netMatch[4] != "" {
		config.QemuVlanTag, _ = strconv.Atoi(netMatch[4])
	}

	return
}

// Useful waiting for ISO install to complete
func WaitForShutdown(vmr *VmRef, client *Client) (err error) {
	for ii := 0; ii < 100; ii++ {
		vmState, err := client.GetVmState(vmr)
		if err != nil {
			log.Print("Wait error:")
			log.Println(err)
		} else if vmState["status"] == "stopped" {
			return nil
		}
		time.Sleep(5 * time.Second)
	}
	return errors.New("Not shutdown within wait time")
}

// This is because proxmox create/config API won't let us make usernet devices
func SshForwardUsernet(vmr *VmRef, client *Client) (sshPort string, err error) {
	vmState, err := client.GetVmState(vmr)
	if err != nil {
		return "", err
	}
	if vmState["status"] == "stopped" {
		return "", errors.New("VM must be running first")
	}
	sshPort = strconv.Itoa(vmr.VmId() + 22000)
	_, err = client.MonitorCmd(vmr, "netdev_add user,id=net1,hostfwd=tcp::"+sshPort+"-:22")
	if err != nil {
		return "", err
	}
	_, err = client.MonitorCmd(vmr, "device_add virtio-net-pci,id=net1,netdev=net1,addr=0x13")
	if err != nil {
		return "", err
	}
	return
}

// device_del net1
// netdev_del net1
func RemoveSshForwardUsernet(vmr *VmRef, client *Client) (err error) {
	vmState, err := client.GetVmState(vmr)
	if err != nil {
		return err
	}
	if vmState["status"] == "stopped" {
		return errors.New("VM must be running first")
	}
	_, err = client.MonitorCmd(vmr, "device_del net1")
	if err != nil {
		return err
	}
	_, err = client.MonitorCmd(vmr, "netdev_del net1")
	if err != nil {
		return err
	}
	return nil
}

func MaxVmId(client *Client) (max int, err error) {
	resp, err := client.GetVmList()
	vms := resp["data"].([]interface{})
	max = 0
	for vmii := range vms {
		vm := vms[vmii].(map[string]interface{})
		vmid := int(vm["vmid"].(float64))
		if vmid > max {
			max = vmid
		}
	}
	return
}

func SendKeysString(vmr *VmRef, client *Client, keys string) (err error) {
	vmState, err := client.GetVmState(vmr)
	if err != nil {
		return err
	}
	if vmState["status"] == "stopped" {
		return errors.New("VM must be running first")
	}
	for _, r := range keys {
		c := string(r)
		lower := strings.ToLower(c)
		if c != lower {
			c = "shift-" + lower
		} else {
			switch c {
			case "!":
				c = "shift-1"
			case "@":
				c = "shift-2"
			case "#":
				c = "shift-3"
			case "$":
				c = "shift-4"
			case "%%":
				c = "shift-5"
			case "^":
				c = "shift-6"
			case "&":
				c = "shift-7"
			case "*":
				c = "shift-8"
			case "(":
				c = "shift-9"
			case ")":
				c = "shift-0"
			case "_":
				c = "shift-minus"
			case "+":
				c = "shift-equal"
			case " ":
				c = "spc"
			case "/":
				c = "slash"
			case "\\":
				c = "backslash"
			case ",":
				c = "comma"
			case "-":
				c = "minus"
			case "=":
				c = "equal"
			case ".":
				c = "dot"
			case "?":
				c = "shift-slash"
			}
		}
		_, err = client.MonitorCmd(vmr, "sendkey "+c)
		if err != nil {
			return err
		}
		time.Sleep(100)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker, Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package metrics

import (
	"bytes"
	"context"
	"encoding/json"
	"net"
	"net/http"
)

type client struct {
	httpClient *http.Client
}

// Command is a command
type Command struct {
	Command string `json:"command"`
	Context string `json:"context"`
	Source  string `json:"source"`
	Status  string `json:"status"`
}

const (
	// CLISource is sent for cli metrics
	CLISource = "cli"
	// APISource is sent for API metrics
	APISource = "api"
	// SuccessStatus is sent for API metrics
	SuccessStatus = "success"
	// FailureStatus is sent for API metrics
	FailureStatus = "failure"
	// CanceledStatus is sent for API metrics
	CanceledStatus = "canceled"
)

// Client sends metrics to Docker Desktopn
type Client interface {
	// Send sends the command to Docker Desktop. Note that the function doesn't
	// return anything, not even an error, this is because we don't really care
	// if the metrics were sent or not. We only fire and forget.
	Send(Command)
}

// NewClient returns a new metrics client
func NewClient() Client {
	return &client{
		httpClient: &http.Client{
			Transport: &http.Transport{
				DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
					return conn()
				},
			},
		},
	}
}

func (c *client) Send(command Command) {
	wasIn := make(chan bool)

	// Fire and forget, we don't want to slow down the user waiting for DD
	// metrics endpoint to respond. We could lose some events but that's ok.
	go func() {
		defer func() {
			_ = recover()
		}()

		wasIn <- true

		req, err := json.Marshal(command)
		if err != nil {
			return
		}

		_, _ = c.httpClient.Post("http://localhost/usage", "application/json", bytes.NewBuffer(req))
	}()
	<-wasIn
}
<commit_msg>We can’t anymore “fire and forget”, now that metrics get posted right at the end, most of the time we’d loose them.  Give it max 50 ms to post metrics, that’s plenty, post call ends in ~2 ms or less when desktop is up, less than one ms to fail the post when DD is not listening.<commit_after>/*
   Copyright 2020 Docker, Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package metrics

import (
	"bytes"
	"context"
	"encoding/json"
	"net"
	"net/http"
	"time"
)

type client struct {
	httpClient *http.Client
}

// Command is a command
type Command struct {
	Command string `json:"command"`
	Context string `json:"context"`
	Source  string `json:"source"`
	Status  string `json:"status"`
}

const (
	// CLISource is sent for cli metrics
	CLISource = "cli"
	// APISource is sent for API metrics
	APISource = "api"
	// SuccessStatus is sent for API metrics
	SuccessStatus = "success"
	// FailureStatus is sent for API metrics
	FailureStatus = "failure"
	// CanceledStatus is sent for API metrics
	CanceledStatus = "canceled"
)

// Client sends metrics to Docker Desktopn
type Client interface {
	// Send sends the command to Docker Desktop. Note that the function doesn't
	// return anything, not even an error, this is because we don't really care
	// if the metrics were sent or not. We only fire and forget.
	Send(Command)
}

// NewClient returns a new metrics client
func NewClient() Client {
	return &client{
		httpClient: &http.Client{
			Transport: &http.Transport{
				DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
					return conn()
				},
			},
		},
	}
}

func (c *client) Send(command Command) {
	result := make(chan bool, 1)
	go func() {
		postMetrics(command, c)
		result <- true
	}()

	// wait for the post finished, or timeout in case anything freezes.
	// Posting metrics without Desktop listening returns in less than a ms, and a handful of ms (often <2ms) when Desktop is listening
	select {
	case <-result:
	case <-time.After(50 * time.Millisecond):
	}
}

func postMetrics(command Command, c *client) {
	req, err := json.Marshal(command)
	if err == nil {
		_, _ = c.httpClient.Post("http://localhost/usage", "application/json", bytes.NewBuffer(req))
	}
}
<|endoftext|>


<commit_before>package difffilter

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

	"github.com/reviewdog/reviewdog/diff"
	"github.com/reviewdog/reviewdog/service/serviceutil"
)

// Mode represents enumeration of available filter modes
type Mode int

const (
	// ModeDefault represents default mode, which means users doesn't specify
	// filter-mode. The behavior can be changed depending on reporters/context
	// later if we want. Basically, it's same as ModeAdded because it's most safe
	// and basic mode for reporters implementation.
	ModeDefault Mode = iota
	// ModeAdded represents filtering by added/changed diff lines.
	ModeAdded
	// ModeDiffContext represents filtering by diff context.
	// i.e. changed lines +-N lines (e.g. N=3 for default git diff).
	ModeDiffContext
	// ModeFile represents filtering by changed files.
	ModeFile
	// ModeNoFilter doesn't filter out any results.
	ModeNoFilter
)

// String implements the flag.Value interface
func (mode *Mode) String() string {
	names := [...]string{
		"default",
		"added",
		"diff_context",
		"file",
		"nofilter",
	}
	if *mode < ModeDefault || *mode > ModeNoFilter {
		return "Unknown mode"
	}

	return names[*mode]
}

// Set implements the flag.Value interface
func (mode *Mode) Set(value string) error {
	switch value {
	case "default", "":
		*mode = ModeDefault
	case "added":
		*mode = ModeAdded
	case "diff_context":
		*mode = ModeDiffContext
	case "file":
		*mode = ModeFile
	case "nofilter":
		*mode = ModeNoFilter
	default:
		return fmt.Errorf("invalid mode name: %s", value)
	}
	return nil
}

// DiffFilter filters lines by diff.
type DiffFilter struct {
	// Current working directory (workdir).
	cwd string

	// Relative path to the project root (e.g. git) directory from current workdir.
	// It can be empty if it doesn't find any project root directory.
	projectRelPath string

	strip int
	mode  Mode

	difflines difflines
}

// difflines is a hash table of normalizedPath to line number to diff.Line.
type difflines map[normalizedPath]map[int]*diff.Line

// New creates a new DiffFilter.
func New(diff []*diff.FileDiff, strip int, cwd string, mode Mode) *DiffFilter {
	df := &DiffFilter{
		strip:     strip,
		cwd:       cwd,
		mode:      mode,
		difflines: make(difflines),
	}
	// If cwd is empty, projectRelPath should not have any meaningful data too.
	if cwd != "" {
		df.projectRelPath, _ = serviceutil.GitRelWorkdir()
	}
	df.addDiff(diff)
	return df
}

func (df *DiffFilter) addDiff(filediffs []*diff.FileDiff) {
	for _, filediff := range filediffs {
		path := df.normalizeDiffPath(filediff)
		lines, ok := df.difflines[path]
		if !ok {
			lines = make(map[int]*diff.Line)
		}
		for _, hunk := range filediff.Hunks {
			for _, line := range hunk.Lines {
				if df.isSignificantLine(line) {
					lines[line.LnumNew] = line
				}
			}
		}
		df.difflines[path] = lines
	}
}

// ShouldReport returns true, if the given path is in diff depending on the filter
// Mode. It also optionally return diff line.
func (df *DiffFilter) ShouldReport(path string, lnum int) (bool, *diff.Line) {
	lines, ok := df.difflines[df.normalizePath(path)]
	if !ok {
		return (df.mode == ModeNoFilter), nil
	}
	line, ok := lines[lnum]
	if !ok {
		return (df.mode == ModeNoFilter || df.mode == ModeFile), nil
	}
	return true, line
}

func (df *DiffFilter) isSignificantLine(line *diff.Line) bool {
	switch df.mode {
	case ModeDiffContext, ModeFile, ModeNoFilter:
		return true // any lines in diff are significant.
	case ModeAdded, ModeDefault:
		return line.Type == diff.LineAdded
	}
	return false
}

// normalizedPath is file path which is relative to **project root dir** or
// to current dir if project root not found.
type normalizedPath struct{ p string }

func (df *DiffFilter) normalizePath(path string) normalizedPath {
	path = filepath.Clean(path)
	// Convert absolute path to relative path only if the path is in current
	// directory.
	if filepath.IsAbs(path) && df.cwd != "" && contains(path, df.cwd) {
		relPath, err := filepath.Rel(df.cwd, path)
		if err == nil {
			path = relPath
		}
	}
	if !filepath.IsAbs(path) && df.projectRelPath != "" {
		path = filepath.Join(df.projectRelPath, path)
	}
	return normalizedPath{p: filepath.ToSlash(path)}
}

func contains(path, base string) bool {
	ps := splitPathList(path)
	bs := splitPathList(base)
	if len(ps) < len(bs) {
		return false
	}
	for i := range bs {
		if bs[i] != ps[i] {
			return false
		}
	}
	return true
}

// Assuming diff path should be relative path to the project root dir by
// default (e.g. git diff).
//
// `git diff --relative` can returns relative path to current workdir, so we
// ask users not to use it for reviewdog command.
func (df *DiffFilter) normalizeDiffPath(filediff *diff.FileDiff) normalizedPath {
	return normalizedPath{p: NormalizeDiffPath(filediff.PathNew, df.strip)}
}

// NormalizeDiffPath return path normalized path from given path in diff with
// strip.
func NormalizeDiffPath(diffpath string, strip int) string {
	if diffpath == "/dev/null" {
		return ""
	}
	path := diffpath
	if strip > 0 {
		ps := splitPathList(path)
		if len(ps) > strip {
			path = filepath.Join(ps[strip:]...)
		}
	}
	return filepath.ToSlash(filepath.Clean(path))
}

func splitPathList(path string) []string {
	return strings.Split(filepath.ToSlash(path), "/")
}
<commit_msg>update ShouldReport func comment as well<commit_after>package difffilter

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

	"github.com/reviewdog/reviewdog/diff"
	"github.com/reviewdog/reviewdog/service/serviceutil"
)

// Mode represents enumeration of available filter modes
type Mode int

const (
	// ModeDefault represents default mode, which means users doesn't specify
	// filter-mode. The behavior can be changed depending on reporters/context
	// later if we want. Basically, it's same as ModeAdded because it's most safe
	// and basic mode for reporters implementation.
	ModeDefault Mode = iota
	// ModeAdded represents filtering by added/changed diff lines.
	ModeAdded
	// ModeDiffContext represents filtering by diff context.
	// i.e. changed lines +-N lines (e.g. N=3 for default git diff).
	ModeDiffContext
	// ModeFile represents filtering by changed files.
	ModeFile
	// ModeNoFilter doesn't filter out any results.
	ModeNoFilter
)

// String implements the flag.Value interface
func (mode *Mode) String() string {
	names := [...]string{
		"default",
		"added",
		"diff_context",
		"file",
		"nofilter",
	}
	if *mode < ModeDefault || *mode > ModeNoFilter {
		return "Unknown mode"
	}

	return names[*mode]
}

// Set implements the flag.Value interface
func (mode *Mode) Set(value string) error {
	switch value {
	case "default", "":
		*mode = ModeDefault
	case "added":
		*mode = ModeAdded
	case "diff_context":
		*mode = ModeDiffContext
	case "file":
		*mode = ModeFile
	case "nofilter":
		*mode = ModeNoFilter
	default:
		return fmt.Errorf("invalid mode name: %s", value)
	}
	return nil
}

// DiffFilter filters lines by diff.
type DiffFilter struct {
	// Current working directory (workdir).
	cwd string

	// Relative path to the project root (e.g. git) directory from current workdir.
	// It can be empty if it doesn't find any project root directory.
	projectRelPath string

	strip int
	mode  Mode

	difflines difflines
}

// difflines is a hash table of normalizedPath to line number to diff.Line.
type difflines map[normalizedPath]map[int]*diff.Line

// New creates a new DiffFilter.
func New(diff []*diff.FileDiff, strip int, cwd string, mode Mode) *DiffFilter {
	df := &DiffFilter{
		strip:     strip,
		cwd:       cwd,
		mode:      mode,
		difflines: make(difflines),
	}
	// If cwd is empty, projectRelPath should not have any meaningful data too.
	if cwd != "" {
		df.projectRelPath, _ = serviceutil.GitRelWorkdir()
	}
	df.addDiff(diff)
	return df
}

func (df *DiffFilter) addDiff(filediffs []*diff.FileDiff) {
	for _, filediff := range filediffs {
		path := df.normalizeDiffPath(filediff)
		lines, ok := df.difflines[path]
		if !ok {
			lines = make(map[int]*diff.Line)
		}
		for _, hunk := range filediff.Hunks {
			for _, line := range hunk.Lines {
				if df.isSignificantLine(line) {
					lines[line.LnumNew] = line
				}
			}
		}
		df.difflines[path] = lines
	}
}

// ShouldReport returns true, if the given path should be reported depending on
// the filter Mode. It also optionally return diff line.
func (df *DiffFilter) ShouldReport(path string, lnum int) (bool, *diff.Line) {
	lines, ok := df.difflines[df.normalizePath(path)]
	if !ok {
		return (df.mode == ModeNoFilter), nil
	}
	line, ok := lines[lnum]
	if !ok {
		return (df.mode == ModeNoFilter || df.mode == ModeFile), nil
	}
	return true, line
}

func (df *DiffFilter) isSignificantLine(line *diff.Line) bool {
	switch df.mode {
	case ModeDiffContext, ModeFile, ModeNoFilter:
		return true // any lines in diff are significant.
	case ModeAdded, ModeDefault:
		return line.Type == diff.LineAdded
	}
	return false
}

// normalizedPath is file path which is relative to **project root dir** or
// to current dir if project root not found.
type normalizedPath struct{ p string }

func (df *DiffFilter) normalizePath(path string) normalizedPath {
	path = filepath.Clean(path)
	// Convert absolute path to relative path only if the path is in current
	// directory.
	if filepath.IsAbs(path) && df.cwd != "" && contains(path, df.cwd) {
		relPath, err := filepath.Rel(df.cwd, path)
		if err == nil {
			path = relPath
		}
	}
	if !filepath.IsAbs(path) && df.projectRelPath != "" {
		path = filepath.Join(df.projectRelPath, path)
	}
	return normalizedPath{p: filepath.ToSlash(path)}
}

func contains(path, base string) bool {
	ps := splitPathList(path)
	bs := splitPathList(base)
	if len(ps) < len(bs) {
		return false
	}
	for i := range bs {
		if bs[i] != ps[i] {
			return false
		}
	}
	return true
}

// Assuming diff path should be relative path to the project root dir by
// default (e.g. git diff).
//
// `git diff --relative` can returns relative path to current workdir, so we
// ask users not to use it for reviewdog command.
func (df *DiffFilter) normalizeDiffPath(filediff *diff.FileDiff) normalizedPath {
	return normalizedPath{p: NormalizeDiffPath(filediff.PathNew, df.strip)}
}

// NormalizeDiffPath return path normalized path from given path in diff with
// strip.
func NormalizeDiffPath(diffpath string, strip int) string {
	if diffpath == "/dev/null" {
		return ""
	}
	path := diffpath
	if strip > 0 {
		ps := splitPathList(path)
		if len(ps) > strip {
			path = filepath.Join(ps[strip:]...)
		}
	}
	return filepath.ToSlash(filepath.Clean(path))
}

func splitPathList(path string) []string {
	return strings.Split(filepath.ToSlash(path), "/")
}
<|endoftext|>