<commit_before>package main

import (
	"github.com/garyburd/redigo/redis"
	"log"
	"strings"
)

var (
	protected = []string{"list", "add", "api", "counter", "css", "img", "js"}
)

type Url struct {
	id     string
	Link   string
	Short  string
	Clicks int64
}

type SiteStats struct {
	Clicks       int
	Links        int
	ClicksPerUrl float64
}

func GetUrlById(id string, host string) (*Url, error) {
	DB := pool.Get()
	defer DB.Close()
	cr := UrlCache.Get(id)
	if cr != nil {
		log.Print("UrlCache: Cache HIT!")
		log.Print("Updating click count in goroutine")
		go UpdateClickCount(id)
		return cr.(*Url), nil
	}
	log.Print("UrlCache: Cache Miss, retrieving from DB")
	id = strings.Split(id, ":")[0]
	k, err := DB.Do("GET", "url:link:"+id)
	if err != nil {
		return nil, err
	}
	switch k.(type) {
	case nil:
		return nil, nil
	default:
		c, _ := UpdateClickCount(id)
		resp := &Url{}
		resp.id = id
		resp.Short = config.GetBaseUrl(host) + id
		resp.Link, _ = redis.String(k, err)
		resp.Clicks = int64(c)
		UrlCache.Set(id, resp)
		return resp, nil
	}
}

func GetNewUrl(link string, host string) (*Url, error) {
	DB := pool.Get()
	defer DB.Close()
	i, err := GetNewCounter()
	if err != nil {
		return nil, err
	}
	for _, k := range protected {
		for b62_Encode(uint64(i)) == k {
			i, err = GetNewCounter()
			if err != nil {
				return nil, err
			}
		}
	}
	pos := b62_Encode(uint64(i))
	_, err = DB.Do("SET", "url:link:"+pos, link)
	go func(pos string) {
		d := pool.Get()
		defer d.Close()
		_, err := d.Do("SET", "url:clicks:"+pos, 0)
		if err != nil {
			log.Printf("Error settings %s clicks to 0", pos)
		} else {
			log.Printf("%s clicks set to 0", pos)
		}
	}(pos)
	if err != nil {
		return nil, err
	}
	new := &Url{}
	new.id = pos
	new.Link = link
	new.Clicks = 0
	new.Short = config.GetBaseUrl(host) + new.id
	UrlCache.Set(new.id, new)
	log.Printf("Shortened %s to %s", new.Link, config.GetBaseUrl(host)+new.id)
	return new, nil
}

func GetNewCounter() (int64, error) {
	DB := pool.Get()
	defer DB.Close()
	n, err := DB.Do("INCR", "meta:COUNTER")
	if err != nil {
		return 0, err
	}
	return n.(int64), nil
}

func GetSiteStats() SiteStats {
	cc := StatsCache.Get("Stats")
	if cc != nil {
		log.Print("Cache: Site Stats HIT")
		return cc.(SiteStats)
	} else {
		log.Print("Cache: Site Stats MISS")
	}
	k := SiteStats{}
	a, _ := GetTotalClicks()
	b, _ := GetTotalUrls()
	c, _ := GetClicksPerUrl()
	k.Clicks = a
	k.Links = b
	k.ClicksPerUrl = c
	StatsCache.Set("Stats", k)
	return k
}

func newPool() *redis.Pool {
	return redis.NewPool(func() (redis.Conn, error) {
		conn, err := redis.Dial("tcp", config.DBAddress)
		if err != nil {
			return nil, err
		}
		_, err = conn.Do("AUTH", config.DBPassword)
		if err != nil {
			log.Print(err.Error())
			return nil, err
		}
		return conn, nil

	}, 3)
}

func GetTotalUrls() (int, error) {
	db := pool.Get()
	defer db.Close()
	k, err := db.Do("GET", "meta:total:links")
	if err != nil {
		return 0, err
	}
	l, err := redis.Int(k, err)
	if err != nil {
		return 0, err
	}
	return l, err
}

func GetTotalClicks() (int, error) {
	DB := pool.Get()
	defer DB.Close()
	k, err := DB.Do("GET", "meta:total:clicks")
	if err != nil {
		return 0, nil
	}
	j, err := redis.Int(k, err)
	if err != nil {
		return 0, nil
	}
	return j, nil
}

func UpdateClickCount(id string) (int, error) {
	DB := pool.Get()
	defer DB.Close()
	k, err := DB.Do("INCR", "url:clicks:"+id)
	i, err := redis.Int(k, err)
	return i, err
}
<commit_msg>cleanup<commit_after>package main

import (
	"github.com/garyburd/redigo/redis"
	"log"
	"strings"
)

var (
	protected = []string{"list", "add", "api", "counter", "css", "img", "js"}
)

type Url struct {
	id     string
	Link   string
	Short  string
	Clicks int64
}

type SiteStats struct {
	Clicks       int
	Links        int
	ClicksPerUrl float64
}

func GetUrlById(id string, host string) (*Url, error) {
	DB := pool.Get()
	defer DB.Close()
	cr := UrlCache.Get(id)
	if cr != nil {
		log.Print("UrlCache: Cache HIT!")
		log.Print("Updating click count in goroutine")
		go UpdateClickCount(id)
		return cr.(*Url), nil
	}
	log.Print("UrlCache: Cache Miss, retrieving from DB")
	id = strings.Split(id, ":")[0]
	k, err := DB.Do("GET", "url:link:"+id)
	if err != nil {
		return nil, err
	}
	switch k.(type) {
	case nil:
		return nil, nil
	default:
		c, _ := UpdateClickCount(id)
		resp := &Url{}
		resp.id = id
		resp.Short = config.GetBaseUrl(host) + id
		resp.Link, _ = redis.String(k, err)
		resp.Clicks = int64(c)
		UrlCache.Set(id, resp)
		return resp, nil
	}
}

func GetNewUrl(link string, host string) (*Url, error) {
	DB := pool.Get()
	defer DB.Close()
	i, err := GetNewCounter()
	if err != nil {
		return nil, err
	}
	for _, k := range protected {
		for b62_Encode(uint64(i)) == k {
			i, err = GetNewCounter()
			if err != nil {
				return nil, err
			}
		}
	}
	pos := b62_Encode(uint64(i))
	_, err = DB.Do("SET", "url:link:"+pos, link)
	go func(pos string) {
		d := pool.Get()
		defer d.Close()
		_, err := d.Do("SET", "url:clicks:"+pos, 0)
		if err != nil {
			log.Printf("Error settings %s clicks to 0", pos)
		} else {
			log.Printf("%s clicks set to 0", pos)
		}
	}(pos)
	if err != nil {
		return nil, err
	}
	new := &Url{}
	new.id = pos
	new.Link = link
	new.Clicks = 0
	new.Short = config.GetBaseUrl(host) + new.id
	UrlCache.Set(new.id, new)
	log.Printf("Shortened %s to %s", new.Link, config.GetBaseUrl(host)+new.id)
	return new, nil
}

func GetNewCounter() (int64, error) {
	DB := pool.Get()
	defer DB.Close()
	n, err := DB.Do("INCR", "meta:COUNTER")
	if err != nil {
		return 0, err
	}
	return n.(int64), nil
}

func GetSiteStats() SiteStats {
	cc := StatsCache.Get("Stats")
	if cc != nil {
		log.Print("Cache: Site Stats HIT")
		return cc.(SiteStats)
	} else {
		log.Print("Cache: Site Stats MISS")
	}
	k := SiteStats{}
	a, _ := GetTotalClicks()
	b, _ := GetTotalUrls()
	c, _ := GetClicksPerUrl()
	k.Clicks = a
	k.Links = b
	k.ClicksPerUrl = c
	StatsCache.Set("Stats", k)
	return k
}

func newPool() *redis.Pool {
	return redis.NewPool(func() (redis.Conn, error) {
		conn, err := redis.Dial("tcp", config.DBAddress)
		if err != nil {
			return nil, err
		}
		_, err = conn.Do("AUTH", config.DBPassword)
		if err != nil {
			log.Print(err.Error())
			return nil, err
		}
		return conn, nil

	}, 3)
}

func GetTotalUrls() (int, error) {
	db := pool.Get()
	defer db.Close()
	l, err := redis.Int(db.Do("GET", "meta:total:links"))
	if err != nil {
		return 0, err
	}
	return l, err
}

func GetTotalClicks() (int, error) {
	DB := pool.Get()
	defer DB.Close()
	j, err := redis.Int(DB.Do("GET", "meta:total:clicks"))
	if err != nil {
		return 0, nil
	}
	return j, nil
}

func UpdateClickCount(id string) (int, error) {
	DB := pool.Get()
	defer DB.Close()
	k, err := DB.Do("INCR", "url:clicks:"+id)
	i, err := redis.Int(k, err)
	return i, err
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	fct "github.com/FactomProject/factoid"
	"github.com/FactomProject/factom"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strconv"
)

var _ = hex.EncodeToString
var serverFct = "localhost:8089"

var badChar, _ = regexp.Compile("[^A-Za-z0-9_-]")

type Response struct {
	Response string
	Success  bool
}

func ValidateKey(key string) (msg string, valid bool) {
	if len(key) > fct.ADDRESS_LENGTH {
		return "Key is too long.  Keys must be less than 32 characters", false
	}
	if badChar.FindStringIndex(key) != nil {
		str := fmt.Sprintf("The key or name '%s' contains invalid characters.\n"+
			"Keys and names are restricted to alphanumeric characters,\n"+
			"minuses (dashes), and underscores", key)
		return str, false
	}
	return "", true
}

func getCmd(cmd string, cmderror string) {
	resp, err := http.Get(cmd)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	resp.Body.Close()

	b := new(Response)
	if err := json.Unmarshal(body, b); err != nil || !b.Success {
		fmt.Println(cmderror)
		fmt.Println("Command Failed: ", string(body))
		os.Exit(1)
	}
	fmt.Println(b.Response)
	return
}

func postCmd(cmd string) {
	resp, err := http.PostForm(cmd, nil)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	resp.Body.Close()

	b := new(Response)
	if err := json.Unmarshal(body, b); err != nil {
		fmt.Printf("Failed to parse the response from factomd: %s\n", body)
		os.Exit(1)
	}

	fmt.Println(b.Response)

	if !b.Success {
		os.Exit(1)
	}

	return
}

// Generates a new Address
func generateaddress(args []string) {

	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		man("generatefactoidaddress")
		os.Exit(1)
	}

	var err error
	var Addr string
	switch args[0] {
	case "ec":
		Addr, err = factom.GenerateEntryCreditAddress(args[1])
	case "fct":
		Addr, err = factom.GenerateFactoidAddress(args[1])
	default:
		panic("Expected ec|fct name")
	}

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(args[0], " = ", Addr)
	return

}

func getaddresses(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) > 0 {
		man("getaddresses")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-get-addresses/", serverFct)
	getCmd(str, "Error printing addresses")

	return
}

func gettransactions(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) > 0 {
		man("transactions")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-get-transactions/", serverFct)
	getCmd(str, "Error Getting Transactions")

	return
}

func fctnewtrans(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		man("newtransaction")
		os.Exit(1)
	}
	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}
	str := fmt.Sprintf("http://%s/v1/factoid-new-transaction/%s", serverFct, args[0])
	postCmd(str)

	return

}

func fctdeletetrans(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		man("deletetransaction")
		os.Exit(1)
	}
	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}
	str := fmt.Sprintf("http://%s/v1/factoid-delete-transaction/%s", serverFct, args[0])
	postCmd(str)

	return

}

func fctaddfee(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		fmt.Println("Was expecting a transaction key, and an address used as an input to that transaction.")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	msg, valid = ValidateKey(args[1])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-fee/?key=%s&name=%s",
		serverFct, args[0], args[1])
	postCmd(str)

	return
}

func fctaddinput(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 3 {
		fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	amt, err := fct.ConvertFixedPoint(args[2])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	ramt, err := strconv.ParseInt(amt, 10, 64)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	_, err = fct.ValidateAmounts(uint64(ramt))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-input/?key=%s&name=%s&amount=%s",
		serverFct, args[0], args[1], amt)
	postCmd(str)

	return
}

