<commit_before>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package util_test

import (
	"encoding/json"
	"fmt"
	"testing"

	"github.com/open-policy-agent/opa/util"
)

func TestRoundTrip(t *testing.T) {
	cases := []interface{}{
		nil,
		1,
		1.1,
		false,
		[]int{1},
		[]bool{true},
		[]string{"foo"},
		map[string]string{"foo": "bar"},
		struct {
			F string `json:"foo"`
			B int    `json:"bar"`
		}{"x", 32},
		map[string][]int{
			"ones": {1, 1, 1},
		},
	}
	for _, tc := range cases {
		t.Run(fmt.Sprintf("input %v", tc), func(t *testing.T) {
			err := util.RoundTrip(&tc)
			if err != nil {
				t.Errorf("expected error=nil, got %s", err.Error())
			}
			switch x := tc.(type) {
			// These are the output types we want, nothing else
			case nil, bool, json.Number, int64, float64, int, string, []interface{},
				[]string, map[string]interface{}, map[string]string:
			default:
				t.Errorf("unexpected type %T", x)
			}
		})
	}
}
<commit_msg>json_test: add util.Reference test<commit_after>// Copyright 2018 The OPA Authors.  All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package util_test

import (
	"encoding/json"
	"fmt"
	"reflect"
	"testing"

	"github.com/open-policy-agent/opa/util"
)

func TestRoundTrip(t *testing.T) {
	cases := []interface{}{
		nil,
		1,
		1.1,
		false,
		[]int{1},
		[]bool{true},
		[]string{"foo"},
		map[string]string{"foo": "bar"},
		struct {
			F string `json:"foo"`
			B int    `json:"bar"`
		}{"x", 32},
		map[string][]int{
			"ones": {1, 1, 1},
		},
	}
	for _, tc := range cases {
		t.Run(fmt.Sprintf("input %v", tc), func(t *testing.T) {
			err := util.RoundTrip(&tc)
			if err != nil {
				t.Errorf("expected error=nil, got %s", err.Error())
			}
			switch x := tc.(type) {
			// These are the output types we want, nothing else
			case nil, bool, json.Number, int64, float64, int, string, []interface{},
				[]string, map[string]interface{}, map[string]string:
			default:
				t.Errorf("unexpected type %T", x)
			}
		})
	}
}

func TestReference(t *testing.T) {
	cases := []interface{}{
		nil,
		func() interface{} { f := interface{}(nil); return &f }(),
		1,
		func() interface{} { f := 1; return &f }(),
		1.1,
		func() interface{} { f := 1.1; return &f }(),
		false,
		func() interface{} { f := false; return &f }(),
		[]int{1},
		&[]int{1},
		func() interface{} { f := &[]int{1}; return &f }(),
		[]bool{true},
		&[]bool{true},
		func() interface{} { f := &[]bool{true}; return &f }(),
		[]string{"foo"},
		&[]string{"foo"},
		func() interface{} { f := &[]string{"foo"}; return &f }(),
		map[string]string{"foo": "bar"},
		&map[string]string{"foo": "bar"},
		func() interface{} { f := &map[string]string{"foo": "bar"}; return &f }(),
		struct {
			F string `json:"foo"`
			B int    `json:"bar"`
		}{"x", 32},
		&struct {
			F string `json:"foo"`
			B int    `json:"bar"`
		}{"x", 32},
		map[string][]int{
			"ones": {1, 1, 1},
		},
		&map[string][]int{
			"ones": {1, 1, 1},
		},
	}
	for _, tc := range cases {
		t.Run(fmt.Sprintf("input %v", tc), func(t *testing.T) {
			ref := util.Reference(tc)
			rv := reflect.ValueOf(ref)
			if rv.Kind() != reflect.Ptr {
				t.Fatalf("expected pointer, got %v", rv.Kind())
			}
			if rv.Elem().Kind() == reflect.Ptr {
				t.Error("expected non-pointer element")
			}
		})
	}
}
<|endoftext|>


<commit_before>// +build linux

package ipvs

const (
	genlCtrlID = 0x10
)

// GENL control commands
const (
	genlCtrlCmdUnspec uint8 = iota
	genlCtrlCmdNewFamily
	genlCtrlCmdDelFamily
	genlCtrlCmdGetFamily
)

// GENL family attributes
const (
	genlCtrlAttrUnspec int = iota
	genlCtrlAttrFamilyID
	genlCtrlAttrFamilyName
)

// IPVS genl commands
const (
	ipvsCmdUnspec uint8 = iota
	ipvsCmdNewService
	ipvsCmdSetService
	ipvsCmdDelService
	ipvsCmdGetService
	ipvsCmdNewDest
	ipvsCmdSetDest
	ipvsCmdDelDest
	ipvsCmdGetDest
	ipvsCmdNewDaemon
	ipvsCmdDelDaemon
	ipvsCmdGetDaemon
	ipvsCmdSetConfig
	ipvsCmdGetConfig
	ipvsCmdSetInfo
	ipvsCmdGetInfo
	ipvsCmdZero
	ipvsCmdFlush
)

// Attributes used in the first level of commands
const (
	ipvsCmdAttrUnspec int = iota
	ipvsCmdAttrService
	ipvsCmdAttrDest
	ipvsCmdAttrDaemon
	ipvsCmdAttrTimeoutTCP
	ipvsCmdAttrTimeoutTCPFin
	ipvsCmdAttrTimeoutUDP
)

// Attributes used to describe a service. Used inside nested attribute
// ipvsCmdAttrService
const (
	ipvsSvcAttrUnspec int = iota
	ipvsSvcAttrAddressFamily
	ipvsSvcAttrProtocol
	ipvsSvcAttrAddress
	ipvsSvcAttrPort
	ipvsSvcAttrFWMark
	ipvsSvcAttrSchedName
	ipvsSvcAttrFlags
	ipvsSvcAttrTimeout
	ipvsSvcAttrNetmask
	ipvsSvcAttrStats
	ipvsSvcAttrPEName
)

// Attributes used to describe a destination (real server). Used
// inside nested attribute ipvsCmdAttrDest.
const (
	ipvsDestAttrUnspec int = iota
	ipvsDestAttrAddress
	ipvsDestAttrPort
	ipvsDestAttrForwardingMethod
	ipvsDestAttrWeight
	ipvsDestAttrUpperThreshold
	ipvsDestAttrLowerThreshold
	ipvsDestAttrActiveConnections
	ipvsDestAttrInactiveConnections
	ipvsDestAttrPersistentConnections
	ipvsDestAttrStats
	ipvsDestAttrAddressFamily
)

// IPVS Svc Statistics constancs

const (
	ipvsSvcStatsUnspec int = iota
	ipvsSvcStatsConns
	ipvsSvcStatsPktsIn
	ipvsSvcStatsPktsOut
	ipvsSvcStatsBytesIn
	ipvsSvcStatsBytesOut
	ipvsSvcStatsCPS
	ipvsSvcStatsPPSIn
	ipvsSvcStatsPPSOut
	ipvsSvcStatsBPSIn
	ipvsSvcStatsBPSOut
)

// Destination forwarding methods
const (
	// ConnectionFlagFwdmask indicates the mask in the connection
	// flags which is used by forwarding method bits.
	ConnectionFlagFwdMask = 0x0007

	// ConnectionFlagMasq is used for masquerade forwarding method.
	ConnectionFlagMasq = 0x0000

	// ConnectionFlagLocalNode is used for local node forwarding
	// method.
	ConnectionFlagLocalNode = 0x0001

	// ConnectionFlagTunnel is used for tunnel mode forwarding
	// method.
	ConnectionFlagTunnel = 0x0002

	// ConnectionFlagDirectRoute is used for direct routing
	// forwarding method.
	ConnectionFlagDirectRoute = 0x0003
)

const (
	// RoundRobin distributes jobs equally amongst the available
	// real servers.
	RoundRobin = "rr"

	// LeastConnection assigns more jobs to real servers with
	// fewer active jobs.
	LeastConnection = "lc"

	// DestinationHashing assigns jobs to servers through looking
	// up a statically assigned hash table by their destination IP
	// addresses.
	DestinationHashing = "dh"

	// SourceHashing assigns jobs to servers through looking up
	// a statically assigned hash table by their source IP
	// addresses.
	SourceHashing = "sh"
)

const (
	// ConnFwdMask is a mask for the fwd methods
	ConnFwdMask = 0x0007

	// ConnFwdMasq denotes forwarding via masquerading/NAT
	ConnFwdMasq = 0x0000

	// ConnFwdLocalNode denotes forwarding to a local node
	ConnFwdLocalNode = 0x0001

	// ConnFwdTunnel denotes forwarding via a tunnel
	ConnFwdTunnel = 0x0002

	// ConnFwdDirectRoute denotes forwarding via direct routing
	ConnFwdDirectRoute = 0x0003

	// ConnFwdBypass denotes forwarding while bypassing the cache
	ConnFwdBypass = 0x0004
)
<commit_msg>weighted scheduling methods constants for ipvs Signed-off-by: Jakub Drahos <jack.drahos@gmail.com><commit_after>// +build linux

package ipvs

const (
	genlCtrlID = 0x10
)

// GENL control commands
const (
	genlCtrlCmdUnspec uint8 = iota
	genlCtrlCmdNewFamily
	genlCtrlCmdDelFamily
	genlCtrlCmdGetFamily
)

// GENL family attributes
const (
	genlCtrlAttrUnspec int = iota
	genlCtrlAttrFamilyID
	genlCtrlAttrFamilyName
)

// IPVS genl commands
const (
	ipvsCmdUnspec uint8 = iota
	ipvsCmdNewService
	ipvsCmdSetService
	ipvsCmdDelService
	ipvsCmdGetService
	ipvsCmdNewDest
	ipvsCmdSetDest
	ipvsCmdDelDest
	ipvsCmdGetDest
	ipvsCmdNewDaemon
	ipvsCmdDelDaemon
	ipvsCmdGetDaemon
	ipvsCmdSetConfig
	ipvsCmdGetConfig
	ipvsCmdSetInfo
	ipvsCmdGetInfo
	ipvsCmdZero
	ipvsCmdFlush
)

// Attributes used in the first level of commands
const (
	ipvsCmdAttrUnspec int = iota
	ipvsCmdAttrService
	ipvsCmdAttrDest
	ipvsCmdAttrDaemon
	ipvsCmdAttrTimeoutTCP
	ipvsCmdAttrTimeoutTCPFin
	ipvsCmdAttrTimeoutUDP
)

// Attributes used to describe a service. Used inside nested attribute
// ipvsCmdAttrService
const (
	ipvsSvcAttrUnspec int = iota
	ipvsSvcAttrAddressFamily
	ipvsSvcAttrProtocol
	ipvsSvcAttrAddress
	ipvsSvcAttrPort
	ipvsSvcAttrFWMark
	ipvsSvcAttrSchedName
	ipvsSvcAttrFlags
	ipvsSvcAttrTimeout
	ipvsSvcAttrNetmask
	ipvsSvcAttrStats
	ipvsSvcAttrPEName
)

// Attributes used to describe a destination (real server). Used
// inside nested attribute ipvsCmdAttrDest.
const (
	ipvsDestAttrUnspec int = iota
	ipvsDestAttrAddress
	ipvsDestAttrPort
	ipvsDestAttrForwardingMethod
	ipvsDestAttrWeight
	ipvsDestAttrUpperThreshold
	ipvsDestAttrLowerThreshold
	ipvsDestAttrActiveConnections
	ipvsDestAttrInactiveConnections
	ipvsDestAttrPersistentConnections
	ipvsDestAttrStats
	ipvsDestAttrAddressFamily
)

// IPVS Svc Statistics constancs

const (
	ipvsSvcStatsUnspec int = iota
	ipvsSvcStatsConns
	ipvsSvcStatsPktsIn
	ipvsSvcStatsPktsOut
	ipvsSvcStatsBytesIn
	ipvsSvcStatsBytesOut
	ipvsSvcStatsCPS
	ipvsSvcStatsPPSIn
	ipvsSvcStatsPPSOut
	ipvsSvcStatsBPSIn
	ipvsSvcStatsBPSOut
)

