<commit_before>package main

import (
	"fmt"
	"koding/kontrol/kontrolproxy/proxyconfig"
	"koding/tools/db"
	"koding/virt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"math"
	"net"
	"net/http"
	"net/url"
	"strings"
)

type UserInfo struct {
	Domain   *proxyconfig.Domain
	IP       string
	Country  string
	Target   *url.URL
	Redirect bool
}

func NewUserInfo(domain *proxyconfig.Domain) *UserInfo {
	return &UserInfo{
		Domain: domain,
	}
}

func populateUser(outreq *http.Request) (*UserInfo, error) {
	user, err := parseDomain(outreq.Host)
	if err != nil {
		return nil, err
	}

	host, err := user.populateIP(outreq.RemoteAddr)
	if err != nil {
		fmt.Println(err)
	} else {
		user.populateCountry(host)
	}

	err = user.populateTarget()
	if err != nil {
		return nil, err
	}

	fmt.Printf("--\nconnected user information %v\n", user)
	return user, nil
}

func (u *UserInfo) populateIP(remoteAddr string) (string, error) {
	host, _, err := net.SplitHostPort(remoteAddr)
	if err != nil {
		fmt.Printf("could not split host and port: %s", err.Error())
		return "", err
	}
	u.IP = host
	return host, nil
}

func (u *UserInfo) populateCountry(host string) {
	if geoIP != nil {
		loc := geoIP.GetLocationByIP(host)
		if loc != nil {
			u.Country = loc.CountryName
		}
	}
}