func fctaddoutput(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 3 {
		fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
		os.Exit(1)
	}
	// localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	msg, valid = ValidateKey(args[1])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	amt, err := fct.ConvertFixedPoint(args[2])
	if err != nil {
		fmt.Println("Invalid format for a number: ", args[2])
		man("addoutput")
		os.Exit(1)
	}

	ramt, err := strconv.ParseInt(amt, 10, 64)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	_, err = fct.ValidateAmounts(uint64(ramt))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-output/?key=%s&name=%s&amount=%s",
		serverFct, args[0], args[1], amt)
	postCmd(str)

	return
}

func fctaddecoutput(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 3 {
		fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
		os.Exit(1)
	}
	// localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	msg, valid = ValidateKey(args[1])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	amt, err := fct.ConvertFixedPoint(args[2])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	ramt, err := strconv.ParseInt(amt, 10, 64)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	_, err = fct.ValidateAmounts(uint64(ramt))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-ecoutput/?key=%s&name=%s&amount=%s",
		serverFct, args[0], args[1], amt)
	postCmd(str)

	return
}

func fctgetfee(args []string) {
	resp, err := http.Get(fmt.Sprintf("http://%s/v1/factoid-get-fee/", serverFct))
	if err != nil {
		fmt.Println("Command Failed Get")
		os.Exit(1)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Command Failed")
		os.Exit(1)
	}
	resp.Body.Close()

	// We pull the fee.  If the fee isn't positive, or if we fail to marshal, then there is a failure
	type x struct{ Fee int64 }
	b := new(x)
	b.Fee = -1
	if err := json.Unmarshal(body, b); err != nil || b.Fee == -1 {
		fmt.Println("Command Failed")
		os.Exit(1)
	}
	tv := b.Fee / 100000000
	lv := b.Fee - (tv * 100000000)
	r := fmt.Sprintf("Fee: %d.%08d", tv, lv)
	var i int
	for i = len(r) - 1; r[i] == '0'; i-- {
	}
	if string(r[i]) == "." {
		i += 1
	}
	fmt.Println(r[:i+1])

}

func fctsign(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-sign-transaction/%s", serverFct, args[0])
	postCmd(str)

}

func fctsubmit(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	s := struct{ Transaction string }{args[0]}

	jdata, err := json.Marshal(s)
	if err != nil {
		fmt.Println("Submitt failed")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-submit/%s", serverFct, bytes.NewBuffer(jdata))
	postCmd(str)
}

func fctsetup(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		msg := "You must supply some random seed. For example (don't use this!)\n" +
			"  factom-cli setup 'woe!#in31!%234ng)%^&$%oeg%^&*^jp45694a;gmr@#t4 q34y'\n" +
			"would make a nice seed.  The more random the better.\n\n" +
			"Note that if you create an address before you call Setup, you must\n" +
			"use those address(s) as you access the fountians."

		fmt.Println(msg)
		os.Exit(1)
	}

	s := struct{ Transaction string }{args[0]}

	jdata, err := json.Marshal(s)
	if err != nil {
		fmt.Println("Submitt failed")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-setup/%s", serverFct, bytes.NewBuffer(jdata))
	postCmd(str)
}
<commit_msg>removed validation from transaction.go<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/hex"
	"encoding/json"
	"flag"
	"fmt"
	fct "github.com/FactomProject/factoid"
	"github.com/FactomProject/factom"
	"io/ioutil"
	"net/http"
	"os"
	"regexp"
	"strconv"
)

var _ = hex.EncodeToString
var serverFct = "localhost:8089"

var badChar, _ = regexp.Compile("[^A-Za-z0-9_-]")

type Response struct {
	Response string
	Success  bool
}

func ValidateKey(key string) (msg string, valid bool) {
	if len(key) > fct.ADDRESS_LENGTH {
		return "Key is too long.  Keys must be less than 32 characters", false
	}
	if badChar.FindStringIndex(key) != nil {
		str := fmt.Sprintf("The key or name '%s' contains invalid characters.\n"+
			"Keys and names are restricted to alphanumeric characters,\n"+
			"minuses (dashes), and underscores", key)
		return str, false
	}
	return "", true
}

func getCmd(cmd string, cmderror string) {
	resp, err := http.Get(cmd)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	resp.Body.Close()

	b := new(Response)
	if err := json.Unmarshal(body, b); err != nil || !b.Success {
		fmt.Println(cmderror)
		fmt.Println("Command Failed: ", string(body))
		os.Exit(1)
	}
	fmt.Println(b.Response)
	return
}

func postCmd(cmd string) {
	resp, err := http.PostForm(cmd, nil)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	resp.Body.Close()

	b := new(Response)
	if err := json.Unmarshal(body, b); err != nil {
		fmt.Printf("Failed to parse the response from factomd: %s\n", body)
		os.Exit(1)
	}

	fmt.Println(b.Response)

	if !b.Success {
		os.Exit(1)
	}

	return
}

// Generates a new Address
func generateaddress(args []string) {

	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		man("generatefactoidaddress")
		os.Exit(1)
	}

	var err error
	var Addr string
	switch args[0] {
	case "ec":
		Addr, err = factom.GenerateEntryCreditAddress(args[1])
	case "fct":
		Addr, err = factom.GenerateFactoidAddress(args[1])
	default:
		panic("Expected ec|fct name")
	}

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(args[0], " = ", Addr)
	return

}

func getaddresses(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) > 0 {
		man("getaddresses")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-get-addresses/", serverFct)
	getCmd(str, "Error printing addresses")

	return
}

func gettransactions(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) > 0 {
		man("transactions")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-get-transactions/", serverFct)
	getCmd(str, "Error Getting Transactions")

	return
}

func fctnewtrans(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		man("newtransaction")
		os.Exit(1)
	}
	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}
	str := fmt.Sprintf("http://%s/v1/factoid-new-transaction/%s", serverFct, args[0])
	postCmd(str)

	return

}

func fctdeletetrans(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		man("deletetransaction")
		os.Exit(1)
	}
	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}
	str := fmt.Sprintf("http://%s/v1/factoid-delete-transaction/%s", serverFct, args[0])
	postCmd(str)

	return

}

func fctaddfee(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 2 {
		fmt.Println("Was expecting a transaction key, and an address used as an input to that transaction.")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-fee/?key=%s&name=%s",
		serverFct, args[0], args[1])
	postCmd(str)

	return
}

func fctaddinput(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 3 {
		fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	amt, err := fct.ConvertFixedPoint(args[2])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	ramt, err := strconv.ParseInt(amt, 10, 64)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	_, err = fct.ValidateAmounts(uint64(ramt))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-input/?key=%s&name=%s&amount=%s",
		serverFct, args[0], args[1], amt)
	postCmd(str)

	return
}

func fctaddoutput(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 3 {
		fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
		os.Exit(1)
	}
	// localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	amt, err := fct.ConvertFixedPoint(args[2])
	if err != nil {
		fmt.Println("Invalid format for a number: ", args[2])
		man("addoutput")
		os.Exit(1)
	}

	ramt, err := strconv.ParseInt(amt, 10, 64)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	_, err = fct.ValidateAmounts(uint64(ramt))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-output/?key=%s&name=%s&amount=%s",
		serverFct, args[0], args[1], amt)
	postCmd(str)

	return
}

func fctaddecoutput(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 3 {
		fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
		os.Exit(1)
	}
	// localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	amt, err := fct.ConvertFixedPoint(args[2])
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	ramt, err := strconv.ParseInt(amt, 10, 64)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	_, err = fct.ValidateAmounts(uint64(ramt))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-add-ecoutput/?key=%s&name=%s&amount=%s",
		serverFct, args[0], args[1], amt)
	postCmd(str)

	return
}

func fctgetfee(args []string) {
	resp, err := http.Get(fmt.Sprintf("http://%s/v1/factoid-get-fee/", serverFct))
	if err != nil {
		fmt.Println("Command Failed Get")
		os.Exit(1)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Command Failed")
		os.Exit(1)
	}
	resp.Body.Close()

	// We pull the fee.  If the fee isn't positive, or if we fail to marshal, then there is a failure
	type x struct{ Fee int64 }
	b := new(x)
	b.Fee = -1
	if err := json.Unmarshal(body, b); err != nil || b.Fee == -1 {
		fmt.Println("Command Failed")
		os.Exit(1)
	}
	tv := b.Fee / 100000000
	lv := b.Fee - (tv * 100000000)
	r := fmt.Sprintf("Fee: %d.%08d", tv, lv)
	var i int
	for i = len(r) - 1; r[i] == '0'; i-- {
	}
	if string(r[i]) == "." {
		i += 1
	}
	fmt.Println(r[:i+1])

}

func fctsign(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-sign-transaction/%s", serverFct, args[0])
	postCmd(str)

}

func fctsubmit(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		fmt.Println("Missing Key")
		os.Exit(1)
	}

	msg, valid := ValidateKey(args[0])
	if !valid {
		fmt.Println(msg)
		os.Exit(1)
	}

	s := struct{ Transaction string }{args[0]}

	jdata, err := json.Marshal(s)
	if err != nil {
		fmt.Println("Submitt failed")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-submit/%s", serverFct, bytes.NewBuffer(jdata))
	postCmd(str)
}

func fctsetup(args []string) {
	os.Args = args
	flag.Parse()
	args = flag.Args()
	if len(args) < 1 {
		msg := "You must supply some random seed. For example (don't use this!)\n" +
			"  factom-cli setup 'woe!#in31!%234ng)%^&$%oeg%^&*^jp45694a;gmr@#t4 q34y'\n" +
			"would make a nice seed.  The more random the better.\n\n" +
			"Note that if you create an address before you call Setup, you must\n" +
			"use those address(s) as you access the fountians."

		fmt.Println(msg)
		os.Exit(1)
	}

	s := struct{ Transaction string }{args[0]}

	jdata, err := json.Marshal(s)
	if err != nil {
		fmt.Println("Submitt failed")
		os.Exit(1)
	}

	str := fmt.Sprintf("http://%s/v1/factoid-setup/%s", serverFct, bytes.NewBuffer(jdata))
	postCmd(str)
}
<|endoftext|>


<commit_before>package makex

import (
	"bytes"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"github.com/sourcegraph/rwvfs"
)

type Makefile struct {
	Rules []Rule
}

type BasicRule struct {
	TargetFile  string
	PrereqFiles []string
	RecipeCmds  []string
}

func (r *BasicRule) Target() string    { return r.TargetFile }
func (r *BasicRule) Prereqs() []string { return r.PrereqFiles }
func (r *BasicRule) Recipes() []string { return r.RecipeCmds }

// Rule returns the rule to make the specified target if it exists, or nil
// otherwise.
//
// TODO(sqs): support multiple rules for one target
// (http://www.gnu.org/software/make/manual/html_node/Multiple-Rules.html).
func (mf *Makefile) Rule(target string) Rule {
	for _, rule := range mf.Rules {
		if rule.Target() == target {
			return rule
		}
	}
	return nil
}

type Rule interface {
	Target() string
	Prereqs() []string
	Recipes() []string
}

// Expand returns a clone of mf with Prereqs filepath globs expanded. If rules
// contain globs, they are replaced with BasicRules with the globs expanded.
//
// Only globs containing "*" are detected.
func (c *Config) Expand(orig *Makefile) (*Makefile, error) {
	var mf Makefile
	mf.Rules = make([]Rule, len(orig.Rules))
	for i, rule := range orig.Rules {
		var hasGlob bool
		for _, target := range rule.Prereqs() {
			if strings.Contains(target, "*") {
				hasGlob = true
				break
			}
		}
		if hasGlob {
			var expandedPrereqs []string
			for _, target := range rule.Prereqs() {
				files, err := rwvfs.Glob(walkableRWVFS{c.fs()}, "", target)
				if err != nil {
					return nil, err
				}
				expandedPrereqs = append(expandedPrereqs, files...)
			}

			mf.Rules[i] = &BasicRule{
				TargetFile:  rule.Target(),
				PrereqFiles: expandedPrereqs,
				RecipeCmds:  rule.Recipes(),
			}
		} else {
			mf.Rules[i] = rule
		}
	}
	return &mf, nil
}