// Destination forwarding methods
const (
	// ConnectionFlagFwdmask indicates the mask in the connection
	// flags which is used by forwarding method bits.
	ConnectionFlagFwdMask = 0x0007

	// ConnectionFlagMasq is used for masquerade forwarding method.
	ConnectionFlagMasq = 0x0000

	// ConnectionFlagLocalNode is used for local node forwarding
	// method.
	ConnectionFlagLocalNode = 0x0001

	// ConnectionFlagTunnel is used for tunnel mode forwarding
	// method.
	ConnectionFlagTunnel = 0x0002

	// ConnectionFlagDirectRoute is used for direct routing
	// forwarding method.
	ConnectionFlagDirectRoute = 0x0003
)

const (
	// RoundRobin distributes jobs equally amongst the available
	// real servers.
	RoundRobin = "rr"

	// LeastConnection assigns more jobs to real servers with
	// fewer active jobs.
	LeastConnection = "lc"

	// DestinationHashing assigns jobs to servers through looking
	// up a statically assigned hash table by their destination IP
	// addresses.
	DestinationHashing = "dh"

	// SourceHashing assigns jobs to servers through looking up
	// a statically assigned hash table by their source IP
	// addresses.
	SourceHashing = "sh"

	// WeightedRoundRobin assigns jobs to real servers proportionally
	// to there real servers' weight. Servers with higher weights
	// receive new jobs first and get more jobs than servers
	// with lower weights. Servers with equal weights get
	// an equal distribution of new jobs
	WeightedRoundRobin = "wrr"

	// WeightedLeastConnection assigns more jobs to servers
	// with fewer jobs and relative to the real servers' weight
	WeightedLeastConnection = "wlc"
)

const (
	// ConnFwdMask is a mask for the fwd methods
	ConnFwdMask = 0x0007

	// ConnFwdMasq denotes forwarding via masquerading/NAT
	ConnFwdMasq = 0x0000

	// ConnFwdLocalNode denotes forwarding to a local node
	ConnFwdLocalNode = 0x0001

	// ConnFwdTunnel denotes forwarding via a tunnel
	ConnFwdTunnel = 0x0002

	// ConnFwdDirectRoute denotes forwarding via direct routing
	ConnFwdDirectRoute = 0x0003

	// ConnFwdBypass denotes forwarding while bypassing the cache
	ConnFwdBypass = 0x0004
)
<|endoftext|>


<commit_before>package util

import (
	"compress/gzip"
	"encoding/gob"
	"fmt"
	"io"
	"os"
	path "path/filepath"
	"strconv"
	"strings"

	"github.com/TuftsBCB/fragbag"
	"github.com/TuftsBCB/fragbag/bow"
	"github.com/TuftsBCB/fragbag/bowdb"
	"github.com/TuftsBCB/hhfrag"
	"github.com/TuftsBCB/io/msa"
	"github.com/TuftsBCB/io/pdb"
	"github.com/TuftsBCB/seq"
)

func Library(fpath string) fragbag.Library {
	libPath := os.Getenv("FRAGLIB_PATH")
	if !Exists(fpath) && len(libPath) > 0 {
		fpath = path.Join(libPath, fpath)
		if !strings.HasSuffix(fpath, ".json") {
			fpath += ".json"
		}
	}
	lib, err := fragbag.Open(OpenFile(fpath))
	Assert(err, "Could not open fragment library '%s'", fpath)
	return lib
}

func StructureLibrary(path string) fragbag.StructureLibrary {
	lib := Library(path)
	libStruct, ok := lib.(fragbag.StructureLibrary)
	if !ok {
		Fatalf("%s (%T) is not a structure library.", path, lib)
	}
	return libStruct
}

func SequenceLibrary(path string) fragbag.SequenceLibrary {
	lib := Library(path)
	libSeq, ok := lib.(fragbag.SequenceLibrary)
	if !ok {
		Fatalf("%s (%T) is not a sequence library.", path, lib)
	}
	return libSeq
}

func MSA(path string) seq.MSA {
	if strings.HasSuffix(path, "a2m") || strings.HasSuffix(path, "a3m") {
		aligned, err := msa.Read(OpenFile(path))
		Assert(err, "Could not read MSA (a2m/a3m) from '%s'", path)
		return aligned
	}
	aligned, err := msa.ReadFasta(OpenFile(path))
	Assert(err, "Could not read MSA (fasta) from '%s'", path)
	return aligned
}

func OpenBowDB(path string) *bowdb.DB {
	db, err := bowdb.Open(path)
	Assert(err, "Could not open BOW database '%s'", path)
	return db
}

func PDBOpenMust(fpath string) (*pdb.Entry, []*pdb.Chain) {
	entry, chains, err := PDBOpen(fpath)
	Assert(err)
	return entry, chains
}

func PDBOpen(fpath string) (*pdb.Entry, []*pdb.Chain, error) {
	pdbNameParse := func(fpath string) (string, []byte) {
		dir, base := path.Dir(fpath), path.Base(fpath)
		pieces := strings.Split(base, ":")

		var idents []byte
		base = pieces[0]
		if len(pieces) > 2 {
			Fatalf("Too many colons in PDB file path '%s'.", fpath)
		} else if len(pieces) == 2 {
			chains := strings.Split(pieces[1], ",")
			idents = make([]byte, len(chains))
			for i := range chains {
				if len(chains[i]) > 1 {
					Fatalf("Chain '%s' is more than one character.", chains[i])
				}
				idents[i] = byte(chains[i][0])
			}
		} else if len(base) == 5 { // special case for '{pdb-id}{chain-id}'
			idents = []byte{base[4]}
			base = base[0:4]
		}

		if dir == "." {
			switch len(base) {
			case 4:
				return PDBPath(base), idents
			case 6:
				return CathPath(base), idents
			case 7:
				if base[0] == 'd' {
					return ScopPath(base), idents
				} else {
					return CathPath(base), idents
				}
			}
		}
		return path.Join(dir, base), idents
	}

	fp, idents := pdbNameParse(fpath)
	entry, err := pdb.ReadPDB(fp)
	if err != nil {
		err = fmt.Errorf("Error reading '%s': %s", fp, err)
		return nil, nil, err
	}

	var chains []*pdb.Chain
	if len(idents) == 0 {
		chains = entry.Chains
	} else {
		chains = make([]*pdb.Chain, 0, 5)
		for _, c := range idents {
			chain := entry.Chain(c)
			if chain == nil {
				Warnf("Chain '%c' does not exist for '%s'.",
					c, entry.IdCode)
				continue
			}
			chains = append(chains, chain)
		}
	}
	return entry, chains, nil
}

func PDBRead(path string) *pdb.Entry {
	entry, err := pdb.ReadPDB(path)
	Assert(err, "Could not open PDB file '%s'", path)
	return entry
}

// PDBPath takes a PDB identifier (e.g., "1ctf" or "1ctfA") and returns
// the full path to the PDB file on the file system.
//
// The PDB_PATH environment variable must be set.
func PDBPath(pid string) string {
	if !IsPDBID(pid) && !IsChainID(pid) {
		Fatalf("PDB ids must contain 4 or 5 characters, but '%s' has %d.",
			pid, len(pid))
	}
	pdbPath := os.Getenv("PDB_PATH")
	if len(pdbPath) == 0 || !IsDir(pdbPath) {
		Fatalf("The PDB_PATH environment variable must be set to open " +
			"PDB chains by just their ID.\n" +
			"PDB_PATH should be set to the directory containing a full " +
			"copy of the PDB database.")
	}

	pdbid := strings.ToLower(pid[0:4])
	group := pdbid[1:3]
	basename := fmt.Sprintf("pdb%s.ent.gz", pdbid)
	return path.Join(pdbPath, group, basename)
}

// ScopPath takes a SCOP identifier (e.g., "d3ciua1" or "d1g09c_") and returns
// the full path to the PDB file on the file system.
//
// The SCOP_PDB_PATH environment variable must be set.
func ScopPath(pid string) string {
	if len(pid) != 7 {
		Fatalf("SCOP domain ids must contain 7 characters, but '%s' has %d.",
			pid, len(pid))
	}
	pdbPath := os.Getenv("SCOP_PDB_PATH")
	if len(pdbPath) == 0 || !IsDir(pdbPath) {
		Fatalf("The SCOP_PDB_PATH environment variable must be set to open " +
			"PDB files of SCOP domain by just their ID.\n" +
			"SCOP_PDB_PATH should be set to the directory containing a full " +
			"copy of the SCOP database as PDB formatted files.")
	}

	group := pid[2:4]
	basename := fmt.Sprintf("%s.ent", pid)
	return path.Join(pdbPath, group, basename)
}

// CathPath takes a CATH identifier (e.g., "2h5xB03") and returns
// the full path to the PDB file on the file system.
//
// The CATH_PDB_PATH environment variable must be set.
func CathPath(pid string) string {
	if len(pid) < 6 || len(pid) > 7 {
		Fatalf("CATH domain ids must contain 6 or 7 characters, but '%s' "+
			"has %d.", pid, len(pid))
	}
	pdbPath := os.Getenv("CATH_PDB_PATH")
	if len(pdbPath) == 0 || !IsDir(pdbPath) {
		Fatalf("The CATH_PDB_PATH environment variable must be set to open " +
			"PDB files of CATH domain by just their ID.\n" +
			"CATH_PDB_PATH should be set to the directory containing a full " +
			"copy of the CATH PDB database as PDB formatted files.")
	}

	// We have to deal with some old data sets using 6-character domain IDs.
	// This is a nightmare because there doesn't appear to be an easy
	// deterministic mapping.
	if len(pid) == 6 {
		if pid[4] == '0' {
			pid_ := fmt.Sprintf("%sA%s", pid[0:4], pid[4:6])
			if p := path.Join(pdbPath, pid_); Exists(p) {
				return p
			}
		}
		pid = fmt.Sprintf("%s0%c", pid[0:5], pid[5])
	}
	return path.Join(pdbPath, pid)
}

func PDBReadId(pid string) (*pdb.Entry, *pdb.Chain) {
	e := PDBRead(PDBPath(pid))
	if IsChainID(pid) {
		chain := e.Chain(pid[4])
		if chain == nil {
			Fatalf("Could not find chain '%s' in PDB entry '%s'.", pid[4], pid)
		}
		return e, chain
	}
	return e, nil
}

func GetFmap(fpath string) *hhfrag.FragmentMap {
	var fmap *hhfrag.FragmentMap
	var err error

	switch {
	case IsFasta(fpath):
		fmap, err = HHfragConf.MapFromFasta(FlagPdbHhmDB, FlagSeqDB, fpath)
		Assert(err, "Could not generate map from '%s'", fpath)
	case IsFmap(fpath):
		fmap = FmapRead(fpath)
	default:
		Fatalf("File '%s' is not a fasta or fmap file.", fpath)
	}

	return fmap
}

func FmapRead(path string) *hhfrag.FragmentMap {
	var fmap *hhfrag.FragmentMap
	f := OpenFile(path)
	defer f.Close()

	r := gob.NewDecoder(f)
	Assert(r.Decode(&fmap), "Could not GOB decode fragment map '%s'", path)
	return fmap
}

func FmapWrite(w io.Writer, fmap *hhfrag.FragmentMap) {
	encoder := gob.NewEncoder(w)
	Assert(encoder.Encode(fmap), "Could not GOB encode fragment map")
}

func BowRead(path string) bow.Bowed {
	var b bow.Bowed
	f := OpenFile(path)
	defer f.Close()

	r := gob.NewDecoder(f)
	Assert(r.Decode(&b), "Could not GOB decode BOW '%s'", path)
	return b
}

func BowWrite(w io.Writer, b bow.Bowed) {
	encoder := gob.NewEncoder(w)
	Assert(encoder.Encode(b), "Could not GOB encode BOW")
}

func OpenFile(path string) *os.File {
	f, err := os.Open(path)
	Assert(err, "Could not open file '%s'", path)
	return f
}

func CreateFile(path string) *os.File {
	f, err := os.Create(path)
	Assert(err, "Could not create file '%s'", path)
	return f
}