func (u *UserInfo) populateTarget() error {
	var err error
	username := u.Domain.Proxy.Username
	servicename := u.Domain.Proxy.Servicename
	key := u.Domain.Proxy.Key
	hostnameAlias := u.Domain.HostnameAlias[0]
	fullurl := u.Domain.Proxy.FullUrl

	switch u.Domain.Proxy.Mode {
	case "direct":
		u.Target, err = url.Parse("http://" + fullurl)
		if err != nil {
			return err
		}
		return nil
	case "vm":
		var vm virt.VM

		if err := db.VMs.Find(bson.M{"hostnameAlias": hostnameAlias}).One(&vm); err != nil {
			u.Target, _ = url.Parse("http://www.koding.com/notfound.html")
			u.Redirect = true
			return nil
		}
		if vm.IP == nil {
			u.Target, _ = url.Parse("http://www.koding.com/notactive.html")
			u.Redirect = true
			return nil
		}
		u.Target, err = url.Parse("http://" + vm.IP.String())
		if err != nil {
			return err
		}

		return nil
	case "internal":
		break // internal is done below
	}

	keyData, err := proxyDB.GetKey(username, servicename, key)
	if err != nil {
		return fmt.Errorf("no keyData for username '%s', servicename '%s' and key '%s'", username, servicename, key)
	}

	var hostname string
	switch keyData.Mode {
	case "roundrobin":
		N := float64(len(keyData.Host))
		n := int(math.Mod(float64(keyData.CurrentIndex+1), N))
		hostname = keyData.Host[n]

		keyData.CurrentIndex = n
		go proxyDB.UpdateKeyData(username, servicename, keyData)
	case "sticky":
		hostname = keyData.Host[keyData.CurrentIndex]
	}

	u.Target, err = url.Parse("http://" + hostname)<commit_msg>kontrolproxy: domains load balancing, WIP<commit_after>package main

import (
	"fmt"
	"koding/kontrol/kontrolproxy/proxyconfig"
	"koding/tools/db"
	"koding/virt"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"math"
	"net"
	"net/http"
	"net/url"
	"strings"
)

type UserInfo struct {
	Domain   *proxyconfig.Domain
	IP       string
	Country  string
	Target   *url.URL
	Redirect bool
}

func NewUserInfo(domain *proxyconfig.Domain) *UserInfo {
	return &UserInfo{
		Domain: domain,
	}
}

func populateUser(outreq *http.Request) (*UserInfo, error) {
	user, err := parseDomain(outreq.Host)
	if err != nil {
		return nil, err
	}

	host, err := user.populateIP(outreq.RemoteAddr)
	if err != nil {
		fmt.Println(err)
	} else {
		user.populateCountry(host)
	}

	err = user.populateTarget()
	if err != nil {
		return nil, err
	}

	fmt.Printf("--\nconnected user information %v\n", user)
	return user, nil
}

func (u *UserInfo) populateIP(remoteAddr string) (string, error) {
	host, _, err := net.SplitHostPort(remoteAddr)
	if err != nil {
		fmt.Printf("could not split host and port: %s", err.Error())
		return "", err
	}
	u.IP = host
	return host, nil
}

func (u *UserInfo) populateCountry(host string) {
	if geoIP != nil {
		loc := geoIP.GetLocationByIP(host)
		if loc != nil {
			u.Country = loc.CountryName
		}
	}
}

func (u *UserInfo) populateTarget() error {
	var err error
	var hostname string

	username := u.Domain.Proxy.Username
	servicename := u.Domain.Proxy.Servicename
	key := u.Domain.Proxy.Key
	fullurl := u.Domain.Proxy.FullUrl

	switch u.Domain.Proxy.Mode {
	case "direct":
		u.Target, err = url.Parse("http://" + fullurl)
		if err != nil {
			return err
		}
		return nil
	case "vm":
		switch u.Domain.LoadBalancer.Mode {
		case "roundrobin":
			N := float64(len(u.Domain.HostnameAlias))
			n := int(math.Mod(float64(u.Domain.LoadBalancer.Index+1), N))
			hostname = u.Domain.HostnameAlias[n]

			u.Domain.LoadBalancer.Index = n
			go proxyDB.UpdateDomain(u.Domain)
		case "sticky":
			hostname = u.Domain.HostnameAlias[u.Domain.LoadBalancer.Index]
			// sessionName := fmt.Sprintf("kodingproxy-%s-%s", u.Domain.Domain, u.IP)
			// // We're ignoring the error resulted from decoding an existing
			// // session: Get() always returns a session, even if empty.
			// session, _ := store.Get(req, sessionName)
			// _, ok := session.Values["JSESSIONID"]
		case "default":
			hostname = u.Domain.HostnameAlias[0]
		}

		var vm virt.VM
		if err := db.VMs.Find(bson.M{"hostnameAlias": hostname}).One(&vm); err != nil {
			u.Target, _ = url.Parse("http://www.koding.com/notfound.html")
			u.Redirect = true
			return nil
		}
		if vm.IP == nil {
			u.Target, _ = url.Parse("http://www.koding.com/notactive.html")
			u.Redirect = true
			return nil
		}
		u.Target, err = url.Parse("http://" + vm.IP.String())
		if err != nil {
			return err
		}

		return nil
	case "internal":
		break // internal is done below
	}

	keyData, err := proxyDB.GetKey(username, servicename, key)
	if err != nil {
		return fmt.Errorf("no keyData for username '%s', servicename '%s' and key '%s'", username, servicename, key)
	}

	switch keyData.Mode {
	case "roundrobin":
		N := float64(len(keyData.Host))
		n := int(math.Mod(float64(keyData.CurrentIndex+1), N))
		hostname = keyData.Host[n]

		keyData.CurrentIndex = n
		go proxyDB.UpdateKeyData(username, servicename, keyData)
	case "sticky":
		hostname = keyData.Host[keyData.CurrentIndex]
	}

	u.Target, err = url.Parse("http://" + hostname)
{'fraction_non_alphanumeric': 0.15008025682182985, 'fraction_numerical': 0.0033707865168539327, 'mean_word_length': 3.511947863866763, 'pattern_counts': {'":': 15, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4321154', 'n_tokens_mistral': 2481, 'n_tokens_neox': 2312, 'n_words': 539}