func Marshal(mf *Makefile) ([]byte, error) {
	return marshal(mf, true)
}

func marshal(mf *Makefile, allRule bool) ([]byte, error) {
	var b bytes.Buffer

	if allRule {
		var all []string
		for _, rule := range mf.Rules {
			ruleName := rule.Target()
			all = append(all, ruleName)
		}
		if len(all) > 0 {
			fmt.Fprintln(&b, ".PHONY: all")
			fmt.Fprintf(&b, "all: %s\n", strings.Join(all, " "))
		}
		fmt.Fprintln(&b)
	}

	for i, rule := range mf.Rules {
		if i != 0 {
			fmt.Fprintln(&b)
		}

		ruleName := rule.Target()
		fmt.Fprintf(&b, "%s:", ruleName)
		for _, prereq := range rule.Prereqs() {
			fmt.Fprintf(&b, " %s", prereq)
		}
		fmt.Fprintln(&b)
		for _, recipe := range rule.Recipes() {
			fmt.Fprintf(&b, "\t%s\n", recipe)
		}
	}

	return b.Bytes(), nil
}

var cleanRE = regexp.MustCompile(`^[\w\d_/.-]+$`)

func Quote(s string) string {
	if cleanRE.MatchString(s) {
		return s
	}
	q := strconv.Quote(s)
	return "'" + strings.Replace(q[1:len(q)-1], "'", "", -1) + "'"
}

func QuoteList(ss []string) []string {
	q := make([]string, len(ss))
	for i, s := range ss {
		q[i] = Quote(s)
	}
	return q
}
<commit_msg>Set glob prefix to avoid checking ALL files in FS<commit_after>package makex

import (
	"bytes"
	"fmt"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/sourcegraph/rwvfs"
)

type Makefile struct {
	Rules []Rule
}

type BasicRule struct {
	TargetFile  string
	PrereqFiles []string
	RecipeCmds  []string
}

func (r *BasicRule) Target() string    { return r.TargetFile }
func (r *BasicRule) Prereqs() []string { return r.PrereqFiles }
func (r *BasicRule) Recipes() []string { return r.RecipeCmds }

// Rule returns the rule to make the specified target if it exists, or nil
// otherwise.
//
// TODO(sqs): support multiple rules for one target
// (http://www.gnu.org/software/make/manual/html_node/Multiple-Rules.html).
func (mf *Makefile) Rule(target string) Rule {
	for _, rule := range mf.Rules {
		if rule.Target() == target {
			return rule
		}
	}
	return nil
}

type Rule interface {
	Target() string
	Prereqs() []string
	Recipes() []string
}

// Expand returns a clone of mf with Prereqs filepath globs expanded. If rules
// contain globs, they are replaced with BasicRules with the globs expanded.
//
// Only globs containing "*" are detected.
func (c *Config) Expand(orig *Makefile) (*Makefile, error) {
	var mf Makefile
	mf.Rules = make([]Rule, len(orig.Rules))
	for i, rule := range orig.Rules {
		var hasGlob bool
		for _, target := range rule.Prereqs() {
			if strings.Contains(target, "*") {
				hasGlob = true
				break
			}
		}
		if hasGlob {
			var expandedPrereqs []string
			for _, target := range rule.Prereqs() {
				files, err := rwvfs.Glob(walkableRWVFS{c.fs()}, globPrefix(target), target)
				if err != nil {
					return nil, err
				}
				expandedPrereqs = append(expandedPrereqs, files...)
			}

			mf.Rules[i] = &BasicRule{
				TargetFile:  rule.Target(),
				PrereqFiles: expandedPrereqs,
				RecipeCmds:  rule.Recipes(),
			}
		} else {
			mf.Rules[i] = rule
		}
	}
	return &mf, nil
}

// globPrefix returns all path components up to (not including) the first path
// component that contains a "*".
func globPrefix(path string) string {
	cs := strings.Split(path, string(filepath.Separator))
	var prefix []string
	for _, c := range cs {
		if strings.Contains(c, "*") {
			break
		}
		prefix = append(prefix, c)
	}
	return filepath.Join(prefix...)
}

func Marshal(mf *Makefile) ([]byte, error) {
	return marshal(mf, true)
}

func marshal(mf *Makefile, allRule bool) ([]byte, error) {
	var b bytes.Buffer

	if allRule {
		var all []string
		for _, rule := range mf.Rules {
			ruleName := rule.Target()
			all = append(all, ruleName)
		}
		if len(all) > 0 {
			fmt.Fprintln(&b, ".PHONY: all")
			fmt.Fprintf(&b, "all: %s\n", strings.Join(all, " "))
		}
		fmt.Fprintln(&b)
	}

	for i, rule := range mf.Rules {
		if i != 0 {
			fmt.Fprintln(&b)
		}

		ruleName := rule.Target()
		fmt.Fprintf(&b, "%s:", ruleName)
		for _, prereq := range rule.Prereqs() {
			fmt.Fprintf(&b, " %s", prereq)
		}
		fmt.Fprintln(&b)
		for _, recipe := range rule.Recipes() {
			fmt.Fprintf(&b, "\t%s\n", recipe)
		}
	}

	return b.Bytes(), nil
}

var cleanRE = regexp.MustCompile(`^[\w\d_/.-]+$`)

func Quote(s string) string {
	if cleanRE.MatchString(s) {
		return s
	}
	q := strconv.Quote(s)
	return "'" + strings.Replace(q[1:len(q)-1], "'", "", -1) + "'"
}

func QuoteList(ss []string) []string {
	q := make([]string, len(ss))
	for i, s := range ss {
		q[i] = Quote(s)
	}
	return q
}
<|endoftext|>


<commit_before>package tumblr

import (
	"encoding/json"
	"github.com/MariaTerzieva/gotumblr"
	"golang.org/x/net/html"
	"sort"
	"strconv"
	"strings"
)

// Post is a representation of a single tumblr post
type Post struct {
	ID    int64  `json:"id"`
	Title string `json:"title"`
	URL   string `json:"url"`
	Image string `json:"image"`
	Likes int64  `json:"likes"`
}

// GoTumblrToPost converts a gotumblr.TextPost into a Post
func GoTumblrToPost(tumblrPost *gotumblr.TextPost) *Post {
	image := getImageFromPostBody(tumblrPost.Body)
	likes := tumblrPost.Note_count
	post := Post{
		ID:    tumblrPost.Id,
		Title: tumblrPost.Title,
		URL:   tumblrPost.Post_url,
		Image: image,
		Likes: likes,
	}
	return &post
}

// CSVToPost converts a CSV row into a Post
func CSVToPost(row []string) *Post {
	id, err := strconv.ParseInt(row[0], 10, 64)
	if err != nil {
		id = 0
	}
	likes, err := strconv.ParseInt(row[4], 10, 64)
	if err != nil {
		likes = 0
	}
	post := Post{
		ID:    id,
		Title: row[1],
		URL:   row[2],
		Image: row[3],
		Likes: likes,
	}
	return &post
}

// PostsToJSON converts a Post into a JSON string
func PostsToJSON(posts []Post) string {
	jsonPosts, _ := json.Marshal(posts)
	return string(jsonPosts)
}

// SortPosts sorts Posts in reverse ID order
func SortPosts(posts *[]Post) *[]Post {
	sort.Sort(SortByID(*posts))
	sort.Sort(sort.Reverse(SortByID(*posts)))
	return posts
}

// SortByID is an interface for Sorting
type SortByID []Post

func (a SortByID) Len() int           { return len(a) }
func (a SortByID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a SortByID) Less(i, j int) bool { return a[i].ID < a[j].ID }

// getImageFromPostBody parses the body of a post and returns the url of the image
func getImageFromPostBody(body string) string {
	bodyReader := strings.NewReader(body)
	tokenizer := html.NewTokenizer(bodyReader)

	for tokenizer.Next() != html.ErrorToken {
		token := tokenizer.Token()
		if token.Data == "img" {
			for _, attr := range token.Attr {
				if attr.Key == "src" {
					return attr.Val
				}
			}
		}
	}
	return ""
}
<commit_msg>Remove useless sort<commit_after>package tumblr

import (
	"encoding/json"
	"github.com/MariaTerzieva/gotumblr"
	"golang.org/x/net/html"
	"sort"
	"strconv"
	"strings"
)

// Post is a representation of a single tumblr post
type Post struct {
	ID    int64  `json:"id"`
	Title string `json:"title"`
	URL   string `json:"url"`
	Image string `json:"image"`
	Likes int64  `json:"likes"`
}

// GoTumblrToPost converts a gotumblr.TextPost into a Post
func GoTumblrToPost(tumblrPost *gotumblr.TextPost) *Post {
	image := getImageFromPostBody(tumblrPost.Body)
	likes := tumblrPost.Note_count
	post := Post{
		ID:    tumblrPost.Id,
		Title: tumblrPost.Title,
		URL:   tumblrPost.Post_url,
		Image: image,
		Likes: likes,
	}
	return &post
}

// CSVToPost converts a CSV row into a Post
func CSVToPost(row []string) *Post {
	id, err := strconv.ParseInt(row[0], 10, 64)
	if err != nil {
		id = 0
	}
	likes, err := strconv.ParseInt(row[4], 10, 64)
	if err != nil {
		likes = 0
	}
	post := Post{
		ID:    id,
		Title: row[1],
		URL:   row[2],
		Image: row[3],
		Likes: likes,
	}
	return &post
}

// PostsToJSON converts a Post into a JSON string
func PostsToJSON(posts []Post) string {
	jsonPosts, _ := json.Marshal(posts)
	return string(jsonPosts)
}

// SortPosts sorts Posts in reverse ID order
func SortPosts(posts *[]Post) *[]Post {
	sort.Sort(sort.Reverse(SortByID(*posts)))
	return posts
}

// SortByID is an interface for Sorting
type SortByID []Post

func (a SortByID) Len() int           { return len(a) }
func (a SortByID) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a SortByID) Less(i, j int) bool { return a[i].ID < a[j].ID }

// getImageFromPostBody parses the body of a post and returns the url of the image
func getImageFromPostBody(body string) string {
	bodyReader := strings.NewReader(body)
	tokenizer := html.NewTokenizer(bodyReader)

	for tokenizer.Next() != html.ErrorToken {
		token := tokenizer.Token()
		if token.Data == "img" {
			for _, attr := range token.Attr {
				if attr.Key == "src" {
					return attr.Val
				}
			}
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package mount

import (
	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/hanwen/go-fuse/v2/fuse"
	"os"
	"syscall"
	"time"
)

func (wfs *WFS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
	println("input node id", input.NodeId)
	if input.NodeId == 1 {
		wfs.setRootAttr(out)
		return fuse.OK
	}

	_, entry, status := wfs.maybeReadEntry(input.NodeId)
	if status != fuse.OK {
		return status
	}
	out.AttrValid = 1
	wfs.setAttrByPbEntry(&out.Attr, input.NodeId, entry)

	return fuse.OK
}

func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
	return fuse.ENOSYS
}
func (wfs *WFS) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, dest []byte) (size uint32, code fuse.Status) {
	return 0, fuse.ENOSYS
}

func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
	return fuse.ENOSYS
}

func (wfs *WFS) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (n uint32, code fuse.Status) {
	return 0, fuse.ENOSYS
}

func (wfs *WFS) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status {
	return fuse.ENOSYS
}

func (wfs *WFS) setRootAttr(out *fuse.AttrOut) {
	now := uint64(time.Now().Unix())
	out.AttrValid = 119
	out.Ino = 1
	setBlksize(&out.Attr, blockSize)
	out.Uid = wfs.option.MountUid
	out.Gid = wfs.option.MountGid
	out.Mtime = now
	out.Ctime = now
	out.Atime = now
	out.Mode = toSystemType(os.ModeDir) | uint32(wfs.option.MountMode)
	out.Nlink = 1
}