func ParseInt(str string) int {
	num, err := strconv.ParseInt(str, 10, 32)
	Assert(err, "Could not parse '%s' as an integer", str)
	return int(num)
}

func IsFasta(fpath string) bool {
	suffix := func(ext string) bool {
		return strings.HasSuffix(fpath, ext)
	}
	return suffix(".fasta") || suffix(".fas") ||
		suffix(".fasta.gz") || suffix(".fas.gz")
}

func OpenFasta(fpath string) io.Reader {
	if strings.HasSuffix(fpath, ".gz") {
		r, err := gzip.NewReader(OpenFile(fpath))
		Assert(err, "Could not open '%s'", fpath)
		return r
	}
	return OpenFile(fpath)
}

func IsFmap(fpath string) bool {
	return strings.HasSuffix(fpath, ".fmap")
}

func IsPDB(fpath string) bool {
	pieces := strings.Split(path.Base(fpath), ":")
	base := pieces[0]
	if path.Dir(fpath) == "." && len(base) >= 4 && len(base) <= 7 {
		return true
	}

	suffix := func(ext string) bool {
		return strings.HasSuffix(base, ext)
	}
	return suffix(".ent.gz") || suffix(".pdb") || suffix(".ent")
}

func IsChainID(s string) bool {
	return len(s) == 5
}

func IsPDBID(s string) bool {
	return len(s) == 4
}
<commit_msg>Output SCOP/CATH id given in pairdists instead of using the real id.<commit_after>package util

import (
	"compress/gzip"
	"encoding/gob"
	"fmt"
	"io"
	"os"
	path "path/filepath"
	"strconv"
	"strings"

	"github.com/TuftsBCB/fragbag"
	"github.com/TuftsBCB/fragbag/bow"
	"github.com/TuftsBCB/fragbag/bowdb"
	"github.com/TuftsBCB/hhfrag"
	"github.com/TuftsBCB/io/msa"
	"github.com/TuftsBCB/io/pdb"
	"github.com/TuftsBCB/seq"
)

func Library(fpath string) fragbag.Library {
	libPath := os.Getenv("FRAGLIB_PATH")
	if !Exists(fpath) && len(libPath) > 0 {
		fpath = path.Join(libPath, fpath)
		if !strings.HasSuffix(fpath, ".json") {
			fpath += ".json"
		}
	}
	lib, err := fragbag.Open(OpenFile(fpath))
	Assert(err, "Could not open fragment library '%s'", fpath)
	return lib
}

func StructureLibrary(path string) fragbag.StructureLibrary {
	lib := Library(path)
	libStruct, ok := lib.(fragbag.StructureLibrary)
	if !ok {
		Fatalf("%s (%T) is not a structure library.", path, lib)
	}
	return libStruct
}

func SequenceLibrary(path string) fragbag.SequenceLibrary {
	lib := Library(path)
	libSeq, ok := lib.(fragbag.SequenceLibrary)
	if !ok {
		Fatalf("%s (%T) is not a sequence library.", path, lib)
	}
	return libSeq
}

func MSA(path string) seq.MSA {
	if strings.HasSuffix(path, "a2m") || strings.HasSuffix(path, "a3m") {
		aligned, err := msa.Read(OpenFile(path))
		Assert(err, "Could not read MSA (a2m/a3m) from '%s'", path)
		return aligned
	}
	aligned, err := msa.ReadFasta(OpenFile(path))
	Assert(err, "Could not read MSA (fasta) from '%s'", path)
	return aligned
}

func OpenBowDB(path string) *bowdb.DB {
	db, err := bowdb.Open(path)
	Assert(err, "Could not open BOW database '%s'", path)
	return db
}

func PDBOpenMust(fpath string) (*pdb.Entry, []*pdb.Chain) {
	entry, chains, err := PDBOpen(fpath)
	Assert(err)
	return entry, chains
}

func PDBOpen(fpath string) (*pdb.Entry, []*pdb.Chain, error) {
	pdbNameParse := func(fpath string) (string, []byte, string) {
		dir, base := path.Dir(fpath), path.Base(fpath)
		pieces := strings.Split(base, ":")

		var idents []byte
		base = pieces[0]
		if len(pieces) > 2 {
			Fatalf("Too many colons in PDB file path '%s'.", fpath)
		} else if len(pieces) == 2 {
			chains := strings.Split(pieces[1], ",")
			idents = make([]byte, len(chains))
			for i := range chains {
				if len(chains[i]) > 1 {
					Fatalf("Chain '%s' is more than one character.", chains[i])
				}
				idents[i] = byte(chains[i][0])
			}
		} else if len(base) == 5 { // special case for '{pdb-id}{chain-id}'
			idents = []byte{base[4]}
			base = base[0:4]
		}

		if dir == "." {
			switch len(base) {
			case 4:
				return PDBPath(base), idents, base
			case 6:
				return CathPath(base), idents, base
			case 7:
				if base[0] == 'd' {
					return ScopPath(base), idents, base
				} else {
					return CathPath(base), idents, base
				}
			}
		}
		return path.Join(dir, base), idents, ""
	}

	fp, idents, idcode := pdbNameParse(fpath)
	entry, err := pdb.ReadPDB(fp)
	if err != nil {
		err = fmt.Errorf("Error reading '%s': %s", fp, err)
		return nil, nil, err
	}
	if len(idcode) > 0 {
		if len(idcode) == 6 || (len(idcode) == 7 && idcode[0] != 'd') {
			entry.Cath = idcode
		} else if len(idcode) == 7 && idcode[0] == 'd' {
			entry.Scop = idcode
		}
	}

	var chains []*pdb.Chain
	if len(idents) == 0 {
		chains = entry.Chains
	} else {
		chains = make([]*pdb.Chain, 0, 5)
		for _, c := range idents {
			chain := entry.Chain(c)
			if chain == nil {
				Warnf("Chain '%c' does not exist for '%s'.",
					c, entry.IdCode)
				continue
			}
			chains = append(chains, chain)
		}
	}
	return entry, chains, nil
}

func PDBRead(path string) *pdb.Entry {
	entry, err := pdb.ReadPDB(path)
	Assert(err, "Could not open PDB file '%s'", path)
	return entry
}

// PDBPath takes a PDB identifier (e.g., "1ctf" or "1ctfA") and returns
// the full path to the PDB file on the file system.
//
// The PDB_PATH environment variable must be set.
func PDBPath(pid string) string {
	if !IsPDBID(pid) && !IsChainID(pid) {
		Fatalf("PDB ids must contain 4 or 5 characters, but '%s' has %d.",
			pid, len(pid))
	}
	pdbPath := os.Getenv("PDB_PATH")
	if len(pdbPath) == 0 || !IsDir(pdbPath) {
		Fatalf("The PDB_PATH environment variable must be set to open " +
			"PDB chains by just their ID.\n" +
			"PDB_PATH should be set to the directory containing a full " +
			"copy of the PDB database.")
	}

	pdbid := strings.ToLower(pid[0:4])
	group := pdbid[1:3]
	basename := fmt.Sprintf("pdb%s.ent.gz", pdbid)
	return path.Join(pdbPath, group, basename)
}

// ScopPath takes a SCOP identifier (e.g., "d3ciua1" or "d1g09c_") and returns
// the full path to the PDB file on the file system.
//
// The SCOP_PDB_PATH environment variable must be set.
func ScopPath(pid string) string {
	if len(pid) != 7 {
		Fatalf("SCOP domain ids must contain 7 characters, but '%s' has %d.",
			pid, len(pid))
	}
	pdbPath := os.Getenv("SCOP_PDB_PATH")
	if len(pdbPath) == 0 || !IsDir(pdbPath) {
		Fatalf("The SCOP_PDB_PATH environment variable must be set to open " +
			"PDB files of SCOP domain by just their ID.\n" +
			"SCOP_PDB_PATH should be set to the directory containing a full " +
			"copy of the SCOP database as PDB formatted files.")
	}

	group := pid[2:4]
	basename := fmt.Sprintf("%s.ent", pid)
	return path.Join(pdbPath, group, basename)
}

// CathPath takes a CATH identifier (e.g., "2h5xB03") and returns
// the full path to the PDB file on the file system.
//
// The CATH_PDB_PATH environment variable must be set.
func CathPath(pid string) string {
	if len(pid) < 6 || len(pid) > 7 {
		Fatalf("CATH domain ids must contain 6 or 7 characters, but '%s' "+
			"has %d.", pid, len(pid))
	}
	pdbPath := os.Getenv("CATH_PDB_PATH")
	if len(pdbPath) == 0 || !IsDir(pdbPath) {
		Fatalf("The CATH_PDB_PATH environment variable must be set to open " +
			"PDB files of CATH domain by just their ID.\n" +
			"CATH_PDB_PATH should be set to the directory containing a full " +
			"copy of the CATH PDB database as PDB formatted files.")
	}

	// We have to deal with some old data sets using 6-character domain IDs.
	// This is a nightmare because there doesn't appear to be an easy
	// deterministic mapping.
	if len(pid) == 6 {
		if pid[4] == '0' {
			pid_ := fmt.Sprintf("%sA%s", pid[0:4], pid[4:6])
			if p := path.Join(pdbPath, pid_); Exists(p) {
				return p
			}
		}
		pid = fmt.Sprintf("%s0%c", pid[0:5], pid[5])
	}
	return path.Join(pdbPath, pid)
}

func PDBReadId(pid string) (*pdb.Entry, *pdb.Chain) {
	e := PDBRead(PDBPath(pid))
	if IsChainID(pid) {
		chain := e.Chain(pid[4])
		if chain == nil {
			Fatalf("Could not find chain '%s' in PDB entry '%s'.", pid[4], pid)
		}
		return e, chain
	}
	return e, nil
}

func GetFmap(fpath string) *hhfrag.FragmentMap {
	var fmap *hhfrag.FragmentMap
	var err error

	switch {
	case IsFasta(fpath):
		fmap, err = HHfragConf.MapFromFasta(FlagPdbHhmDB, FlagSeqDB, fpath)
		Assert(err, "Could not generate map from '%s'", fpath)
	case IsFmap(fpath):
		fmap = FmapRead(fpath)
	default:
		Fatalf("File '%s' is not a fasta or fmap file.", fpath)
	}

	return fmap
}

func FmapRead(path string) *hhfrag.FragmentMap {
	var fmap *hhfrag.FragmentMap
	f := OpenFile(path)
	defer f.Close()

	r := gob.NewDecoder(f)
	Assert(r.Decode(&fmap), "Could not GOB decode fragment map '%s'", path)
	return fmap
}

func FmapWrite(w io.Writer, fmap *hhfrag.FragmentMap) {
	encoder := gob.NewEncoder(w)
	Assert(encoder.Encode(fmap), "Could not GOB encode fragment map")
}

func BowRead(path string) bow.Bowed {
	var b bow.Bowed
	f := OpenFile(path)
	defer f.Close()

	r := gob.NewDecoder(f)
	Assert(r.Decode(&b), "Could not GOB decode BOW '%s'", path)
	return b
}

func BowWrite(w io.Writer, b bow.Bowed) {
	encoder := gob.NewEncoder(w)
	Assert(encoder.Encode(b), "Could not GOB encode BOW")
}

func OpenFile(path string) *os.File {
	f, err := os.Open(path)
	Assert(err, "Could not open file '%s'", path)
	return f
}

func CreateFile(path string) *os.File {
	f, err := os.Create(path)
	Assert(err, "Could not create file '%s'", path)
	return f
}

func ParseInt(str string) int {
	num, err := strconv.ParseInt(str, 10, 32)
	Assert(err, "Could not parse '%s' as an integer", str)
	return int(num)
}

func IsFasta(fpath string) bool {
	suffix := func(ext string) bool {
		return strings.HasSuffix(fpath, ext)
	}
	return suffix(".fasta") || suffix(".fas") ||
		suffix(".fasta.gz") || suffix(".fas.gz")
}

func OpenFasta(fpath string) io.Reader {
	if strings.HasSuffix(fpath, ".gz") {
		r, err := gzip.NewReader(OpenFile(fpath))
		Assert(err, "Could not open '%s'", fpath)
		return r
	}
	return OpenFile(fpath)
}