func (wfs *WFS) setAttrByPbEntry(out *fuse.Attr, inode uint64, entry *filer_pb.Entry) {
	out.Ino = inode
	out.Uid = entry.Attributes.Uid
	out.Gid = entry.Attributes.Gid
	out.Mode = toSystemMode(os.FileMode(entry.Attributes.FileMode))
	out.Mtime = uint64(entry.Attributes.Mtime)
	out.Ctime = uint64(entry.Attributes.Mtime)
	out.Atime = uint64(entry.Attributes.Mtime)
	if entry.HardLinkCounter > 0 {
		out.Nlink = uint32(entry.HardLinkCounter)
	} else {
		out.Nlink = 1
	}
	out.Size = filer.FileSize(entry)
	out.Blocks = (out.Size + blockSize - 1) / blockSize
	setBlksize(out, blockSize)
}

func (wfs *WFS) setAttrByFilerEntry(out *fuse.Attr, inode uint64, entry *filer.Entry) {
	out.Ino = inode
	out.Size = entry.FileSize
	out.Blocks = (out.Size + blockSize - 1) / blockSize
	setBlksize(out, blockSize)
	out.Atime = uint64(entry.Attr.Mtime.Unix())
	out.Mtime = uint64(entry.Attr.Mtime.Unix())
	out.Ctime = uint64(entry.Attr.Mtime.Unix())
	out.Crtime_ = uint64(entry.Attr.Crtime.Unix())
	out.Mode = toSystemMode(entry.Attr.Mode)
	if entry.HardLinkCounter > 0 {
		out.Nlink = uint32(entry.HardLinkCounter)
	} else {
		out.Nlink = 1
	}
	out.Uid = entry.Attr.Uid
	out.Gid = entry.Attr.Gid
}

func (wfs *WFS) outputEntry(out *fuse.EntryOut, inode uint64, entry *filer.Entry) {
	out.NodeId = inode
	out.Generation = 1
	out.EntryValid = 1
	out.AttrValid = 1
	wfs.setAttrByFilerEntry(&out.Attr, inode, entry)
}

func toSystemMode(mode os.FileMode) uint32 {
	return toSystemType(mode) | uint32(mode)
}

func toSystemType(mode os.FileMode) uint32 {
	switch mode & os.ModeType {
	case os.ModeDir:
		return syscall.S_IFDIR
	case os.ModeSymlink:
		return syscall.S_IFLNK
	case os.ModeNamedPipe:
		return syscall.S_IFIFO
	case os.ModeSocket:
		return syscall.S_IFSOCK
	case os.ModeDevice:
		return syscall.S_IFBLK
	case os.ModeCharDevice:
		return syscall.S_IFCHR
	default:
		return syscall.S_IFREG
	}
}
<commit_msg>sync format<commit_after>package mount

import (
	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/hanwen/go-fuse/v2/fuse"
	"os"
	"syscall"
	"time"
)

func (wfs *WFS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
	println("input node id", input.NodeId)
	if input.NodeId == 1 {
		wfs.setRootAttr(out)
		return fuse.OK
	}

	_, entry, status := wfs.maybeReadEntry(input.NodeId)
	if status != fuse.OK {
		return status
	}
	out.AttrValid = 1
	wfs.setAttrByPbEntry(&out.Attr, input.NodeId, entry)

	return fuse.OK
}

func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
	return fuse.ENOSYS
}
func (wfs *WFS) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, dest []byte) (size uint32, code fuse.Status) {
	return 0, fuse.ENOSYS
}

func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
	return fuse.ENOSYS
}

func (wfs *WFS) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (n uint32, code fuse.Status) {
	return 0, fuse.ENOSYS
}

func (wfs *WFS) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status {
	return fuse.ENOSYS
}

func (wfs *WFS) setRootAttr(out *fuse.AttrOut) {
	now := uint64(time.Now().Unix())
	out.AttrValid = 119
	out.Ino = 1
	setBlksize(&out.Attr, blockSize)
	out.Uid = wfs.option.MountUid
	out.Gid = wfs.option.MountGid
	out.Mtime = now
	out.Ctime = now
	out.Atime = now
	out.Mode = toSystemType(os.ModeDir) | uint32(wfs.option.MountMode)
	out.Nlink = 1
}

func (wfs *WFS) setAttrByPbEntry(out *fuse.Attr, inode uint64, entry *filer_pb.Entry) {
	out.Ino = inode
	out.Size = filer.FileSize(entry)
	out.Blocks = (out.Size + blockSize - 1) / blockSize
	setBlksize(out, blockSize)
	out.Mtime = uint64(entry.Attributes.Mtime)
	out.Ctime = uint64(entry.Attributes.Mtime)
	out.Atime = uint64(entry.Attributes.Mtime)
	out.Mode = toSystemMode(os.FileMode(entry.Attributes.FileMode))
	if entry.HardLinkCounter > 0 {
		out.Nlink = uint32(entry.HardLinkCounter)
	} else {
		out.Nlink = 1
	}
	out.Uid = entry.Attributes.Uid
	out.Gid = entry.Attributes.Gid
}

func (wfs *WFS) setAttrByFilerEntry(out *fuse.Attr, inode uint64, entry *filer.Entry) {
	out.Ino = inode
	out.Size = entry.FileSize
	out.Blocks = (out.Size + blockSize - 1) / blockSize
	setBlksize(out, blockSize)
	out.Atime = uint64(entry.Attr.Mtime.Unix())
	out.Mtime = uint64(entry.Attr.Mtime.Unix())
	out.Ctime = uint64(entry.Attr.Mtime.Unix())
	out.Crtime_ = uint64(entry.Attr.Crtime.Unix())
	out.Mode = toSystemMode(entry.Attr.Mode)
	if entry.HardLinkCounter > 0 {
		out.Nlink = uint32(entry.HardLinkCounter)
	} else {
		out.Nlink = 1
	}
	out.Uid = entry.Attr.Uid
	out.Gid = entry.Attr.Gid
}

func (wfs *WFS) outputEntry(out *fuse.EntryOut, inode uint64, entry *filer.Entry) {
	out.NodeId = inode
	out.Generation = 1
	out.EntryValid = 1
	out.AttrValid = 1
	wfs.setAttrByFilerEntry(&out.Attr, inode, entry)
}

func toSystemMode(mode os.FileMode) uint32 {
	return toSystemType(mode) | uint32(mode)
}

func toSystemType(mode os.FileMode) uint32 {
	switch mode & os.ModeType {
	case os.ModeDir:
		return syscall.S_IFDIR
	case os.ModeSymlink:
		return syscall.S_IFLNK
	case os.ModeNamedPipe:
		return syscall.S_IFIFO
	case os.ModeSocket:
		return syscall.S_IFSOCK
	case os.ModeDevice:
		return syscall.S_IFBLK
	case os.ModeCharDevice:
		return syscall.S_IFCHR
	default:
		return syscall.S_IFREG
	}
}
<|endoftext|>


<commit_before>package types

import (
	"time"

	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/pkg/version"
	"github.com/docker/docker/runconfig"
)

// ContainerCreateResponse contains the information returned to a client on the
// creation of a new container.
type ContainerCreateResponse struct {
	// ID is the ID of the created container.
	ID string `json:"Id"`

	// Warnings are any warnings encountered during the creation of the container.
	Warnings []string `json:"Warnings"`
}

// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
	// ID is the exec ID.
	ID string `json:"Id"`
}

// POST /auth
type AuthResponse struct {
	// Status is the authentication status
	Status string `json:"Status"`
}

// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
	// StatusCode is the status code of the wait job
	StatusCode int `json:"StatusCode"`
}

// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
	ID string `json:"Id"`
}

// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
	Kind int
	Path string
}

// GET "/images/{name:.*}/history"
type ImageHistory struct {
	ID        string `json:"Id"`
	Created   int64
	CreatedBy string
	Tags      []string
	Size      int64
	Comment   string
}

// DELETE "/images/{name:.*}"
type ImageDelete struct {
	Untagged string `json:",omitempty"`
	Deleted  string `json:",omitempty"`
}

// GET "/images/json"
type Image struct {
	ID          string `json:"Id"`
	ParentId    string
	RepoTags    []string
	RepoDigests []string
	Created     int
	Size        int
	VirtualSize int
	Labels      map[string]string
}

// GET "/images/{name:.*}/json"
type ImageInspect struct {
	Id              string
	Parent          string
	Comment         string
	Created         time.Time
	Container       string
	ContainerConfig *runconfig.Config
	DockerVersion   string
	Author          string
	Config          *runconfig.Config
	Architecture    string
	Os              string
	Size            int64
	VirtualSize     int64
}

// GET  "/containers/json"
type Port struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type Container struct {
	ID         string            `json:"Id"`
	Names      []string          `json:",omitempty"`
	Image      string            `json:",omitempty"`
	Command    string            `json:",omitempty"`
	Created    int               `json:",omitempty"`
	Ports      []Port            `json:",omitempty"`
	SizeRw     int               `json:",omitempty"`
	SizeRootFs int               `json:",omitempty"`
	Labels     map[string]string `json:",omitempty"`
	Status     string            `json:",omitempty"`
}

// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
	Resource string
}

// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
	Processes [][]string
	Titles    []string
}

type Version struct {
	Version       string
	ApiVersion    version.Version
	GitCommit     string
	GoVersion     string
	Os            string
	Arch          string
	KernelVersion string `json:",omitempty"`
	Experimental  bool
}

// GET "/info"
type Info struct {
	ID                 string
	Containers         int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	MemoryLimit        bool
	SwapLimit          bool
	CpuCfsPeriod       bool
	CpuCfsQuota        bool
	IPv4Forwarding     bool
	Debug              bool
	NFd                int
	OomKillDisable     bool
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	IndexServerAddress string
	RegistryConfig     interface{}
	InitSha1           string
	InitPath           string
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HttpProxy          string
	HttpsProxy         string
	NoProxy            string
	Name               string
	Labels             []string
	ExperimentalBuild  bool
}

// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
}

type ContainerState struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string
	StartedAt  time.Time
	FinishedAt time.Time
}

// GET "/containers/{name:.*}/json"
type ContainerJSON struct {
	Id              string
	Created         time.Time
	Path            string
	Args            []string
	Config          *runconfig.Config
	State           *ContainerState
	Image           string
	NetworkSettings *network.Settings
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	ExecDriver      string
	MountLabel      string
	ProcessLabel    string
	Volumes         map[string]string
	VolumesRW       map[string]bool
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *runconfig.HostConfig
}
<commit_msg>Expose old config field for api < 1.19<commit_after>package types

import (
	"time"

	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/pkg/version"
	"github.com/docker/docker/runconfig"
)

// ContainerCreateResponse contains the information returned to a client on the
// creation of a new container.
type ContainerCreateResponse struct {
	// ID is the ID of the created container.
	ID string `json:"Id"`

	// Warnings are any warnings encountered during the creation of the container.
	Warnings []string `json:"Warnings"`
}

// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
	// ID is the exec ID.
	ID string `json:"Id"`
}

// POST /auth
type AuthResponse struct {
	// Status is the authentication status
	Status string `json:"Status"`
}

// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
	// StatusCode is the status code of the wait job
	StatusCode int `json:"StatusCode"`
}

// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
	ID string `json:"Id"`
}

// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
	Kind int
	Path string
}

// GET "/images/{name:.*}/history"
type ImageHistory struct {
	ID        string `json:"Id"`
	Created   int64
	CreatedBy string
	Tags      []string
	Size      int64
	Comment   string
}

// DELETE "/images/{name:.*}"
type ImageDelete struct {
	Untagged string `json:",omitempty"`
	Deleted  string `json:",omitempty"`
}

// GET "/images/json"
type Image struct {
	ID          string `json:"Id"`
	ParentId    string
	RepoTags    []string
	RepoDigests []string
	Created     int
	Size        int
	VirtualSize int
	Labels      map[string]string
}

// GET "/images/{name:.*}/json"
type ImageInspect struct {
	Id              string
	Parent          string
	Comment         string
	Created         time.Time
	Container       string
	ContainerConfig *runconfig.Config
	DockerVersion   string
	Author          string
	Config          *runconfig.Config
	Architecture    string
	Os              string
	Size            int64
	VirtualSize     int64
}

// GET  "/containers/json"
type Port struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type Container struct {
	ID         string            `json:"Id"`
	Names      []string          `json:",omitempty"`
	Image      string            `json:",omitempty"`
	Command    string            `json:",omitempty"`
	Created    int               `json:",omitempty"`
	Ports      []Port            `json:",omitempty"`
	SizeRw     int               `json:",omitempty"`
	SizeRootFs int               `json:",omitempty"`
	Labels     map[string]string `json:",omitempty"`
	Status     string            `json:",omitempty"`
}

// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
	Resource string
}

// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
	Processes [][]string
	Titles    []string
}

type Version struct {
	Version       string
	ApiVersion    version.Version
	GitCommit     string
	GoVersion     string
	Os            string
	Arch          string
	KernelVersion string `json:",omitempty"`
	Experimental  bool
}

// GET "/info"
type Info struct {
	ID                 string
	Containers         int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	MemoryLimit        bool
	SwapLimit          bool
	CpuCfsPeriod       bool
	CpuCfsQuota        bool
	IPv4Forwarding     bool
	Debug              bool
	NFd                int
	OomKillDisable     bool
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	IndexServerAddress string
	RegistryConfig     interface{}
	InitSha1           string
	InitPath           string
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HttpProxy          string
	HttpsProxy         string
	NoProxy            string
	Name               string
	Labels             []string
	ExperimentalBuild  bool
}

// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
}

type ContainerState struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string
	StartedAt  time.Time
	FinishedAt time.Time
}

// GET "/containers/{name:.*}/json"
type ContainerJSONBase struct {
	Id              string
	Created         time.Time
	Path            string
	Args            []string
	State           *ContainerState
	Image           string
	NetworkSettings *network.Settings
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	ExecDriver      string
	MountLabel      string
	ProcessLabel    string
	Volumes         map[string]string
	VolumesRW       map[string]bool
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *runconfig.HostConfig
}

type ContainerJSON struct {
	*ContainerJSONBase
	Config *runconfig.Config
}

// backcompatibility struct along with ContainerConfig
type ContainerJSONRaw struct {
	*ContainerJSONBase
	Config *ContainerConfig
}

type ContainerConfig struct {
	*runconfig.Config

	// backward compatibility, they now live in HostConfig
	Memory     int64
	MemorySwap int64
	CpuShares  int64
	Cpuset     string
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Paul R. Tagliamonte, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE. */

package dictd

/* server.go - infrastructure code for the dictd server
 *
 * In particular, this file contains a few interfaces and commonly used
 * structs for message passing, as well as generic routing code. */

import (
	"errors"
)

/* Command is the encapsulation for a user's request of the Server. */
type Command struct {
	Command string
	Params  []string
}

/* Definition is the encapsulation of a response for a given Entry. */
type Definition struct {
	Word             string
	Definition       string
	DictDatabase     Database
	DictDatabaseName string
}

/* Database is an interface for external Database "Backends" to implement. */
type Database interface {

	/* Method to handle incoming `MATCH` commands. */
	Match(name string, query string, strat string) []*Definition

	/* Method to handle incoming `DEFINE` commands. */
	Define(name string, query string) []*Definition

	/* Method to handle incoming `SHOW INFO` commands. */
	Info(name string) string

	/* Method to return a one-line Description of the Database. */
	Description(name string) string
}

/* Server encapsulation.
 *
 * This contains a bundle of useful helpers, as well as a few data structures
 * to handle registered Databases and Commands. */
type Server struct {
	Name      string
	Info      string
	databases map[string]Database
	commands  map[string]func(*Session, Command)
}

/* Define a word against the server, according to fun rules! */
func (this *Server) Define(
	database string,
	query string,
) ([]*Definition, error) {
	db := this.GetDatabase(database)
	if db == nil {
		return nil, errors.New("No such database")
	}
	return db.Define(database, query), nil
}

/* Register dict.Database `database` under `name`. */
func (this *Server) RegisterDatabase(database Database, name string) {
	this.databases[name] = database
}

/* Get dict.Database that has been registered under `name`. */
func (this *Server) GetDatabase(name string) Database {
	if value, ok := this.databases[name]; ok {
		return value
	}
	return nil
}

/* Register a Command `handler` under name `name`. */
func (this *Server) RegisterHandler(
	name string,
	handler func(*Session, Command),
) {
	this.commands[name] = handler
}

/* Get a Command handler for the given dict.Command `command` */
func (this *Server) GetHandler(command *Command) func(*Session, Command) {
	name := command.Command

	if value, ok := this.commands[name]; ok {
		return value
	}
	return nil
}

/* Create a new server by name `name`. */
func NewServer(name string) Server {
	server := Server{
		Name:      name,
		Info:      "",
		commands:  map[string]func(*Session, Command){},
		databases: map[string]Database{},
	}
	registerDefaultHandlers(&server)
	return server
}
<commit_msg>Add in custom */! logic<commit_after>/**
 * Copyright (c) Paul R. Tagliamonte, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE. */

package dictd

/* server.go - infrastructure code for the dictd server
 *
 * In particular, this file contains a few interfaces and commonly used
 * structs for message passing, as well as generic routing code. */

import (
	"errors"
)

/* Command is the encapsulation for a user's request of the Server. */
type Command struct {
	Command string
	Params  []string
}

/* Definition is the encapsulation of a response for a given Entry. */
type Definition struct {
	Word             string
	Definition       string
	DictDatabase     Database
	DictDatabaseName string
}

/* Database is an interface for external Database "Backends" to implement. */
type Database interface {

	/* Method to handle incoming `MATCH` commands. */
	Match(name string, query string, strat string) []*Definition

	/* Method to handle incoming `DEFINE` commands. */
	Define(name string, query string) []*Definition

	/* Method to handle incoming `SHOW INFO` commands. */
	Info(name string) string

	/* Method to return a one-line Description of the Database. */
	Description(name string) string
}

/* Server encapsulation.
 *
 * This contains a bundle of useful helpers, as well as a few data structures
 * to handle registered Databases and Commands. */
type Server struct {
	Name      string
	Info      string
	databases map[string]Database
	commands  map[string]func(*Session, Command)
}

/* Define a word against the server, according to fun rules! */
func (this *Server) Define(
	database string,
	query string,
) ([]*Definition, error) {

	switch database {
	case "!":
		for database, databaseBackend := range this.databases {
			defs := databaseBackend.Define(database, query)
			if defs != nil && len(defs) != 0 {
				return defs, nil
			}
		}
		return make([]*Definition, 0), nil
	case "*":
		var allDefs = make([]*Definition, 0)
		for database, databaseBackend := range this.databases {
			defs := databaseBackend.Define(database, query)
			allDefs = append(allDefs, defs...)
		}
		return allDefs, nil
	}

	db := this.GetDatabase(database)
	if db == nil {
		return nil, errors.New("No such database")
	}
	return db.Define(database, query), nil
}

/* Register dict.Database `database` under `name`. */
func (this *Server) RegisterDatabase(database Database, name string) {
	this.databases[name] = database
}

/* Get dict.Database that has been registered under `name`. */
func (this *Server) GetDatabase(name string) Database {
	if value, ok := this.databases[name]; ok {
		return value
	}
	return nil
}

/* Register a Command `handler` under name `name`. */
func (this *Server) RegisterHandler(
	name string,
	handler func(*Session, Command),
) {
	this.commands[name] = handler
}

/* Get a Command handler for the given dict.Command `command` */
func (this *Server) GetHandler(command *Command) func(*Session, Command) {
	name := command.Command

	if value, ok := this.commands[name]; ok {
		return value
	}
	return nil
}

/* Create a new server by name `name`. */
func NewServer(name string) Server {
	server := Server{
		Name:      name,
		Info:      "",
		commands:  map[string]func(*Session, Command){},
		databases: map[string]Database{},
	}
	registerDefaultHandlers(&server)
	return server
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"testing"
)

func TestFormatYear(t *testing.T) {
	cases := []struct {
		in, want string
	}{
		{"2015", "Thu, 01 Jan 2015 00:00:00 +0000"},
		{"20151102", "Mon, 02 Nov 2015 00:00:00 +0000"},
		{"20152402", "Tue, 24 Feb 2015 00:00:00 +0000"},
		{"", ""},
		{"NOT_A_YEAR", ""},
	}
	for _, c := range cases {
		got := formatYear(c.in)
		if got != c.want {
			t.Errorf("formatYear(%q) == %q, want %q", c.in, got, c.want)
		}
	}
}

func TestFileUrl(t *testing.T) {
	cases := []struct {
		relativePath, baseUrl, want string
	}{
		{"", "", ""},
		{"c/d/e", "a/b/", "a/b/c/d/e"},
		{"c d", "a/b/", "a/b/c%20d"},
	}
	for _, c := range cases {
		got := fileUrl(c.relativePath, c.baseUrl)
		if got != c.want {
			t.Errorf("fileUrl(%q, %q) == %q, want %q", c.relativePath, c.baseUrl, got, c.want)
		}
	}
}

func TestAddMetaTitle(t *testing.T) {
	title := "Nice Life (Feat. Basick)"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.Title != title {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.Title, title)
	}
}

func TestAddMetaTitleFallbackOnFilieName(t *testing.T) {
	title := "test.mp3"
	in := Item{}
	f, _ := os.Stat("./vendor/src/github.com/mikkyang/id3-go/test.mp3")

	addMeta("NOT_PATH_TO_FILE", f, &in)

	if in.Title != title {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.Title, title)
	}
}

func TestAddMetaPubDate(t *testing.T) {
	pubDate := "Mon, 25 Nov 2013 00:00:00 +0000"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.PubDate != pubDate {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.PubDate, pubDate)
	}

}
<commit_msg>fix assert message, wrong variable<commit_after>package main

import (
	"os"
	"testing"
)

func TestFormatYear(t *testing.T) {
	cases := []struct {
		in, want string
	}{
		{"2015", "Thu, 01 Jan 2015 00:00:00 +0000"},
		{"20151102", "Mon, 02 Nov 2015 00:00:00 +0000"},
		{"20152402", "Tue, 24 Feb 2015 00:00:00 +0000"},
		{"", ""},
		{"NOT_A_YEAR", ""},
	}
	for _, c := range cases {
		got := formatYear(c.in)
		if got != c.want {
			t.Errorf("formatYear(%q) == %q, want %q", c.in, got, c.want)
		}
	}
}

func TestFileUrl(t *testing.T) {
	cases := []struct {
		relativePath, baseUrl, want string
	}{
		{"", "", ""},
		{"c/d/e", "a/b/", "a/b/c/d/e"},
		{"c d", "a/b/", "a/b/c%20d"},
	}
	for _, c := range cases {
		got := fileUrl(c.relativePath, c.baseUrl)
		if got != c.want {
			t.Errorf("fileUrl(%q, %q) == %q, want %q", c.relativePath, c.baseUrl, got, c.want)
		}
	}
}

func TestAddMetaTitle(t *testing.T) {
	title := "Nice Life (Feat. Basick)"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.Title != title {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.Title, title)
	}
}

func TestAddMetaTitleFallbackOnFilieName(t *testing.T) {
	title := "test.mp3"
	in := Item{}
	f, _ := os.Stat("./vendor/src/github.com/mikkyang/id3-go/test.mp3")

	addMeta("NOT_PATH_TO_FILE", f, &in)

	if in.Title != title {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.Title == %q want %q", in.Title, title)
	}
}

func TestAddMetaPubDate(t *testing.T) {
	pubDate := "Mon, 25 Nov 2013 00:00:00 +0000"
	in := Item{}
	path := "./vendor/src/github.com/mikkyang/id3-go/test.mp3"
	f, _ := os.Stat(path)

	addMeta(path, f, &in)

	if in.PubDate != pubDate {
		t.Errorf("addMeta(<test.mp3>, <FileInfo>, <Item>) Item.PubDate == %q want %q", in.PubDate, pubDate)
	}

}
	}

}
<|endoftext|>