func IsFmap(fpath string) bool {
	return strings.HasSuffix(fpath, ".fmap")
}

func IsPDB(fpath string) bool {
	pieces := strings.Split(path.Base(fpath), ":")
	base := pieces[0]
	if path.Dir(fpath) == "." && len(base) >= 4 && len(base) <= 7 {
		return true
	}

	suffix := func(ext string) bool {
		return strings.HasSuffix(base, ext)
	}
	return suffix(".ent.gz") || suffix(".pdb") || suffix(".ent")
}

func IsChainID(s string) bool {
	return len(s) == 5
}

func IsPDBID(s string) bool {
	return len(s) == 4
}
<|endoftext|>


<commit_before>package util

type Semaphore chan struct{}

func NewSemaphore(n int) Semaphore {
	return make(Semaphore, n)
}

func (s Semaphore) Acquire() {
	s <- struct{}{}
}

func (s Semaphore) Release() {
	<-s
}
<commit_msg>rename NewSemaphore -> MakeSemaphore<commit_after>package util

type Semaphore chan struct{}

func MakeSemaphore(n int) Semaphore {
	return make(Semaphore, n)
}

func (s Semaphore) Acquire() {
	s <- struct{}{}
}

func (s Semaphore) Release() {
	<-s
}
<|endoftext|>


<commit_before>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

   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.

      Based on http://github.com/nf/webfront

   @author: Juliano Martinez
*/

package http_server