<commit_before>package taskrun

import (
	"github.com/taskcluster/taskcluster-worker/engines"
	"github.com/taskcluster/taskcluster-worker/plugins"
	"github.com/taskcluster/taskcluster-worker/runtime"
	"github.com/taskcluster/taskcluster-worker/runtime/client"
)

// Options required to create a TaskRun
type Options struct {
	Environment   runtime.Environment
	Engine        engines.Engine
	PluginManager *plugins.PluginManager
	Monitor       runtime.Monitor
	TaskInfo      runtime.TaskInfo
	Payload       map[string]interface{}
	Queue         client.Queue
}

// mustBeValid panics if Options contains empty values, this allows us to catch
// bugs early, rather than having to debug and trace throughout the entire stack.
func (o *Options) mustBeValid() {
	if o.Environment.GarbageCollector == nil {
		panic("taskrun: Options.Environment.GarbageCollector is nil")
	}
	if o.Environment.Monitor == nil {
		panic("taskrun: Options.Environment.Monitor is nil")
	}
	if o.Environment.TemporaryStorage == nil {
		panic("taskrun: Options.Environment.TemporaryStorage is nil")
	}
	if o.Environment.WebHookServer == nil {
		panic("taskrun: Options.Environment.WebHookServer is nil")
	}
	if o.Engine == nil {
		panic("taskrun: Options.Engine is nil")
	}
	if o.PluginManager == nil {
		panic("taskrun: Options.PluginManager is nil")
	}
	if o.Monitor == nil {
		panic("taskrun: Options.Monitor is nil")
	}
	if o.TaskInfo == (runtime.TaskInfo{}) {
		panic("taskrun: Options.TaskInfo is empty")
	}
	if o.Payload == nil {
		panic("taskrun: Options.Payload is nil")
	}
	if o.Queue == nil {
		panic("taskrun: Options.Queue is nil")
	}
}
<commit_msg>Fixed TaskInfo comparison bug<commit_after>package taskrun

import (
	"github.com/taskcluster/taskcluster-worker/engines"
	"github.com/taskcluster/taskcluster-worker/plugins"
	"github.com/taskcluster/taskcluster-worker/runtime"
	"github.com/taskcluster/taskcluster-worker/runtime/client"
)

// Options required to create a TaskRun
type Options struct {
	Environment   runtime.Environment
	Engine        engines.Engine
	PluginManager *plugins.PluginManager
	Monitor       runtime.Monitor
	TaskInfo      runtime.TaskInfo
	Payload       map[string]interface{}
	Queue         client.Queue
}

// mustBeValid panics if Options contains empty values, this allows us to catch
// bugs early, rather than having to debug and trace throughout the entire stack.
func (o *Options) mustBeValid() {
	if o.Environment.GarbageCollector == nil {
		panic("taskrun: Options.Environment.GarbageCollector is nil")
	}
	if o.Environment.Monitor == nil {
		panic("taskrun: Options.Environment.Monitor is nil")
	}
	if o.Environment.TemporaryStorage == nil {
		panic("taskrun: Options.Environment.TemporaryStorage is nil")
	}
	if o.Environment.WebHookServer == nil {
		panic("taskrun: Options.Environment.WebHookServer is nil")
	}
	if o.Engine == nil {
		panic("taskrun: Options.Engine is nil")
	}
	if o.PluginManager == nil {
		panic("taskrun: Options.PluginManager is nil")
	}
	if o.Monitor == nil {
		panic("taskrun: Options.Monitor is nil")
	}
	if o.TaskInfo.TaskID == "" {
		panic("taskrun: Options.TaskInfo is empty")
	}
	if o.Payload == nil {
		panic("taskrun: Options.Payload is nil")
	}
	if o.Queue == nil {
		panic("taskrun: Options.Queue is nil")
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 The LUCI Authors.
//
// 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 configcron

import (
	"context"
	"math/rand"
	"testing"
	"time"

	"google.golang.org/protobuf/encoding/prototext"
	"google.golang.org/protobuf/proto"

	"go.chromium.org/luci/common/clock"
	"go.chromium.org/luci/common/clock/testclock"
	"go.chromium.org/luci/common/data/rand/mathrand"
	"go.chromium.org/luci/config"
	"go.chromium.org/luci/config/cfgclient"
	cfgmemory "go.chromium.org/luci/config/impl/memory"
	"go.chromium.org/luci/gae/filter/txndefer"
	gaememory "go.chromium.org/luci/gae/impl/memory"
	"go.chromium.org/luci/gae/service/datastore"
	"go.chromium.org/luci/server/tq"
	"go.chromium.org/luci/server/tq/tqtesting"

	cvconfig "go.chromium.org/luci/cv/internal/config"
	"go.chromium.org/luci/cv/internal/prjmanager/pmtest"

	. "github.com/smartystreets/goconvey/convey"
	. "go.chromium.org/luci/common/testing/assertions"
)

var testNow = testclock.TestTimeLocal.Round(1 * time.Millisecond)

func TestConfigRefreshCron(t *testing.T) {
	t.Parallel()

	Convey("Config refresh cron works", t, func() {
		ctx, tqScheduler := mkTestingCtx()

		Convey("for a new project", func() {
			ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{
				config.ProjectSet("chromium"): {cvconfig.ConfigFileName: ""},
			}))
			// Project chromium doesn't exist in datastore.
			err := SubmitRefreshTasks(ctx)
			So(err, ShouldBeNil)
			So(tqScheduler.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
				{Project: "chromium"},
			})
			tqScheduler.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
			So(pmtest.Projects(tqScheduler.Tasks()), ShouldResemble, []string{"chromium"})
		})

		Convey("for an existing project", func() {
			ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{
				config.ProjectSet("chromium"): {cvconfig.ConfigFileName: ""},
			}))
			So(datastore.Put(ctx, &cvconfig.ProjectConfig{
				Project: "chromium",
				Enabled: true,
			}), ShouldBeNil)
			err := SubmitRefreshTasks(ctx)
			So(err, ShouldBeNil)
			So(tqScheduler.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
				{Project: "chromium"},
			})
			tqScheduler.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
			So(pmtest.Projects(tqScheduler.Tasks()), ShouldResemble, []string{"chromium"})
		})

		Convey("Disable project", func() {
			Convey("that doesn't have CV config", func() {
				ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{
					config.ProjectSet("chromium"): {"other.cfg": ""},
				}))
				So(datastore.Put(ctx, &cvconfig.ProjectConfig{
					Project: "chromium",
					Enabled: true,
				}), ShouldBeNil)
				err := SubmitRefreshTasks(ctx)
				So(err, ShouldBeNil)
				So(tqScheduler.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
					{Project: "chromium", Disable: true},
				})
				tqScheduler.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
				So(pmtest.Projects(tqScheduler.Tasks()), ShouldResemble, []string{"chromium"})
			})
			Convey("that doesn't exist in LUCI Config", func() {
				ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{}))
				So(datastore.Put(ctx, &cvconfig.ProjectConfig{
					Project: "chromium",
					Enabled: true,
				}), ShouldBeNil)
				err := SubmitRefreshTasks(ctx)
				So(err, ShouldBeNil)
				So(tqScheduler.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
					{Project: "chromium", Disable: true},
				})
				tqScheduler.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
				So(pmtest.Projects(tqScheduler.Tasks()), ShouldResemble, []string{"chromium"})
			})

			Convey("Skip already disabled Project", func() {
				ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{}))
				So(datastore.Put(ctx, &cvconfig.ProjectConfig{
					Project: "foo",
					Enabled: false,
				}), ShouldBeNil)
				err := SubmitRefreshTasks(ctx)
				So(err, ShouldBeNil)
				So(tqScheduler.Tasks(), ShouldBeEmpty)
			})
		})
	})
}

func mkTestingCtx() (context.Context, *tqtesting.Scheduler) {
	ctx, tclock := testclock.UseTime(context.Background(), testNow)
	ctx = mathrand.Set(ctx, rand.New(rand.NewSource(1)))
	tclock.SetTimerCallback(func(dur time.Duration, _ clock.Timer) {
		// Move fake time forward whenever someone's waiting for it.
		tclock.Add(dur)
	})

	ctx = txndefer.FilterRDS(gaememory.Use(ctx))
	datastore.GetTestable(ctx).AutoIndex(true)
	datastore.GetTestable(ctx).Consistent(true)

	ctx, scheduler := tq.TestingContext(ctx, nil)
	return ctx, scheduler
}

func toProtoText(msg proto.Message) string {
	bs, err := prototext.Marshal(msg)
	So(err, ShouldBeNil)
	return string(bs)
}
<commit_msg>[cv] switch configcron tests to cvtesting.Test.<commit_after>// Copyright 2020 The LUCI Authors.
//
// 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 configcron

import (
	"testing"
	"time"

	"google.golang.org/protobuf/encoding/prototext"
	"google.golang.org/protobuf/proto"

	"go.chromium.org/luci/common/clock/testclock"
	"go.chromium.org/luci/config"
	"go.chromium.org/luci/config/cfgclient"
	cfgmemory "go.chromium.org/luci/config/impl/memory"
	"go.chromium.org/luci/gae/service/datastore"
	"go.chromium.org/luci/server/tq/tqtesting"

	cvconfig "go.chromium.org/luci/cv/internal/config"
	"go.chromium.org/luci/cv/internal/cvtesting"
	"go.chromium.org/luci/cv/internal/prjmanager/pmtest"

	. "github.com/smartystreets/goconvey/convey"
	. "go.chromium.org/luci/common/testing/assertions"
)

var testNow = testclock.TestTimeLocal.Round(1 * time.Millisecond)

func TestConfigRefreshCron(t *testing.T) {
	t.Parallel()

	Convey("Config refresh cron works", t, func() {
		ct := cvtesting.Test{}
		ctx, cancel := ct.SetUp()
		defer cancel()

		Convey("for a new project", func() {
			ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{
				config.ProjectSet("chromium"): {cvconfig.ConfigFileName: ""},
			}))
			// Project chromium doesn't exist in datastore.
			err := SubmitRefreshTasks(ctx)
			So(err, ShouldBeNil)
			So(ct.TQ.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
				{Project: "chromium"},
			})
			ct.TQ.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
			So(pmtest.Projects(ct.TQ.Tasks()), ShouldResemble, []string{"chromium"})
		})

		Convey("for an existing project", func() {
			ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{
				config.ProjectSet("chromium"): {cvconfig.ConfigFileName: ""},
			}))
			So(datastore.Put(ctx, &cvconfig.ProjectConfig{
				Project: "chromium",
				Enabled: true,
			}), ShouldBeNil)
			err := SubmitRefreshTasks(ctx)
			So(err, ShouldBeNil)
			So(ct.TQ.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
				{Project: "chromium"},
			})
			ct.TQ.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
			So(pmtest.Projects(ct.TQ.Tasks()), ShouldResemble, []string{"chromium"})
		})

		Convey("Disable project", func() {
			Convey("that doesn't have CV config", func() {
				ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{
					config.ProjectSet("chromium"): {"other.cfg": ""},
				}))
				So(datastore.Put(ctx, &cvconfig.ProjectConfig{
					Project: "chromium",
					Enabled: true,
				}), ShouldBeNil)
				err := SubmitRefreshTasks(ctx)
				So(err, ShouldBeNil)
				So(ct.TQ.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
					{Project: "chromium", Disable: true},
				})
				ct.TQ.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
				So(pmtest.Projects(ct.TQ.Tasks()), ShouldResemble, []string{"chromium"})
			})
			Convey("that doesn't exist in LUCI Config", func() {
				ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{}))
				So(datastore.Put(ctx, &cvconfig.ProjectConfig{
					Project: "chromium",
					Enabled: true,
				}), ShouldBeNil)
				err := SubmitRefreshTasks(ctx)
				So(err, ShouldBeNil)
				So(ct.TQ.Tasks().Payloads(), ShouldResembleProto, []*RefreshProjectConfigTask{
					{Project: "chromium", Disable: true},
				})
				ct.TQ.Run(ctx, tqtesting.StopAfterTask("refresh-project-config"))
				So(pmtest.Projects(ct.TQ.Tasks()), ShouldResemble, []string{"chromium"})
			})

			Convey("Skip already disabled Project", func() {
				ctx = cfgclient.Use(ctx, cfgmemory.New(map[config.Set]cfgmemory.Files{}))
				So(datastore.Put(ctx, &cvconfig.ProjectConfig{
					Project: "foo",
					Enabled: false,
				}), ShouldBeNil)
				err := SubmitRefreshTasks(ctx)
				So(err, ShouldBeNil)
				So(ct.TQ.Tasks(), ShouldBeEmpty)
			})
		})
	})
}

func toProtoText(msg proto.Message) string {
	bs, err := prototext.Marshal(msg)
	So(err, ShouldBeNil)
	return string(bs)
}
<|endoftext|>


<commit_before>package middleware

import (
	"context"
	"fmt"
	"net/http"

	dd_opentracing "github.com/DataDog/dd-trace-go/opentracing"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/remind101/pkg/httpx"
)

type OpentracingTracer struct {
	handler httpx.Handler
	router  *httpx.Router
}

func OpentracingTracing(h httpx.Handler, router *httpx.Router) *OpentracingTracer {
	return &OpentracingTracer{h, router}
}

func (h *OpentracingTracer) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	path := templatePath(h.router, r)
	route := fmt.Sprintf("%s %s", r.Method, path)

	var span opentracing.Span
	wireContext, err := opentracing.GlobalTracer().Extract(
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(r.Header))
	if err != nil {
		span = opentracing.StartSpan("server.request")
	} else {
		span = opentracing.StartSpan("server.request", ext.RPCServerOption(wireContext))
	}
	span.SetTag(dd_opentracing.ResourceName, route)
	span.SetTag(dd_opentracing.SpanType, "web")

	defer span.Finish()
	ctx = opentracing.ContextWithSpan(ctx, span)

	return h.handler.ServeHTTPContext(ctx, w, r)
}
<commit_msg>Add more request info to traces<commit_after>package middleware

import (
	"context"
	"fmt"
	"net/http"

	dd_opentracing "github.com/DataDog/dd-trace-go/opentracing"
	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"github.com/remind101/pkg/httpx"
)

type OpentracingTracer struct {
	handler httpx.Handler
	router  *httpx.Router
}

func OpentracingTracing(h httpx.Handler, router *httpx.Router) *OpentracingTracer {
	return &OpentracingTracer{h, router}
}

func (h *OpentracingTracer) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	path := templatePath(h.router, r)
	route := fmt.Sprintf("%s %s", r.Method, path)

	var span opentracing.Span
	wireContext, err := opentracing.GlobalTracer().Extract(
		opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(r.Header))
	if err != nil {
		span = opentracing.StartSpan("server.request")
	} else {
		span = opentracing.StartSpan("server.request", ext.RPCServerOption(wireContext))
	}
	span.SetTag(dd_opentracing.ResourceName, route)
	span.SetTag(dd_opentracing.SpanType, "web")
	span.SetTag("http.method", r.Method)
	span.SetTag("http.url", r.RequestURI)

	if rw, ok := w.(ResponseWriter); ok {
		span.SetTag("http.status_code", rw.Status())
	}

	if rid := httpx.RequestID(ctx); rid != "" {
		span.SetTag("request_id", rid)
	}

	defer span.Finish()
	ctx = opentracing.ContextWithSpan(ctx, span)

	reqErr := h.handler.ServeHTTPContext(ctx, w, r)

	if reqErr != nil {
		span.SetTag("error.msg", reqErr.Error())
	}

	return reqErr
}
<|endoftext|>


<commit_before>package json

import (
	"io"
)

// State is the internal state of parser.
type State byte

const (
	StateContent State = iota
	StateEscape
	StateDoubleQuote
	StateDoubleQuoteEscape
	StateSingleQuote
	StateSingleQuoteEscape
	StateComment
	StateSlash
	StateMultilineComment
	StateMultilineCommentStar
)

type Reader struct {
	io.Reader
	state State
}

func (v *Reader) Read(b []byte) (int, error) {
	n, err := v.Reader.Read(b)
	if err != nil {
		return n, err
	}
	p := b[:0]
	for _, x := range b[:n] {
		switch v.state {
		case StateContent:
			switch x {
			case '"':
				v.state = StateDoubleQuote
				p = append(p, x)
			case '\'':
				v.state = StateSingleQuote
				p = append(p, x)
			case '\\':
				v.state = StateEscape
			case '#':
				v.state = StateComment
			case '/':
				v.state = StateSlash
			default:
				p = append(p, x)
			}
		case StateEscape:
			p = append(p, '\\', x)
			v.state = StateContent
		case StateDoubleQuote:
			switch x {
			case '"':
				v.state = StateContent
				p = append(p, x)
			case '\\':
				v.state = StateDoubleQuoteEscape
			default:
				p = append(p, x)
			}
		case StateDoubleQuoteEscape:
			p = append(p, '\\', x)
			v.state = StateDoubleQuote
		case StateSingleQuote:
			switch x {
			case '\'':
				v.state = StateContent
				p = append(p, x)
			case '\\':
				v.state = StateSingleQuoteEscape
			default:
				p = append(p, x)
			}
		case StateSingleQuoteEscape:
			p = append(p, '\\', x)
			v.state = StateSingleQuote
		case StateComment:
			if x == '\n' {
				v.state = StateContent
			}
		case StateSlash:
			switch x {
			case '/':
				v.state = StateComment
			case '*':
				v.state = StateMultilineComment
			default:
				p = append(p, '/', x)
			}
		case StateMultilineComment:
			if x == '*' {
				v.state = StateMultilineCommentStar
			}
		case StateMultilineCommentStar:
			switch x {
			case '/':
				v.state = StateContent
			case '*':
				// Stay
			default:
				v.state = StateMultilineComment
			}
		default:
			panic("Unknown state.")
		}
	}
	return len(p), nil
}
<commit_msg>comments<commit_after>package json

import (
	"io"
)

// State is the internal state of parser.
type State byte

const (
	StateContent State = iota
	StateEscape
	StateDoubleQuote
	StateDoubleQuoteEscape
	StateSingleQuote
	StateSingleQuoteEscape
	StateComment
	StateSlash
	StateMultilineComment
	StateMultilineCommentStar
)

// Reader is a JSON reader which allows comments.
type Reader struct {
	io.Reader
	state State
}

// Read implements io.Reader.Read().
func (v *Reader) Read(b []byte) (int, error) {
	n, err := v.Reader.Read(b)
	if err != nil {
		return n, err
	}
	p := b[:0]
	for _, x := range b[:n] {
		switch v.state {
		case StateContent:
			switch x {
			case '"':
				v.state = StateDoubleQuote
				p = append(p, x)
			case '\'':
				v.state = StateSingleQuote
				p = append(p, x)
			case '\\':
				v.state = StateEscape
			case '#':
				v.state = StateComment
			case '/':
				v.state = StateSlash
			default:
				p = append(p, x)
			}
		case StateEscape:
			p = append(p, '\\', x)
			v.state = StateContent
		case StateDoubleQuote:
			switch x {
			case '"':
				v.state = StateContent
				p = append(p, x)
			case '\\':
				v.state = StateDoubleQuoteEscape
			default:
				p = append(p, x)
			}
		case StateDoubleQuoteEscape:
			p = append(p, '\\', x)
			v.state = StateDoubleQuote
		case StateSingleQuote:
			switch x {
			case '\'':
				v.state = StateContent
				p = append(p, x)
			case '\\':
				v.state = StateSingleQuoteEscape
			default:
				p = append(p, x)
			}
		case StateSingleQuoteEscape:
			p = append(p, '\\', x)
			v.state = StateSingleQuote
		case StateComment:
			if x == '\n' {
				v.state = StateContent
			}
		case StateSlash:
			switch x {
			case '/':
				v.state = StateComment
			case '*':
				v.state = StateMultilineComment
			default:
				p = append(p, '/', x)
			}
		case StateMultilineComment:
			if x == '*' {
				v.state = StateMultilineCommentStar
			}
		case StateMultilineCommentStar:
			switch x {
			case '/':
				v.state = StateContent
			case '*':
				// Stay
			default:
				v.state = StateMultilineComment
			}
		default:
			panic("Unknown state.")
		}
	}
	return len(p), nil
}
<|endoftext|>


<commit_before>package utils

// transfer2go/utils - Go utilities for transfer2go
//
// Author: Valentin Kuznetsov <vkuznet@gmail.com>

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"os"
	"os/user"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/vkuznet/x509proxy"
)

// ResponseType structure is what we expect to get for our URL call.
// It contains a request URL, the data chunk and possible error from remote
type ResponseType struct {
	Url        string // response url
	Data       []byte // response data, i.e. what we got with Body of the response
	Error      error  // http error, a non-2xx return code is not an error
	Status     string // http status string
	StatusCode int    // http status code
}

// UrlRequest structure holds details about url request's attributes
type UrlRequest struct {
	rurl string
	args string
	out  chan<- ResponseType
	ts   int64
}

// VERBOSE variable control verbosity level of client's utilities
var VERBOSE int

// variable to neglect auth layer
var Auth bool

// global HTTP client
var _client = HttpClient()

// global client's x509 certificates
var _certs []tls.Certificate

// UserDN function parses user Distinguished Name (DN) from client's HTTP request
func UserDN(r *http.Request) string {
	var names []interface{}
	for _, cert := range r.TLS.PeerCertificates {
		for _, name := range cert.Subject.Names {
			switch v := name.Value.(type) {
			case string:
				names = append(names, v)
			}
		}
	}
	parts := names[:7]
	return fmt.Sprintf("/DC=%s/DC=%s/OU=%s/OU=%s/CN=%s/CN=%s/CN=%s", parts...)
}

// client X509 certificates
func tlsCerts() ([]tls.Certificate, error) {
	if len(_certs) != 0 {
		return _certs, nil // use cached certs
	}
	uproxy := os.Getenv("X509_USER_PROXY")
	uckey := os.Getenv("X509_USER_KEY")
	ucert := os.Getenv("X509_USER_CERT")

	// check if /tmp/x509up_u$UID exists, if so setup X509_USER_PROXY env
	u, err := user.Current()
	if err == nil {
		fname := fmt.Sprintf("/tmp/x509up_u%s", u.Uid)
		if _, err := os.Stat(fname); err == nil {
			uproxy = fname
		}
	}
	if VERBOSE > 1 {
		log.WithFields(log.Fields{
			"uproxy": uproxy,
		}).Println("")
		log.WithFields(log.Fields{
			"uckey": uckey,
		}).Println("")
		log.WithFields(log.Fields{
			"ucert": ucert,
		}).Println("")
	}

	if uproxy == "" && uckey == "" { // user doesn't have neither proxy or user certs
		log.Warn("Neither proxy or user certs are found, to proceed use auth=false option otherwise setup X509 environment")
		return nil, nil
	}
	if uproxy != "" {
		// use local implementation of LoadX409KeyPair instead of tls one
		x509cert, err := x509proxy.LoadX509Proxy(uproxy)
		if err != nil {
			return nil, fmt.Errorf("failed to parse proxy X509 proxy set by X509_USER_PROXY: %v", err)
		}
		_certs = []tls.Certificate{x509cert}
		return _certs, nil
	}
	x509cert, err := tls.LoadX509KeyPair(ucert, uckey)
	if err != nil {
		return nil, fmt.Errorf("failed to parse user X509 certificate: %v", err)
	}
	_certs = []tls.Certificate{x509cert}
	return _certs, nil
}

// HttpClient provides HTTP client
func HttpClient() *http.Client {
	if Auth == false {
		return &http.Client{}
	}
	// get X509 certs
	certs, err := tlsCerts()
	if err != nil {
		panic(err.Error())
	}
	if len(certs) == 0 {
		return &http.Client{}
	}
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{Certificates: certs,
			InsecureSkipVerify: true},
	}
	return &http.Client{Transport: tr}
}