import (
	"errors"
	"fmt"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func xff(req *http.Request) string {
	remote_addr := strings.Split(req.RemoteAddr, ":")
	if len(remote_addr) == 0 {
		return ""
	}
	return remote_addr[0]
}

type Server struct {
	mu      sync.RWMutex
	proxy   map[string][]Proxy
	backend map[string]int
}

type Proxy struct {
	//	last    time.Time
	Backend string
	handler http.Handler
}

func Listen(fd int, addr string) net.Listener {
	var l net.Listener
	var err error
	if fd >= 3 {
		l, err = net.FileListener(os.NewFile(uintptr(fd), "http"))
	} else {
		l, err = net.Listen("tcp", addr)
	}
	if err != nil {
		log.Fatal(err)
	}
	return l
}

func NewServer(probe time.Duration) (*Server, error) {
	s := new(Server)
	s.proxy = make(map[string][]Proxy)
	s.backend = make(map[string]int)
	go s.probe_backends(probe)
	return s, nil
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h := s.handler(r); h != nil {
		client := xff(r)
		hpr_utils.Log(fmt.Sprintf("Request from: %s Url: %s", client, r.Host))
		r.Header.Add("X-Forwarded-For", client)
		r.Header.Add("X-Real-IP", client)
		h.ServeHTTP(w, r)
		return
	}
	http.Error(w, "Not found.", http.StatusNotFound)
}

func (s *Server) handler(req *http.Request) http.Handler {
	vhost := req.Host
	if i := strings.Index(vhost, ":"); i >= 0 {
		vhost = vhost[:i]
	}

	s.mu.RLock()
	_, ok := s.proxy[vhost]
	if !ok {
		err := s.populate_proxies(vhost)
		if err != nil {
			hpr_utils.Log(fmt.Sprintf("%s for vhost %s", err, vhost))
			return nil
		}
	}
	s.mu.RUnlock()
	return s.Next(vhost)
}

func (s *Server) populate_proxies(vhost string) (err error) {
	f, _ := rc.ZRange(fmt.Sprintf("hpr-backends::%s", vhost), 0, -1, true)
	if len(f) == 0 {
		return errors.New("Backend list is empty")
	}

	var url string
	for _, be := range f {
		count, err := strconv.Atoi(be)
		if err != nil {
			url = be
			continue
		}

		for r := 1; r <= count; r++ {
			s.proxy[vhost] = append(s.proxy[vhost],
				Proxy{fmt.Sprintf("http://%s", url), makeHandler(url)})
		}
	}
	return
}

/* TODO: Implement more balance algorithms */
func (s *Server) Next(vhost string) http.Handler {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.backend[vhost]++
	total := len(s.proxy[vhost])
	if s.backend[vhost] >= total {
		s.backend[vhost] = 0
	}
	hpr_utils.Log(fmt.Sprintf(
		"Using backend: %s Url: %s", s.proxy[vhost][s.backend[vhost]].Backend, vhost))
	return s.proxy[vhost][s.backend[vhost]].handler
}

/* TODO: Implement more probes */
func (s *Server) probe_backends(probe time.Duration) {
	transport := http.Transport{Dial: dialTimeout}
	client := &http.Client{
		Transport: &transport,
	}

	for {
		time.Sleep(probe)

		s.mu.Lock()
		for vhost, backends := range s.proxy {
			// err := s.populate_proxies(vhost)
			fmt.Printf("%v", backends)
			fmt.Println(len(backends))
			is_dead := make(map[string]bool)
			removed := 0
			for backend := range backends {
				backend = backend - removed
				fmt.Println(backend)
				hpr_utils.Log(fmt.Sprintf(
					"vhost: %s backends: %s", vhost, s.proxy[vhost][backend].Backend))
				if is_dead[s.proxy[vhost][backend].Backend] {
					hpr_utils.Log(fmt.Sprintf("Removing dead backend: %s", s.proxy[vhost][backend].Backend))
					s.proxy[vhost] = s.proxy[vhost][:backend+copy(s.proxy[vhost][backend:], s.proxy[vhost][backend+1:])]
					removed++
				}

				_, err := client.Get(s.proxy[vhost][backend].Backend)
				if err != nil {
					hpr_utils.Log(fmt.Sprintf("Removing dead backend: %s", s.proxy[vhost][backend].Backend))
					s.proxy[vhost] = s.proxy[vhost][:backend+copy(s.proxy[vhost][backend:], s.proxy[vhost][backend+1:])]
					is_dead[s.proxy[vhost][backend].Backend] = true
					removed++
				} else {
					hpr_utils.Log(fmt.Sprintf("Alive: %s", s.proxy[vhost][backend].Backend))
				}
			}

		}
		s.mu.Unlock()
	}
}

func dialTimeout(network, addr string) (net.Conn, error) {
	timeout := time.Duration(2 * time.Second)
	return net.DialTimeout(network, addr, timeout)
}

func makeHandler(f string) http.Handler {
	if f != "" {
		return &httputil.ReverseProxy{
			Director: func(req *http.Request) {
				req.URL.Scheme = "http"
				req.URL.Host = f
			},
		}
	}
	return nil
}
<commit_msg>changing positions<commit_after>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

   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.

      Based on http://github.com/nf/webfront

   @author: Juliano Martinez
*/

package http_server

import (
	"errors"
	"fmt"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func xff(req *http.Request) string {
	remote_addr := strings.Split(req.RemoteAddr, ":")
	if len(remote_addr) == 0 {
		return ""
	}
	return remote_addr[0]
}

type Server struct {
	mu      sync.RWMutex
	proxy   map[string][]Proxy
	backend map[string]int
}

type Proxy struct {
	//	last    time.Time
	Backend string
	handler http.Handler
}

func Listen(fd int, addr string) net.Listener {
	var l net.Listener
	var err error
	if fd >= 3 {
		l, err = net.FileListener(os.NewFile(uintptr(fd), "http"))
	} else {
		l, err = net.Listen("tcp", addr)
	}
	if err != nil {
		log.Fatal(err)
	}
	return l
}

func NewServer(probe time.Duration) (*Server, error) {
	s := new(Server)
	s.proxy = make(map[string][]Proxy)
	s.backend = make(map[string]int)
	go s.probe_backends(probe)
	return s, nil
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h := s.handler(r); h != nil {
		client := xff(r)
		hpr_utils.Log(fmt.Sprintf("Request from: %s Url: %s", client, r.Host))
		r.Header.Add("X-Forwarded-For", client)
		r.Header.Add("X-Real-IP", client)
		h.ServeHTTP(w, r)
		return
	}
	http.Error(w, "Not found.", http.StatusNotFound)
}

func (s *Server) handler(req *http.Request) http.Handler {
	vhost := req.Host
	if i := strings.Index(vhost, ":"); i >= 0 {
		vhost = vhost[:i]
	}

	s.mu.RLock()
	_, ok := s.proxy[vhost]
	if !ok {
		err := s.populate_proxies(vhost)
		if err != nil {
			hpr_utils.Log(fmt.Sprintf("%s for vhost %s", err, vhost))
			return nil
		}
	}
	s.mu.RUnlock()
	return s.Next(vhost)
}

func (s *Server) populate_proxies(vhost string) (err error) {
	f, _ := rc.ZRange(fmt.Sprintf("hpr-backends::%s", vhost), 0, -1, true)
	if len(f) == 0 {
		return errors.New("Backend list is empty")
	}

	var url string
	for _, be := range f {
		count, err := strconv.Atoi(be)
		if err != nil {
			url = be
			continue
		}

		for r := 1; r <= count; r++ {
			s.proxy[vhost] = append(s.proxy[vhost],
				Proxy{fmt.Sprintf("http://%s", url), makeHandler(url)})
		}
	}
	return
}

/* TODO: Implement more balance algorithms */
func (s *Server) Next(vhost string) http.Handler {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.backend[vhost]++
	total := len(s.proxy[vhost])
	if s.backend[vhost] >= total {
		s.backend[vhost] = 0
	}
	hpr_utils.Log(fmt.Sprintf(
		"Using backend: %s Url: %s", s.proxy[vhost][s.backend[vhost]].Backend, vhost))
	return s.proxy[vhost][s.backend[vhost]].handler
}

/* TODO: Implement more probes */
func (s *Server) probe_backends(probe time.Duration) {
	transport := http.Transport{Dial: dialTimeout}
	client := &http.Client{
		Transport: &transport,
	}

	for {
		time.Sleep(probe)

		s.mu.Lock()
		for vhost, backends := range s.proxy {
			// err := s.populate_proxies(vhost)
			fmt.Printf("%v", backends)
			fmt.Println(len(backends))
			is_dead := make(map[string]bool)
			removed := 0
			for backend := range backends {
				backend = backend - removed
				fmt.Println(backend)
				hpr_utils.Log(fmt.Sprintf(
					"vhost: %s backends: %s", vhost, s.proxy[vhost][backend].Backend))
				if is_dead[s.proxy[vhost][backend].Backend] {
					hpr_utils.Log(fmt.Sprintf("Removing dead backend: %s", s.proxy[vhost][backend].Backend))
					s.proxy[vhost] = s.proxy[vhost][:backend+copy(s.proxy[vhost][backend:], s.proxy[vhost][backend+1:])]
					removed++
				}

				_, err := client.Get(s.proxy[vhost][backend].Backend)
				if err != nil {
					hpr_utils.Log(fmt.Sprintf("Removing dead backend: %s", s.proxy[vhost][backend].Backend))
					is_dead[s.proxy[vhost][backend].Backend] = true
					s.proxy[vhost] = s.proxy[vhost][:backend+copy(s.proxy[vhost][backend:], s.proxy[vhost][backend+1:])]
					removed++
				} else {
					hpr_utils.Log(fmt.Sprintf("Alive: %s", s.proxy[vhost][backend].Backend))

				}
			}

		}
		s.mu.Unlock()
	}
}

func dialTimeout(network, addr string) (net.Conn, error) {
	timeout := time.Duration(2 * time.Second)
	return net.DialTimeout(network, addr, timeout)
}

func makeHandler(f string) http.Handler {
	if f != "" {
		return &httputil.ReverseProxy{
			Director: func(req *http.Request) {
				req.URL.Scheme = "http"
				req.URL.Host = f
			},
		}
	}
	return nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

   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.

      Based on http://github.com/nf/webfront

   @author: Juliano Martinez
*/

package http_server

import (
	"fmt"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func xff(req *http.Request) string {
	remote_addr := strings.Split(req.RemoteAddr, ":")
	if len(remote_addr) == 0 {
		return ""
	}
	return remote_addr[0]
}

type Server struct {
	mu      sync.RWMutex
	last    time.Time
	proxy   map[string][]Proxy
	backend map[string]int
}

type Proxy struct {
	Connections int64
	Backend     string
	handler     http.Handler
}

func Listen(fd int, addr string) net.Listener {
	var l net.Listener
	var err error
	if fd >= 3 {
		l, err = net.FileListener(os.NewFile(uintptr(fd), "http"))
	} else {
		l, err = net.Listen("tcp", addr)
	}
	if err != nil {
		log.Fatal(err)
	}
	return l
}

func NewServer(probe time.Duration) (*Server, error) {
	s := new(Server)
	s.proxy = make(map[string][]Proxy)
	s.backend = make(map[string]int)
	go s.probe_backends(probe)
	return s, nil
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h := s.handler(r); h != nil {
		client := xff(r)
		hpr_utils.Log(fmt.Sprintf("Request from: %s Url: %s", client, r.Host))
		r.Header.Add("X-Forwarded-For", client)
		r.Header.Add("X-Real-IP", client)
		h.ServeHTTP(w, r)
		return
	}
	http.Error(w, "Not found.", http.StatusNotFound)
}

func (s *Server) handler(req *http.Request) http.Handler {
	h := req.Host
	if i := strings.Index(h, ":"); i >= 0 {
		h = h[:i]
	}

	_, ok := s.proxy[h]
	if !ok {
		f, _ := rc.ZRange(fmt.Sprint("hpr-backends::%s", h), 0, -1, true)
		log.Println(f[0])
		/* if len(f) == 0 {
			return nil
		}*/
		s.mu.Lock()
		for _, be := range f {

			log.Println(be)
			s.proxy[h] = append(s.proxy[h], Proxy{0, be, makeHandler(be)})
		}
		s.mu.Unlock()
	}
	return s.Next(h)
}

/* TODO: Implement more balance algorithms */
func (s *Server) Next(h string) http.Handler {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.backend[h]++
	total := len(s.proxy[h])
	if s.backend[h] == total {
		s.backend[h] = 0
	}
	hpr_utils.Log(fmt.Sprintf("Using backend: %s Url: %s", s.proxy[h][s.backend[h]].Backend, h))
	return s.proxy[h][s.backend[h]].handler
}

func (s *Server) probe_backends(probe time.Duration) {
	for {
		time.Sleep(probe)
		// s.mu.Lock()
		for key, value := range s.proxy {
			hpr_utils.Log(fmt.Sprintf("Key: %s Value: %s", key, value))
		}
		// s.mu.Unlock()
	}
}

func makeHandler(f string) http.Handler {
	if f != "" {
		return &httputil.ReverseProxy{
			Director: func(req *http.Request) {
				req.URL.Scheme = "http"
				req.URL.Host = f
			},
		}
	}
	return nil
}
<commit_msg>fixed sprintf<commit_after>/*
   Copyright 2013 Juliano Martinez <juliano@martinez.io>

   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.

      Based on http://github.com/nf/webfront

   @author: Juliano Martinez
*/

package http_server

import (
	"fmt"
	"github.com/fiorix/go-redis/redis"
	hpr_utils "github.com/ncode/hot-potato-router/utils"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
	"sync"
	"time"
)

var (
	cfg = hpr_utils.NewConfig()
	rc  = redis.New(cfg.Options["redis"]["server_list"])
)

func xff(req *http.Request) string {
	remote_addr := strings.Split(req.RemoteAddr, ":")
	if len(remote_addr) == 0 {
		return ""
	}
	return remote_addr[0]
}

type Server struct {
	mu      sync.RWMutex
	last    time.Time
	proxy   map[string][]Proxy
	backend map[string]int
}

type Proxy struct {
	Connections int64
	Backend     string
	handler     http.Handler
}

func Listen(fd int, addr string) net.Listener {
	var l net.Listener
	var err error
	if fd >= 3 {
		l, err = net.FileListener(os.NewFile(uintptr(fd), "http"))
	} else {
		l, err = net.Listen("tcp", addr)
	}
	if err != nil {
		log.Fatal(err)
	}
	return l
}

func NewServer(probe time.Duration) (*Server, error) {
	s := new(Server)
	s.proxy = make(map[string][]Proxy)
	s.backend = make(map[string]int)
	go s.probe_backends(probe)
	return s, nil
}

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h := s.handler(r); h != nil {
		client := xff(r)
		hpr_utils.Log(fmt.Sprintf("Request from: %s Url: %s", client, r.Host))
		r.Header.Add("X-Forwarded-For", client)
		r.Header.Add("X-Real-IP", client)
		h.ServeHTTP(w, r)
		return
	}
	http.Error(w, "Not found.", http.StatusNotFound)
}

func (s *Server) handler(req *http.Request) http.Handler {
	h := req.Host
	if i := strings.Index(h, ":"); i >= 0 {
		h = h[:i]
	}

	_, ok := s.proxy[h]
	if !ok {
		fmt.Println(fmt.Sprintf("hpr-backends::%s", h))
		f, _ := rc.ZRange(fmt.Sprintf("hpr-backends::%s", h), 0, -1, true)
		fmt.Println(f)
		/* if len(f) == 0 {
			return nil
		}*/
		s.mu.Lock()
		for _, be := range f {

			log.Println(be)
			s.proxy[h] = append(s.proxy[h], Proxy{0, be, makeHandler(be)})
		}
		s.mu.Unlock()
	}
	return s.Next(h)
}

/* TODO: Implement more balance algorithms */
func (s *Server) Next(h string) http.Handler {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.backend[h]++
	total := len(s.proxy[h])
	if s.backend[h] == total {
		s.backend[h] = 0
	}
	hpr_utils.Log(fmt.Sprintf("Using backend: %s Url: %s", s.proxy[h][s.backend[h]].Backend, h))
	return s.proxy[h][s.backend[h]].handler
}

func (s *Server) probe_backends(probe time.Duration) {
	for {
		time.Sleep(probe)
		// s.mu.Lock()
		for key, value := range s.proxy {
			hpr_utils.Log(fmt.Sprintf("Key: %s Value: %s", key, value))
		}
		// s.mu.Unlock()
	}
}

func makeHandler(f string) http.Handler {
	if f != "" {
		return &httputil.ReverseProxy{
			Director: func(req *http.Request) {
				req.URL.Scheme = "http"
				req.URL.Host = f
			},
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package attr defines types and helpers for accessing typed attributes.
package attr

// Getter is an interface which is implemented by types which want to export typed
// values.
type Getter interface {
	GetInt(string) int
	GetString(string) string
	GetStrings(string) []string
}

// Interface is a type which defines behaviour necessary to implement a typed attribute.
type Interface interface {
	// Field returns the name of the attribute.
	Field() string

	// IsEmpty returns true iff `x` is a representation of the empty value of this attribute.
	IsEmpty(x interface{}) bool

	// Value returns the value of this attribute in `g`.
	Value(g Getter) interface{}

	// Intersect returns the intersection of `x` and `y`, assumed to be the type of the
	// attribute.
	Intersect(x, y interface{}) interface{}
}

type valueType struct {
	field string
	empty interface{}
	get   func(Getter) interface{}
}

func (v *valueType) Field() string {
	return v.field
}

func (v *valueType) IsEmpty(x interface{}) bool {
	return v.empty == x
}

func (v *valueType) Value(g Getter) interface{} {
	return v.get(g)
}

func (v *valueType) Intersect(x, y interface{}) interface{} {
	if x == y {
		return x
	}
	return v.empty
}

// String constructs an implementation of Interface with the field name `f` to access a string
// attribute of an implementation of Getter.
func String(f string) Interface {
	return &valueType{
		field: f,
		empty: "",
		get: func(g Getter) interface{} {
			return g.GetString(f)
		},
	}
}

// Int constructs an implementation of Interface with the field name `f` to access an int
// attribute of an implementation of Getter.
func Int(f string) Interface {
	return &valueType{
		field: f,
		empty: 0,
		get: func(g Getter) interface{} {
			return g.GetInt(f)
		},
	}
}

type stringsType struct {
	valueType
}

func (p *stringsType) IsEmpty(x interface{}) bool {
	if x == nil {
		return true
	}
	xs := x.([]string)
	return len(xs) == 0
}

func (p *stringsType) Intersect(x, y interface{}) interface{} {
	if x == nil || y == nil {
		return nil
	}
	xs := x.([]string)
	ys := y.([]string)
	return stringSliceIntersect(xs, ys)
}

// Strings constructs an implementation of Interface with the field name `f` to access a string slice
// attribute of an implementation of Getter.
func Strings(f string) Interface {
	return &stringsType{
		valueType{
			field: f,
			empty: nil,
			get: func(g Getter) interface{} {
				return g.GetStrings(f)
			},
		},
	}
}

// stringSliceIntersect computes the intersection of two string slices (ignoring ordering).
func stringSliceIntersect(s, t []string) []string {
	var res []string
	m := make(map[string]bool)
	for _, x := range s {
		m[x] = true
	}
	for _, y := range t {
		if m[y] {
			res = append(res, y)
		}
	}
	return res
}
<commit_msg>Finish godoc for attr.<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package attr defines types and helpers for accessing typed attributes.
package attr

// Getter is an interface which is implemented by types which want to export typed
// values.
type Getter interface {
	GetInt(string) int
	GetString(string) string
	GetStrings(string) []string
}

// Interface is a type which defines behaviour necessary to implement a typed attribute.
type Interface interface {
	// Field returns the name of the attribute.
	Field() string

	// IsEmpty returns true iff `x` is a representation of the empty value of this attribute.
	IsEmpty(x interface{}) bool

	// Value returns the value of this attribute in `g`.
	Value(g Getter) interface{}

	// Intersect returns the intersection of `x` and `y`, assumed to be the type of the
	// attribute.
	Intersect(x, y interface{}) interface{}
}

type valueType struct {
	field string
	empty interface{}
	get   func(Getter) interface{}
}

// Field implements Interface.
func (v *valueType) Field() string {
	return v.field
}

// IsEmpty implements Interface.
func (v *valueType) IsEmpty(x interface{}) bool {
	return v.empty == x
}

// Value implements Interface.
func (v *valueType) Value(g Getter) interface{} {
	return v.get(g)
}

// Intersect implements Interface.
func (v *valueType) Intersect(x, y interface{}) interface{} {
	if x == y {
		return x
	}
	return v.empty
}

// String constructs an implementation of Interface with the field name `f` to access a string
// attribute of an implementation of Getter.
func String(f string) Interface {
	return &valueType{
		field: f,
		empty: "",
		get: func(g Getter) interface{} {
			return g.GetString(f)
		},
	}
}

// Int constructs an implementation of Interface with the field name `f` to access an int
// attribute of an implementation of Getter.
func Int(f string) Interface {
	return &valueType{
		field: f,
		empty: 0,
		get: func(g Getter) interface{} {
			return g.GetInt(f)
		},
	}
}

type stringsType struct {
	valueType
}

// IsEmpty implements Interface.
func (p *stringsType) IsEmpty(x interface{}) bool {
	if x == nil {
		return true
	}
	xs := x.([]string)
	return len(xs) == 0
}

// Intersect implements Interface.
func (p *stringsType) Intersect(x, y interface{}) interface{} {
	if x == nil || y == nil {
		return nil
	}
	xs := x.([]string)
	ys := y.([]string)
	return stringSliceIntersect(xs, ys)
}

// Strings constructs an implementation of Interface with the field name `f` to access a string slice
// attribute of an implementation of Getter.
func Strings(f string) Interface {
	return &stringsType{
		valueType{
			field: f,
			empty: nil,
			get: func(g Getter) interface{} {
				return g.GetStrings(f)
			},
		},
	}
}

// stringSliceIntersect computes the intersection of two string slices (ignoring ordering).
func stringSliceIntersect(s, t []string) []string {
	var res []string
	m := make(map[string]bool)
	for _, x := range s {
		m[x] = true
	}
	for _, y := range t {
		if m[y] {
			res = append(res, y)
		}
	}
	return res
}
<|endoftext|>


<commit_before>package copy

import (
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"strings"
)

// File Meta data representation
type Meta struct {
	Id                      string                  `json:"id,omitempty"`
	Path                    string                  `json:"path,omitempty"`
	Name                    string                  `json:"name,omitempty"`
	LinkName                string                  `json:"link_name,omitempty"`
	Token                   string                  `json:"token,omitempty"`
	Permissions             string                  `json:"permissions,omitempty"`
	Public                  bool                    `json:"public,omitempty"`
	Type                    string                  `json:"type,omitempty"`
	Size                    int                     `json:"size,omitempty"`
	DateLastSynced          int                     `json:"date_last_synced,omitempty"`
	ModifiedTime            int                     `json:"modified_time,omitempty"`
	Stub                    bool                    `json:"stub,omitempty"`
	Share                   bool                    `json:"share,omitempty"`
	Children                []Meta                  `json:"children,omitempty"` // Inception :D
	Counts                  Count                   `json:"counts,omitempty"`   // Array? (sometimes? ask copy.com)
	RecipientConfirmed      bool                    `json:"recipient_confirmed",omitempty"`
	MimeType                string                  `json:"mime_type",omitempty"`
	Syncing                 bool                    `json:"syncing",omitempty"`
	ObjectAvailable         bool                    `json:"object_available,omitempty"`
	Links                   []Link                  `json:"links,omitempty"`
	Revisions               []Revision              `json:"revisions,omitempty"`
	Url                     string                  `json:"url,omitempty"`
	RevisionId              int                     `json:"revision_id,omitempty"`
	Thumb                   string                  `json:"thumb,omitempty"`
	ThumbOriginalDimensions ThumbOriginalDimensions `json:"thumb_original_dimensions,omitempty"`
	ChildrenCount           int                     `json:"children_count",omitempty"`
	Revision                int                     `json:"revision",omitempty"`
	ListIndex               int                     `json:"list_index",omitempty"`
}

type Count struct {
	New    int `json:"new,omitempty"`
	Viewed int `json:"viewed,omitempty"`
	Hidden int `json:"hidden,omitempty"`
}

type Link struct {
	Id                   string      `json:"id,omitempty"`
	Public               bool        `json:"public,omitempty"`
	Expires              bool        `json:"expires,omitempty"`
	Expired              bool        `json:"expired,omitempty"`
	Url                  string      `json:"url,omitempty"`
	UrlShort             string      `json:"url_short,omitempty"`
	Recipients           []Recipient `json:"recipients,omitempty"`
	CreatorId            string      `json:"creator_id,omitempty"`
	ConfirmationRequired bool        `json:"confirmation_required,omitempty"`
}
type Recipient struct {
	ContactType   string  `json:"contact_type,omitempty"`
	ContactId     string  `json:"contact_id,omitempty"`
	ContactSource string  `json:"contact_source,omitempty"`
	UserId        string  `json:"user_id,omitempty"`
	FirstName     string  `json:"first_name,omitempty"`
	LastName      string  `json:"last_name,omitempty"`
	Email         string  `json:"email,omitempty"`
	Permissions   string  `json:"permissions,omitempty"`
	Emails        []Email `json:"emails,omitempty"` // In users.go
}

type ThumbOriginalDimensions struct {
	Width  int `json:"width,omitempty"`
	Height int `json:"Height,omitempty"`
}

type Revision struct {
	RevisionId   string  `json:"revision_id,omitempty"`
	ModifiedTime string  `json:"modified_time,omitempty"`
	Size         int     `json:"size,omitempty"`
	Latest       bool    `json:"latest,omitempty"`
	Conflict     int     `json:"conflict,omitempty"`
	Id           string  `json:"id,omitempty"`
	Type         string  `json:"type,omitempty"`
	Creator      Creator `json:"creator,omitempty"`
}

type Creator struct {
	UserId      string `json:"user_id,omitempty"`
	CreatedTime int    `json:"created_time,omitempty"`
	Email       string `json:"email,omitempty"`
	FirstName   string `json:"first_name,omitempty"`
	LastName    string `json:"last_name,omitempty"`
	Confirmed   bool   `json:"confirmed,omitempty"`
}

type FileService struct {
	client *Client
}

var (
	metaTopLevelSuffix  = "meta"
	firstLevelSuffix    = strings.Join([]string{metaTopLevelSuffix, "copy"}, "/")
	listRevisionsSuffix = strings.Join([]string{metaTopLevelSuffix, "%v@activity"}, "/")
	revisionSuffix      = strings.Join([]string{metaTopLevelSuffix, "@time:%d"}, "/")
	filesTopLevelSuffix = "files"
	overwriteOption     = "?overwrite=%t"
)

func NewFileService(client *Client) *FileService {
	fs := new(FileService)
	fs.client = client
	return fs
}

// Returns the top level metadata (this is root folder, cannot change, see docs)
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetTopLevelMeta() (*Meta, error) {
	meta := new(Meta)
	resp, err := fs.client.DoRequestDecoding("GET", metaTopLevelSuffix, nil, meta)

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 { // 400s and 500s
		return nil, errors.New(fmt.Sprintf("Client response: %d", resp.StatusCode))
	}

	return meta, nil
}

// Returns the metadata of a file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetMeta(path string) (*Meta, error) {
	meta := new(Meta)
	resp, err := fs.client.DoRequestDecoding("GET", strings.Join([]string{firstLevelSuffix, path}, "/"), nil, meta)

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 { // 400s and 500s
		return nil, errors.New(fmt.Sprintf("Client response: %d", resp.StatusCode))
	}

	return meta, nil
}

// Returns all the metadata revisions of a file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) ListRevisionsMeta(path string) (*Meta, error) {
	return nil, nil
}

// Returns the metadata in an specified revision
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetRevisionMeta(path string, time int) (*Meta, error) {
	return nil, nil
}

// Returns the file content. the user NEEDS TO CLOSE the buffer after using in
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetFile(path string) (io.ReadCloser, error) {

	resp, err := fs.client.DoRequestContent(strings.Join([]string{filesTopLevelSuffix, path}, "/"))

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 { // 400s and 500s
		return nil, errors.New(fmt.Sprintf("Client response: %d", resp.StatusCode))
	}

	return resp.Body, nil
}

// Deletes the file content
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) DeleteFile(path string) error {
	return nil
}

// Uploads the file. Loads the file from the file path and uploads to the
// uploadPath.
// For example:
//   filePath: /home/slok/myFile.txt
//   UploadPath: test/uploads/something.txt
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) UploadFile(filePath, uploadPath string, overwrite bool) error {

	// Sanitize path
	uploadPath = strings.Trim(uploadPath, "/")

	// Get upload filename
	filename := filepath.Base(uploadPath)

	if filename == "" {
		return errors.New("Wrong uploadPath")
	}

	// Get upload path
	uploadPath = filepath.Dir(uploadPath)

	if uploadPath == "." { // Check if is at root, if so delete the point returned by Dir
		uploadPath = ""
	}

	// Set overwrite option
	options := fmt.Sprintf(overwriteOption, overwrite)

	// Sanitize path again
	uploadPath = strings.Trim(uploadPath, "/")

	// Create final paths
	uploadPath = strings.Join([]string{filesTopLevelSuffix, uploadPath}, "/")
	uploadPath = strings.Join([]string{uploadPath, options}, "")

	res, err := fs.client.DoRequestMultipart(filePath, uploadPath, filename)

	if err != nil {
		return err
	}

	if res.StatusCode >= 400 { // 400s and 500s
		return errors.New(fmt.Sprintf("Client response: %d", res.StatusCode))
	}

	return nil
}

// Renames the file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) RenameFile(path string, newName string) error {
	return nil
}

// Moves the file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) MoveFile(path string, newPath string) error {
	return nil
}

// Creates a directory
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) CreateDirectory(path string) error {
	return nil
}
<commit_msg>Updated request urls for files<commit_after>package copy

import (
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"strings"
)

// File Meta data representation
type Meta struct {
	Id                      string                  `json:"id,omitempty"`
	Path                    string                  `json:"path,omitempty"`
	Name                    string                  `json:"name,omitempty"`
	LinkName                string                  `json:"link_name,omitempty"`
	Token                   string                  `json:"token,omitempty"`
	Permissions             string                  `json:"permissions,omitempty"`
	Public                  bool                    `json:"public,omitempty"`
	Type                    string                  `json:"type,omitempty"`
	Size                    int                     `json:"size,omitempty"`
	DateLastSynced          int                     `json:"date_last_synced,omitempty"`
	ModifiedTime            int                     `json:"modified_time,omitempty"`
	Stub                    bool                    `json:"stub,omitempty"`
	Share                   bool                    `json:"share,omitempty"`
	Children                []Meta                  `json:"children,omitempty"` // Inception :D
	Counts                  Count                   `json:"counts,omitempty"`   // Array? (sometimes? ask copy.com)
	RecipientConfirmed      bool                    `json:"recipient_confirmed",omitempty"`
	MimeType                string                  `json:"mime_type",omitempty"`
	Syncing                 bool                    `json:"syncing",omitempty"`
	ObjectAvailable         bool                    `json:"object_available,omitempty"`
	Links                   []Link                  `json:"links,omitempty"`
	Revisions               []Revision              `json:"revisions,omitempty"`
	Url                     string                  `json:"url,omitempty"`
	RevisionId              int                     `json:"revision_id,omitempty"`
	Thumb                   string                  `json:"thumb,omitempty"`
	ThumbOriginalDimensions ThumbOriginalDimensions `json:"thumb_original_dimensions,omitempty"`
	ChildrenCount           int                     `json:"children_count",omitempty"`
	Revision                int                     `json:"revision",omitempty"`
	ListIndex               int                     `json:"list_index",omitempty"`
}

type Count struct {
	New    int `json:"new,omitempty"`
	Viewed int `json:"viewed,omitempty"`
	Hidden int `json:"hidden,omitempty"`
}

type Link struct {
	Id                   string      `json:"id,omitempty"`
	Public               bool        `json:"public,omitempty"`
	Expires              bool        `json:"expires,omitempty"`
	Expired              bool        `json:"expired,omitempty"`
	Url                  string      `json:"url,omitempty"`
	UrlShort             string      `json:"url_short,omitempty"`
	Recipients           []Recipient `json:"recipients,omitempty"`
	CreatorId            string      `json:"creator_id,omitempty"`
	ConfirmationRequired bool        `json:"confirmation_required,omitempty"`
}
type Recipient struct {
	ContactType   string  `json:"contact_type,omitempty"`
	ContactId     string  `json:"contact_id,omitempty"`
	ContactSource string  `json:"contact_source,omitempty"`
	UserId        string  `json:"user_id,omitempty"`
	FirstName     string  `json:"first_name,omitempty"`
	LastName      string  `json:"last_name,omitempty"`
	Email         string  `json:"email,omitempty"`
	Permissions   string  `json:"permissions,omitempty"`
	Emails        []Email `json:"emails,omitempty"` // In users.go
}

type ThumbOriginalDimensions struct {
	Width  int `json:"width,omitempty"`
	Height int `json:"Height,omitempty"`
}

type Revision struct {
	RevisionId   string  `json:"revision_id,omitempty"`
	ModifiedTime string  `json:"modified_time,omitempty"`
	Size         int     `json:"size,omitempty"`
	Latest       bool    `json:"latest,omitempty"`
	Conflict     int     `json:"conflict,omitempty"`
	Id           string  `json:"id,omitempty"`
	Type         string  `json:"type,omitempty"`
	Creator      Creator `json:"creator,omitempty"`
}

type Creator struct {
	UserId      string `json:"user_id,omitempty"`
	CreatedTime int    `json:"created_time,omitempty"`
	Email       string `json:"email,omitempty"`
	FirstName   string `json:"first_name,omitempty"`
	LastName    string `json:"last_name,omitempty"`
	Confirmed   bool   `json:"confirmed,omitempty"`
}

type FileService struct {
	client *Client
}