// String provides string representation for ResponseType
func (r *ResponseType) String() string {
	return fmt.Sprintf("<Response: url=%s data=%s error=%v>", r.Url, string(r.Data), r.Error)
}

// FetchResponse fetches data for provided URL, args is a json dump of arguments
func FetchResponse(rurl string, args []byte) ResponseType {
	startTime := time.Now()
	var response ResponseType
	response.Url = rurl
	if validateUrl(rurl) == false {
		response.Error = errors.New("Invalid URL")
		return response
	}
	var req *http.Request
	var e error
	if len(args) > 0 {
		req, e = http.NewRequest("POST", rurl, bytes.NewBuffer(args))
		req.Header.Set("Content-Type", "application/json")
	} else {
		req, e = http.NewRequest("GET", rurl, nil)
		if e != nil {
			log.WithFields(log.Fields{
				"Error": e,
			}).Error("Unable to make GET request")
		}
		req.Header.Add("Accept", "*/*")
	}
	if VERBOSE > 1 {
		dump1, err1 := httputil.DumpRequestOut(req, true)
		log.WithFields(log.Fields{
			"Request": req,
			"Dump":    string(dump1),
			"Error":   err1,
		}).Println("HTTP request")
	}
	resp, err := _client.Do(req)
	if err != nil {
		log.WithFields(log.Fields{
			"Error": err,
		}).Error("HTTP", err)
		response.Error = err
		return response
	}
	response.Status = resp.Status
	response.StatusCode = resp.StatusCode
	if VERBOSE > 0 {
		if len(args) > 0 {
			log.WithFields(log.Fields{
				"URL":   rurl,
				"Args":  string(args),
				"Error": err,
				"Time":  time.Now().Sub(startTime),
			}).Println("HTTP POST")
		} else {
			log.WithFields(log.Fields{
				"URL":   rurl,
				"Args":  string(args),
				"Error": err,
				"Time":  time.Now().Sub(startTime),
			}).Println("HTTP GET")
		}
	}
	if VERBOSE > 1 {
		dump2, err2 := httputil.DumpResponse(resp, true)
		log.WithFields(log.Fields{
			"Dump":  string(dump2),
			"Error": err2,
		}).Println("HTTP response")
	}
	if err != nil {
		response.Error = err
		return response
	}
	defer resp.Body.Close()
	response.Data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		response.Error = err
	}
	return response
}

// Fetch data for provided URL and redirect results to given channel
func Fetch(rurl string, args []byte, ch chan<- ResponseType) {
	urlRetry := 3
	var resp, r ResponseType
	resp = FetchResponse(rurl, args)
	if resp.Error != nil {
		log.WithFields(log.Fields{
			"URL":   rurl,
			"Error": resp.Error,
		}).Warn("Fail to fetch data")
		for i := 1; i <= urlRetry; i++ {
			sleep := time.Duration(i) * time.Second
			time.Sleep(sleep)
			r = FetchResponse(rurl, args)
			if r.Error == nil {
				break
			}
			log.WithFields(log.Fields{
				"URL":   rurl,
				"retry": i,
				"Error": r.Error,
			}).Warn("TRANSFER2GO")
		}
		resp = r
	}
	if resp.Error != nil {
		log.WithFields(log.Fields{
			"URL":   rurl,
			"Retry": urlRetry,
			"Error": resp.Error,
		}).Error("TRANSFER2GO, fail to fetch data")
	}
	ch <- resp
}

// Helper function which validates given URL
func validateUrl(rurl string) bool {
	if len(rurl) > 0 {
		if PatternUrl.MatchString(rurl) {
			return true
		}
		log.WithFields(log.Fields{
			"URL": rurl,
		}).Error("Invalid URL:", rurl)
	}
	return false
}

// Response represents final response in a form of JSON structure
// we use custorm representation
func Response(rurl string, data []byte) []byte {
	b := []byte(`{"url":`)
	u := []byte(rurl)
	c := []byte(",")
	d := []byte(`"data":`)
	e := []byte(`}`)
	a := [][]byte{b, u, c, d, data, e}
	s := []byte(" ")
	r := bytes.Join(a, s)
	return r

}
<commit_msg>Change log to logs<commit_after>package utils

// transfer2go/utils - Go utilities for transfer2go
//
// Author: Valentin Kuznetsov <vkuznet@gmail.com>

import (
	"bytes"
	"crypto/tls"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"os"
	"os/user"
	"time"

	logs "github.com/sirupsen/logrus"
	"github.com/vkuznet/x509proxy"
)

// ResponseType structure is what we expect to get for our URL call.
// It contains a request URL, the data chunk and possible error from remote
type ResponseType struct {
	Url        string // response url
	Data       []byte // response data, i.e. what we got with Body of the response
	Error      error  // http error, a non-2xx return code is not an error
	Status     string // http status string
	StatusCode int    // http status code
}

// UrlRequest structure holds details about url request's attributes
type UrlRequest struct {
	rurl string
	args string
	out  chan<- ResponseType
	ts   int64
}

// VERBOSE variable control verbosity level of client's utilities
var VERBOSE int

// variable to neglect auth layer
var Auth bool

// global HTTP client
var _client = HttpClient()

// global client's x509 certificates
var _certs []tls.Certificate

// UserDN function parses user Distinguished Name (DN) from client's HTTP request
func UserDN(r *http.Request) string {
	var names []interface{}
	for _, cert := range r.TLS.PeerCertificates {
		for _, name := range cert.Subject.Names {
			switch v := name.Value.(type) {
			case string:
				names = append(names, v)
			}
		}
	}
	parts := names[:7]
	return fmt.Sprintf("/DC=%s/DC=%s/OU=%s/OU=%s/CN=%s/CN=%s/CN=%s", parts...)
}

// client X509 certificates
func tlsCerts() ([]tls.Certificate, error) {
	if len(_certs) != 0 {
		return _certs, nil // use cached certs
	}
	uproxy := os.Getenv("X509_USER_PROXY")
	uckey := os.Getenv("X509_USER_KEY")
	ucert := os.Getenv("X509_USER_CERT")

	// check if /tmp/x509up_u$UID exists, if so setup X509_USER_PROXY env
	u, err := user.Current()
	if err == nil {
		fname := fmt.Sprintf("/tmp/x509up_u%s", u.Uid)
		if _, err := os.Stat(fname); err == nil {
			uproxy = fname
		}
	}
	if VERBOSE > 1 {
		logs.WithFields(logs.Fields{
			"uproxy": uproxy,
		}).Println("")
		logs.WithFields(logs.Fields{
			"uckey": uckey,
		}).Println("")
		logs.WithFields(logs.Fields{
			"ucert": ucert,
		}).Println("")
	}

	if uproxy == "" && uckey == "" { // user doesn't have neither proxy or user certs
		logs.Warn("Neither proxy or user certs are found, to proceed use auth=false option otherwise setup X509 environment")
		return nil, nil
	}
	if uproxy != "" {
		// use local implementation of LoadX409KeyPair instead of tls one
		x509cert, err := x509proxy.LoadX509Proxy(uproxy)
		if err != nil {
			return nil, fmt.Errorf("failed to parse proxy X509 proxy set by X509_USER_PROXY: %v", err)
		}
		_certs = []tls.Certificate{x509cert}
		return _certs, nil
	}
	x509cert, err := tls.LoadX509KeyPair(ucert, uckey)
	if err != nil {
		return nil, fmt.Errorf("failed to parse user X509 certificate: %v", err)
	}
	_certs = []tls.Certificate{x509cert}
	return _certs, nil
}

// HttpClient provides HTTP client
func HttpClient() *http.Client {
	if Auth == false {
		return &http.Client{}
	}
	// get X509 certs
	certs, err := tlsCerts()
	if err != nil {
		panic(err.Error())
	}
	if len(certs) == 0 {
		return &http.Client{}
	}
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{Certificates: certs,
			InsecureSkipVerify: true},
	}
	return &http.Client{Transport: tr}
}

// String provides string representation for ResponseType
func (r *ResponseType) String() string {
	return fmt.Sprintf("<Response: url=%s data=%s error=%v>", r.Url, string(r.Data), r.Error)
}

// FetchResponse fetches data for provided URL, args is a json dump of arguments
func FetchResponse(rurl string, args []byte) ResponseType {
	startTime := time.Now()
	var response ResponseType
	response.Url = rurl
	if validateUrl(rurl) == false {
		response.Error = errors.New("Invalid URL")
		return response
	}
	var req *http.Request
	var e error
	if len(args) > 0 {
		req, e = http.NewRequest("POST", rurl, bytes.NewBuffer(args))
		req.Header.Set("Content-Type", "application/json")
	} else {
		req, e = http.NewRequest("GET", rurl, nil)
		if e != nil {
			logs.WithFields(logs.Fields{
				"Error": e,
			}).Error("Unable to make GET request")
		}
		req.Header.Add("Accept", "*/*")
	}
	if VERBOSE > 1 {
		dump1, err1 := httputil.DumpRequestOut(req, true)
		logs.WithFields(logs.Fields{
			"Request": req,
			"Dump":    string(dump1),
			"Error":   err1,
		}).Println("HTTP request")
	}
	resp, err := _client.Do(req)
	if err != nil {
		logs.WithFields(logs.Fields{
			"Error": err,
		}).Error("HTTP", err)
		response.Error = err
		return response
	}
	response.Status = resp.Status
	response.StatusCode = resp.StatusCode
	if VERBOSE > 0 {
		if len(args) > 0 {
			logs.WithFields(logs.Fields{
				"URL":   rurl,
				"Args":  string(args),
				"Error": err,
				"Time":  time.Now().Sub(startTime),
			}).Println("HTTP POST")
		} else {
			logs.WithFields(logs.Fields{
				"URL":   rurl,
				"Args":  string(args),
				"Error": err,
				"Time":  time.Now().Sub(startTime),
			}).Println("HTTP GET")
		}
	}
	if VERBOSE > 1 {
		dump2, err2 := httputil.DumpResponse(resp, true)
		logs.WithFields(logs.Fields{
			"Dump":  string(dump2),
			"Error": err2,
		}).Println("HTTP response")
	}
	if err != nil {
		response.Error = err
		return response
	}
	defer resp.Body.Close()
	response.Data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		response.Error = err
	}
	return response
}

// Fetch data for provided URL and redirect results to given channel
func Fetch(rurl string, args []byte, ch chan<- ResponseType) {
	urlRetry := 3
	var resp, r ResponseType
	resp = FetchResponse(rurl, args)
	if resp.Error != nil {
		logs.WithFields(logs.Fields{
			"URL":   rurl,
			"Error": resp.Error,
		}).Warn("Fail to fetch data")
		for i := 1; i <= urlRetry; i++ {
			sleep := time.Duration(i) * time.Second
			time.Sleep(sleep)
			r = FetchResponse(rurl, args)
			if r.Error == nil {
				break
			}
			logs.WithFields(logs.Fields{
				"URL":   rurl,
				"retry": i,
				"Error": r.Error,
			}).Warn("TRANSFER2GO")
		}
		resp = r
	}
	if resp.Error != nil {
		logs.WithFields(logs.Fields{
			"URL":   rurl,
			"Retry": urlRetry,
			"Error": resp.Error,
		}).Error("TRANSFER2GO, fail to fetch data")
	}
	ch <- resp
}

// Helper function which validates given URL
func validateUrl(rurl string) bool {
	if len(rurl) > 0 {
		if PatternUrl.MatchString(rurl) {
			return true
		}
		logs.WithFields(logs.Fields{
			"URL": rurl,
		}).Error("Invalid URL:", rurl)
	}
	return false
}

// Response represents final response in a form of JSON structure
// we use custorm representation
func Response(rurl string, data []byte) []byte {
	b := []byte(`{"url":`)
	u := []byte(rurl)
	c := []byte(",")
	d := []byte(`"data":`)
	e := []byte(`}`)
	a := [][]byte{b, u, c, d, data, e}
	s := []byte(" ")
	r := bytes.Join(a, s)
	return r

}
<|endoftext|>