var (
	//Options
	overwriteOption = "overwrite=%t"
	nameOption      = "name=%v"
	pathOption      = "path=%v"
	sizeOption      = "size=%d"

	// Meta paths
	metaTopLevelSuffix  = "meta"                                                        // http.../meta/PATH
	firstLevelSuffix    = strings.Join([]string{metaTopLevelSuffix, "copy"}, "/")       // http.../meta/copy
	getMetaSuffix       = strings.Join([]string{firstLevelSuffix, "%v"}, "/")           // http.../meta/copy/PATH
	listRevisionsSuffix = strings.Join([]string{firstLevelSuffix, "%v/@activity"}, "/") // http.../meta/copy/PATH/@activity
	revisionSuffix      = strings.Join([]string{listRevisionsSuffix, "@time:%d"}, "/")  // http.../meta/copy/PATH/@activity/@time:TIME

	// File paths
	filesTopLevelSuffix  = "files"
	filesCreateSuffix    = strings.Join([]string{filesTopLevelSuffix, "/%v?", overwriteOption}, "")                  // http.../files/PATH?overwrite=FLAG
	filesRenameSuffix    = strings.Join([]string{filesTopLevelSuffix, "/%v?", nameOption, "&", overwriteOption}, "") // http.../files/PATH?name=NEWFILENAME&overwrite=FLAG
	filesMoveSuffix      = strings.Join([]string{filesTopLevelSuffix, "/%v?", pathOption, "&", overwriteOption}, "") // http.../files/PATH?overwrite=FLAG
	filesThumbnailSuffix = strings.Join([]string{filesTopLevelSuffix, "/%v?", sizeOption}, "")                       // http.../files/PATH?size=SIZE
)

func NewFileService(client *Client) *FileService {
	fs := new(FileService)
	fs.client = client
	return fs
}

// Returns the top level metadata (this is root folder, cannot change, see docs)
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetTopLevelMeta() (*Meta, error) {
	meta := new(Meta)
	resp, err := fs.client.DoRequestDecoding("GET", metaTopLevelSuffix, nil, meta)

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 { // 400s and 500s
		return nil, errors.New(fmt.Sprintf("Client response: %d", resp.StatusCode))
	}

	return meta, nil
}

// Returns the metadata of a file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetMeta(path string) (*Meta, error) {

	path = strings.Trim(path, "/")

	meta := new(Meta)
	resp, err := fs.client.DoRequestDecoding("GET", fmt.Sprintf(getMetaSuffix, path), nil, meta)

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 { // 400s and 500s
		return nil, errors.New(fmt.Sprintf("Client response: %d", resp.StatusCode))
	}

	return meta, nil
}

// Returns all the metadata revisions of a file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) ListRevisionsMeta(path string) (*Meta, error) {
	return nil, nil
}

// Returns the metadata in an specified revision
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetRevisionMeta(path string, time int) (*Meta, error) {
	return nil, nil
}

// Returns the file content. the user NEEDS TO CLOSE the buffer after using in
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) GetFile(path string) (io.ReadCloser, error) {

	resp, err := fs.client.DoRequestContent(strings.Join([]string{filesTopLevelSuffix, path}, "/"))

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 400 { // 400s and 500s
		return nil, errors.New(fmt.Sprintf("Client response: %d", resp.StatusCode))
	}

	return resp.Body, nil
}

// Deletes the file content
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) DeleteFile(path string) error {
	return nil
}

// Uploads the file. Loads the file from the file path and uploads to the
// uploadPath.
// For example:
//   filePath: /home/slok/myFile.txt
//   UploadPath: test/uploads/something.txt
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) UploadFile(filePath, uploadPath string, overwrite bool) error {

	// Sanitize path
	uploadPath = strings.Trim(uploadPath, "/")

	// Get upload filename
	filename := filepath.Base(uploadPath)

	if filename == "" {
		return errors.New("Wrong uploadPath")
	}

	// Get upload path
	uploadPath = filepath.Dir(uploadPath)

	if uploadPath == "." { // Check if is at root, if so delete the point returned by Dir
		uploadPath = ""
	}

	// Set overwrite option
	options := fmt.Sprintf(overwriteOption, overwrite)

	// Sanitize path again
	uploadPath = strings.Trim(uploadPath, "/")

	// Create final paths
	uploadPath = strings.Join([]string{filesTopLevelSuffix, uploadPath}, "/")
	uploadPath = strings.Join([]string{uploadPath, options}, "")

	res, err := fs.client.DoRequestMultipart(filePath, uploadPath, filename)

	if err != nil {
		return err
	}

	if res.StatusCode >= 400 { // 400s and 500s
		return errors.New(fmt.Sprintf("Client response: %d", res.StatusCode))
	}

	return nil
}

// Renames the file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) RenameFile(path string, newName string) error {
	return nil
}

// Moves the file
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) MoveFile(path string, newPath string) error {
	return nil
}

// Creates a directory
//
// https://www.copy.com/developer/documentation#api-calls/filesystem
func (fs *FileService) CreateDirectory(path string) error {
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"fmt"
	"math"
	"sync"

	"github.com/hajimehoshi/ebiten/internal/buffered"
	"github.com/hajimehoshi/ebiten/internal/clock"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphicscommand"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/shareable"
)

func init() {
	shareable.SetGraphicsDriver(graphicsDriver())
	graphicscommand.SetGraphicsDriver(graphicsDriver())
}

type defaultGame struct {
	update  func(screen *Image) error
	width   int
	height  int
	context *uiContext
}

func (d *defaultGame) Update(screen *Image) error {
	return d.update(screen)
}

func (d *defaultGame) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	// Ignore the outside size.
	d.context.m.Lock()
	w, h := d.width, d.height
	d.context.m.Unlock()
	return w, h
}

func newUIContext(game Game, width, height int, scaleForWindow float64) *uiContext {
	u := &uiContext{
		game:           game,
		scaleForWindow: scaleForWindow,
	}
	if g, ok := game.(*defaultGame); ok {
		g.context = u
	}
	return u
}

type uiContext struct {
	game           Game
	offscreen      *Image
	screen         *Image
	screenScale    float64
	scaleForWindow float64
	offsetX        float64
	offsetY        float64

	outsideSizeUpdated bool
	outsideWidth       float64
	outsideHeight      float64

	m sync.Mutex
}

var theUIContext *uiContext

func (c *uiContext) setScaleForWindow(scale float64) {
	g, ok := c.game.(*defaultGame)
	if !ok {
		panic("ebiten: setScaleForWindow must be called when Run is used")
	}

	c.m.Lock()
	defer c.m.Unlock()

	w, h := g.width, g.height
	c.scaleForWindow = scale
	uiDriver().SetWindowSize(int(float64(w)*scale), int(float64(h)*scale))
}

func (c *uiContext) getScaleForWindow() float64 {
	if _, ok := c.game.(*defaultGame); !ok {
		panic("ebiten: getScaleForWindow must be called when Run is used")
	}

	c.m.Lock()
	s := c.scaleForWindow
	c.m.Unlock()
	return s
}

func (c *uiContext) SetScreenSize(width, height int) {
	g, ok := c.game.(*defaultGame)
	if !ok {
		panic("ebiten: SetScreenSize must be called when Run is used")
	}

	c.m.Lock()
	defer c.m.Unlock()

	g.width = width
	g.height = height
	s := c.scaleForWindow
	uiDriver().SetWindowSize(int(float64(width)*s), int(float64(height)*s))
}

func (c *uiContext) Layout(outsideWidth, outsideHeight float64) {
	c.outsideSizeUpdated = true
	c.outsideWidth = outsideWidth
	c.outsideHeight = outsideHeight
}

func (c *uiContext) updateOffscreen() {
	sw, sh := c.game.Layout(int(c.outsideWidth), int(c.outsideHeight))

	if c.offscreen != nil && !c.outsideSizeUpdated {
		if w, h := c.offscreen.Size(); w == sw && h == sh {
			return
		}
	}
	c.outsideSizeUpdated = false

	if c.screen != nil {
		_ = c.screen.Dispose()
		c.screen = nil
	}

	if c.offscreen != nil {
		if w, h := c.offscreen.Size(); w != sw || h != sh {
			_ = c.offscreen.Dispose()
			c.offscreen = nil
		}
	}
	if c.offscreen == nil {
		c.offscreen = newImage(sw, sh, FilterDefault, true)
	}
	c.SetScreenSize(sw, sh)

	// TODO: This is duplicated with mobile/ebitenmobileview/funcs.go. Refactor this.
	d := uiDriver().DeviceScaleFactor()
	c.screen = newScreenFramebufferImage(int(c.outsideWidth*d), int(c.outsideHeight*d))

	scaleX := c.outsideWidth / float64(sw) * d
	scaleY := c.outsideHeight / float64(sh) * d
	c.screenScale = math.Min(scaleX, scaleY)
	if uiDriver().CanHaveWindow() && !uiDriver().IsFullscreen() {
		c.setScaleForWindow(c.screenScale / d)
	}

	width := float64(sw) * c.screenScale
	height := float64(sh) * c.screenScale
	c.offsetX = (c.outsideWidth*d - width) / 2
	c.offsetY = (c.outsideHeight*d - height) / 2
}

func (c *uiContext) Update(afterFrameUpdate func()) error {
	updateCount := clock.Update(MaxTPS())

	// TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped.

	if err := buffered.BeginFrame(); err != nil {
		return err
	}

	for i := 0; i < updateCount; i++ {
		c.updateOffscreen()

		// Mipmap images should be disposed by Clear.
		c.offscreen.Clear()

		setDrawingSkipped(i < updateCount-1)

		if err := hooks.RunBeforeUpdateHooks(); err != nil {
			return err
		}
		if err := c.game.Update(c.offscreen); err != nil {
			return err
		}
		uiDriver().Input().ResetForFrame()
		afterFrameUpdate()
	}

	// This clear is needed for fullscreen mode or some mobile platforms (#622).
	c.screen.Clear()

	op := &DrawImageOptions{}

	switch vd := graphicsDriver().VDirection(); vd {
	case driver.VDownward:
		// c.screen is special: its Y axis is down to up,
		// and the origin point is lower left.
		op.GeoM.Scale(c.screenScale, -c.screenScale)
		_, h := c.offscreen.Size()
		op.GeoM.Translate(0, float64(h)*c.screenScale)
	case driver.VUpward:
		op.GeoM.Scale(c.screenScale, c.screenScale)
	default:
		panic(fmt.Sprintf("ebiten: invalid v-direction: %d", vd))
	}

	op.GeoM.Translate(c.offsetX, c.offsetY)
	op.CompositeMode = CompositeModeCopy

	// filterScreen works with >=1 scale, but does not well with <1 scale.
	// Use regular FilterLinear instead so far (#669).
	if c.screenScale >= 1 {
		op.Filter = filterScreen
	} else {
		op.Filter = FilterLinear
	}
	_ = c.screen.DrawImage(c.offscreen, op)

	if err := buffered.EndFrame(); err != nil {
		return err
	}
	return nil
}

func (c *uiContext) AdjustPosition(x, y float64) (float64, float64) {
	d := uiDriver().DeviceScaleFactor()
	return (x*d - c.offsetX) / c.screenScale, (y*d - c.offsetY) / c.screenScale
}
<commit_msg>ui: Reduce members from uiContext<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"fmt"
	"math"
	"sync"

	"github.com/hajimehoshi/ebiten/internal/buffered"
	"github.com/hajimehoshi/ebiten/internal/clock"
	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/graphicscommand"
	"github.com/hajimehoshi/ebiten/internal/hooks"
	"github.com/hajimehoshi/ebiten/internal/shareable"
)

func init() {
	shareable.SetGraphicsDriver(graphicsDriver())
	graphicscommand.SetGraphicsDriver(graphicsDriver())
}

type defaultGame struct {
	update  func(screen *Image) error
	width   int
	height  int
	context *uiContext
}

func (d *defaultGame) Update(screen *Image) error {
	return d.update(screen)
}

func (d *defaultGame) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	// Ignore the outside size.
	d.context.m.Lock()
	w, h := d.width, d.height
	d.context.m.Unlock()
	return w, h
}

func newUIContext(game Game, width, height int, scaleForWindow float64) *uiContext {
	u := &uiContext{
		game:           game,
		scaleForWindow: scaleForWindow,
	}
	if g, ok := game.(*defaultGame); ok {
		g.context = u
	}
	return u
}

type uiContext struct {
	game           Game
	offscreen      *Image
	screen         *Image
	scaleForWindow float64

	outsideSizeUpdated bool
	outsideWidth       float64
	outsideHeight      float64

	m sync.Mutex
}

var theUIContext *uiContext

func (c *uiContext) setScaleForWindow(scale float64) {
	g, ok := c.game.(*defaultGame)
	if !ok {
		panic("ebiten: setScaleForWindow must be called when Run is used")
	}

	c.m.Lock()
	defer c.m.Unlock()

	w, h := g.width, g.height
	c.scaleForWindow = scale
	uiDriver().SetWindowSize(int(float64(w)*scale), int(float64(h)*scale))
}

func (c *uiContext) getScaleForWindow() float64 {
	if _, ok := c.game.(*defaultGame); !ok {
		panic("ebiten: getScaleForWindow must be called when Run is used")
	}

	c.m.Lock()
	s := c.scaleForWindow
	c.m.Unlock()
	return s
}

func (c *uiContext) SetScreenSize(width, height int) {
	g, ok := c.game.(*defaultGame)
	if !ok {
		panic("ebiten: SetScreenSize must be called when Run is used")
	}

	c.m.Lock()
	defer c.m.Unlock()

	g.width = width
	g.height = height
	s := c.scaleForWindow
	uiDriver().SetWindowSize(int(float64(width)*s), int(float64(height)*s))
}

func (c *uiContext) Layout(outsideWidth, outsideHeight float64) {
	c.outsideSizeUpdated = true
	c.outsideWidth = outsideWidth
	c.outsideHeight = outsideHeight
}

func (c *uiContext) updateOffscreen() {
	sw, sh := c.game.Layout(int(c.outsideWidth), int(c.outsideHeight))

	if c.offscreen != nil && !c.outsideSizeUpdated {
		if w, h := c.offscreen.Size(); w == sw && h == sh {
			return
		}
	}
	c.outsideSizeUpdated = false

	if c.screen != nil {
		_ = c.screen.Dispose()
		c.screen = nil
	}

	if c.offscreen != nil {
		if w, h := c.offscreen.Size(); w != sw || h != sh {
			_ = c.offscreen.Dispose()
			c.offscreen = nil
		}
	}
	if c.offscreen == nil {
		c.offscreen = newImage(sw, sh, FilterDefault, true)
	}
	c.SetScreenSize(sw, sh)

	// TODO: This is duplicated with mobile/ebitenmobileview/funcs.go. Refactor this.
	d := uiDriver().DeviceScaleFactor()
	c.screen = newScreenFramebufferImage(int(c.outsideWidth*d), int(c.outsideHeight*d))

	if uiDriver().CanHaveWindow() && !uiDriver().IsFullscreen() {
		c.setScaleForWindow(c.screenScale() / d)
	}
}

func (c *uiContext) screenScale() float64 {
	if c.offscreen == nil {
		return 0
	}
	sw, sh := c.offscreen.Size()
	d := uiDriver().DeviceScaleFactor()
	scaleX := c.outsideWidth / float64(sw) * d
	scaleY := c.outsideHeight / float64(sh) * d
	return math.Min(scaleX, scaleY)
}

func (c *uiContext) offsets() (float64, float64) {
	if c.offscreen == nil {
		return 0, 0
	}
	sw, sh := c.offscreen.Size()
	d := uiDriver().DeviceScaleFactor()
	s := c.screenScale()
	width := float64(sw) * s
	height := float64(sh) * s
	return (c.outsideWidth*d - width) / 2, (c.outsideHeight*d - height) / 2
}

func (c *uiContext) Update(afterFrameUpdate func()) error {
	updateCount := clock.Update(MaxTPS())

	// TODO: If updateCount is 0 and vsync is disabled, swapping buffers can be skipped.

	if err := buffered.BeginFrame(); err != nil {
		return err
	}

	for i := 0; i < updateCount; i++ {
		c.updateOffscreen()

		// Mipmap images should be disposed by Clear.
		c.offscreen.Clear()

		setDrawingSkipped(i < updateCount-1)

		if err := hooks.RunBeforeUpdateHooks(); err != nil {
			return err
		}
		if err := c.game.Update(c.offscreen); err != nil {
			return err
		}
		uiDriver().Input().ResetForFrame()
		afterFrameUpdate()
	}

	// This clear is needed for fullscreen mode or some mobile platforms (#622).
	c.screen.Clear()

	op := &DrawImageOptions{}

	s := c.screenScale()
	switch vd := graphicsDriver().VDirection(); vd {
	case driver.VDownward:
		// c.screen is special: its Y axis is down to up,
		// and the origin point is lower left.
		op.GeoM.Scale(s, -s)
		_, h := c.offscreen.Size()
		op.GeoM.Translate(0, float64(h)*s)
	case driver.VUpward:
		op.GeoM.Scale(s, s)
	default:
		panic(fmt.Sprintf("ebiten: invalid v-direction: %d", vd))
	}

	op.GeoM.Translate(c.offsets())
	op.CompositeMode = CompositeModeCopy

	// filterScreen works with >=1 scale, but does not well with <1 scale.
	// Use regular FilterLinear instead so far (#669).
	if s >= 1 {
		op.Filter = filterScreen
	} else {
		op.Filter = FilterLinear
	}
	_ = c.screen.DrawImage(c.offscreen, op)

	if err := buffered.EndFrame(); err != nil {
		return err
	}
	return nil
}

func (c *uiContext) AdjustPosition(x, y float64) (float64, float64) {
	d := uiDriver().DeviceScaleFactor()
	ox, oy := c.offsets()
	s := c.screenScale()
	return (x*d - ox) / s, (y*d - oy) / s
}
<|endoftext|>


<commit_before>package utils

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os/user"
	"regexp"
	"runtime"
)

func ValidateUser(userName string) error {
	userInfo, err := user.Current()
	if err != nil {
		return err
	}
	if userInfo.Name != userName {
		return errors.New(fmt.Sprintf("You are \"%s\",only \"%s\" is permitted to run it.",
			userInfo.Username, userName))
	}
	return nil
}

// ValidateDistro validates distribution
func ValidateDistro(regExp, file string) error {
	buf, err := ioutil.ReadFile(file)
	if err == nil {
		ok, err := regexp.Match(regExp, buf)
		if ok && err == nil {
			return nil
		}
	}
	return errors.New("unsupported Linux distribution")
}

// ValidateNics gets a reference to a string slice containing
// NICs names and verifies if appropriate NIC is available
func ValidateNics(nicList []string) error {
	for _, iface := range nicList {
		if _, err := net.InterfaceByName(iface); err != nil {
			return err
		}
	}
	return nil
}

// ValidateAmountOfCpus gets amount of CPUs required
// It verifies that amount of installed CPUs is equal
// to amount of required
func ValidateAmountOfCpus(required int) error {
	amountOfInstalledCpus := runtime.NumCPU()
	if amountOfInstalledCpus != required {
		return errors.New(fmt.Sprintf("CPU amount.Required %d.Installed %d",
			required, amountOfInstalledCpus))
	}
	return nil
}

// ValidateAmountOfRam gets amount of RAM needed for proceeding
// The function verifies if eligable amount RAM is installed
func ValidateAmountOfRam(minRequiredInMb int) error {
	installedRamInMb, err := SysinfoRam()
	if err != nil {
		return err
	}
	if minRequiredInMb > installedRamInMb {
		return errors.New(fmt.Sprintf("RAM amount.Required %d.Installed %d",
			minRequiredInMb, installedRamInMb))
	}
	return nil
}

//hostname max length is 255 chars
const hostnameLength = 256

// hostname: names separated by '.' every name must be max 63 chars in length
// according to RFC 952 <name>  ::= <let>[*[<let-or-digit-or-hyphen>]<let-or-digit>]
// according to RFC 1123 - trailing and starting digits are allowed
var hostnameExpr = regexp.MustCompile(`^([a-zA-Z]|[0-9]|_)(([a-zA-Z]|[0-9]|-|_)*([a-zA-Z]|[0-9]|_))?(\.([a-zA-Z]|[0-9]|_)(([a-zA-Z]|[0-9]|-|_)*([a-zA-Z]|[0-9]))?)*$`)
var hostnameLenExpr = regexp.MustCompile(`^[a-zA-Z0-9-_]{1,64}(\.([a-zA-Z0-9-_]{1,64}))*$`)
var ipAddrExpr = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$`)

func ValidateHostname(hostname string) error {
	switch {
	case len(hostname) > hostnameLength:
		return fmt.Errorf("hostname length is greater than %d", hostnameLength)
	case !hostnameExpr.MatchString(hostname):
		return fmt.Errorf("hostname doesn't match RFC")
	case !hostnameLenExpr.MatchString(hostname):
		return fmt.Errorf("hostname length")
	case ipAddrExpr.MatchString(hostname):
		return fmt.Errorf("hostname cannot be like an ip")
	}
	return nil
}
<commit_msg>Adding ValidateUserID<commit_after>package utils

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os/user"
	"regexp"
	"runtime"
	"syscall"
)

func ValidateUserName(userName string) error {
	userInfo, err := user.Current()
	if err != nil {
		return err
	}
	if userInfo.Name != userName {
		return errors.New(fmt.Sprintf("You are not \"%s\"", userName))
	}
	return nil
}

func ValidateUserID(id int) error {
	if syscall.Getuid() != id {
		return errors.New(fmt.Sprintf("Your ID is not \"%d\"", id))
	}
	return nil
}

// ValidateDistro validates distribution
func ValidateDistro(regExp, file string) error {
	buf, err := ioutil.ReadFile(file)
	if err == nil {
		ok, err := regexp.Match(regExp, buf)
		if ok && err == nil {
			return nil
		}
	}
	return errors.New("unsupported Linux distribution")
}

// ValidateNics gets a reference to a string slice containing
// NICs names and verifies if appropriate NIC is available
func ValidateNics(nicList []string) error {
	for _, iface := range nicList {
		if _, err := net.InterfaceByName(iface); err != nil {
			return err
		}
	}
	return nil
}

// ValidateAmountOfCpus gets amount of CPUs required
// It verifies that amount of installed CPUs is equal
// to amount of required
func ValidateAmountOfCpus(required int) error {
	amountOfInstalledCpus := runtime.NumCPU()
	if amountOfInstalledCpus != required {
		return errors.New(fmt.Sprintf("CPU amount.Required %d.Installed %d",
			required, amountOfInstalledCpus))
	}
	return nil
}

// ValidateAmountOfRam gets amount of RAM needed for proceeding
// The function verifies if eligable amount RAM is installed
func ValidateAmountOfRam(minRequiredInMb int) error {
	installedRamInMb, err := SysinfoRam()
	if err != nil {
		return err
	}
	if minRequiredInMb > installedRamInMb {
		return errors.New(fmt.Sprintf("RAM amount.Required %d.Installed %d",
			minRequiredInMb, installedRamInMb))
	}
	return nil
}

//hostname max length is 255 chars
const hostnameLength = 256

// hostname: names separated by '.' every name must be max 63 chars in length
// according to RFC 952 <name>  ::= <let>[*[<let-or-digit-or-hyphen>]<let-or-digit>]
// according to RFC 1123 - trailing and starting digits are allowed
var hostnameExpr = regexp.MustCompile(`^([a-zA-Z]|[0-9]|_)(([a-zA-Z]|[0-9]|-|_)*([a-zA-Z]|[0-9]|_))?(\.([a-zA-Z]|[0-9]|_)(([a-zA-Z]|[0-9]|-|_)*([a-zA-Z]|[0-9]))?)*$`)
var hostnameLenExpr = regexp.MustCompile(`^[a-zA-Z0-9-_]{1,64}(\.([a-zA-Z0-9-_]{1,64}))*$`)
var ipAddrExpr = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$`)

func ValidateHostname(hostname string) error {
	switch {
	case len(hostname) > hostnameLength:
		return fmt.Errorf("hostname length is greater than %d", hostnameLength)
	case !hostnameExpr.MatchString(hostname):
		return fmt.Errorf("hostname doesn't match RFC")
	case !hostnameLenExpr.MatchString(hostname):
		return fmt.Errorf("hostname length")
	case ipAddrExpr.MatchString(hostname):
		return fmt.Errorf("hostname cannot be like an ip")
	}
	return nil
}
<|endoftext|>