<commit_before>package main

import (
	"flag"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"context"
)

const retryDelay = 500 * time.Millisecond

type Resource interface {
	fmt.Stringer
	Await(context.Context) error
}

type unavailableError struct {
	Reason error
}

// Error implements the error interface.
func (e *unavailableError) Error() string {
	return e.Reason.Error()
}

func main() {
	var (
		forceFlag   = flag.Bool("f", false, "Force running the command even after giving up")
		timeoutFlag = flag.Duration("t", 1*time.Minute, "Timeout duration before giving up")
		verboseFlag = flag.Bool("v", false, "Set verbose output")
		quietFlag   = flag.Bool("q", false, "Set quiet mode")
	)
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: await [options...] <res>... [ -- <cmd>]")
		fmt.Fprintln(os.Stderr, "Await availability of resources.")
		fmt.Fprintln(os.Stderr)
		flag.PrintDefaults()
	}
	flag.Parse()

	logLevel := errorLevel
	switch {
	case *quietFlag:
		logLevel = silentLevel
	case *verboseFlag:
		logLevel = infoLevel
	}
	log := NewLogger(logLevel)

	resArgs, cmdArgs := splitArgs(flag.Args())
	ress, err := parseResources(resArgs)
	if err != nil {
		log.Fatalln("Error: failed to parse resources: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), *timeoutFlag)
	go func() {
		for i := 0; i < len(ress); {
			select {
			case <-ctx.Done(): // Exceeded timeout
				return
			default:
				res, err := identifyResource(ress[i])
				if err != nil { // Permanent error
					log.Fatalf("Error: %v", err)
				}

				log.Infof("Awaiting resource: %s", res)
				if err := res.Await(ctx); err != nil {
					if e, ok := err.(*unavailableError); ok { // transient error
						log.Infof("Resource unavailable: %v", e)
					} else { // Maybe transient error
						log.Errorf("Error: failed to await resource: %v", err)
					}
					time.Sleep(retryDelay)
				} else {
					i++ // Next resource
				}
			}
		}

		cancel() // All resources are available
	}()

	switch <-ctx.Done(); ctx.Err() {
	case context.Canceled:
		log.Infoln("All resources available")
	case context.DeadlineExceeded:
		log.Infoln("Timeout exceeded")
		if !*forceFlag {
			os.Exit(1)
		}
	}

	if len(cmdArgs) > 0 {
		log.Infof("Runnning command: %v", cmdArgs)
		if err := execCmd(cmdArgs); err != nil {
			log.Fatalf("Error: failed to execute command: %v", err)
		}
	}
}

func splitArgs(args []string) ([]string, []string) {
	for i, a := range args {
		if a == "--" {
			return args[0:i], args[i+1:]
		}
	}
	return args, []string{}
}

func parseResources(urlArgs []string) ([]url.URL, error) {
	var urls []url.URL
	for _, urlArg := range urlArgs {
		// Leveraging the fact the Go's URL parser matches e.g. `curl -s
		// http://example.com` as url.Path instead of throwing an error.
		u, err := url.Parse(urlArg)
		if err != nil {
			return urls, err
		}
		urls = append(urls, *u)
	}
	return urls, nil
}

func identifyResource(u url.URL) (Resource, error) {
	switch u.Scheme {
	case "http", "https":
		return &httpResource{u}, nil
	case "ws", "wss":
		return &websocketResource{u}, nil
	case "tcp", "tcp4", "tcp6":
		return &tcpResource{u}, nil
	case "file":
		return &fileResource{u}, nil
	case "postgres":
		return &postgresqlResource{u}, nil
	case "mysql":
		return &mysqlResource{u}, nil
	case "":
		return &commandResource{u}, nil
	default:
		return nil, fmt.Errorf("unsupported resource scheme: %v", u.Scheme)
	}
}

func execCmd(cmdArgs []string) error {
	path, err := exec.LookPath(cmdArgs[0])
	if err != nil {
		return err
	}
	return syscall.Exec(path, cmdArgs, os.Environ())
}

func parseTags(tag string) map[string]string {
	tags := map[string]string{}
	tagParts := strings.Split(tag, ",")
	for _, t := range tagParts {
		kv := strings.SplitN(t, "=", 2)
		k := kv[0]
		if len(kv) == 1 {
			tags[k] = ""
		} else {
			tags[k] = kv[1]
		}
	}
	return tags
}
<commit_msg>Unexport resource type<commit_after>package main

import (
	"flag"
	"fmt"
	"net/url"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"time"

	"context"
)

const retryDelay = 500 * time.Millisecond

type resource interface {
	fmt.Stringer
	Await(context.Context) error
}

type unavailableError struct {
	Reason error
}

// Error implements the error interface.
func (e *unavailableError) Error() string {
	return e.Reason.Error()
}

func main() {
	var (
		forceFlag   = flag.Bool("f", false, "Force running the command even after giving up")
		timeoutFlag = flag.Duration("t", 1*time.Minute, "Timeout duration before giving up")
		verboseFlag = flag.Bool("v", false, "Set verbose output")
		quietFlag   = flag.Bool("q", false, "Set quiet mode")
	)
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage: await [options...] <res>... [ -- <cmd>]")
		fmt.Fprintln(os.Stderr, "Await availability of resources.")
		fmt.Fprintln(os.Stderr)
		flag.PrintDefaults()
	}
	flag.Parse()

	logLevel := errorLevel
	switch {
	case *quietFlag:
		logLevel = silentLevel
	case *verboseFlag:
		logLevel = infoLevel
	}
	log := NewLogger(logLevel)

	resArgs, cmdArgs := splitArgs(flag.Args())
	ress, err := parseResources(resArgs)
	if err != nil {
		log.Fatalln("Error: failed to parse resources: %v", err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), *timeoutFlag)
	go func() {
		for i := 0; i < len(ress); {
			select {
			case <-ctx.Done(): // Exceeded timeout
				return
			default:
				res, err := identifyResource(ress[i])
				if err != nil { // Permanent error
					log.Fatalf("Error: %v", err)
				}

				log.Infof("Awaiting resource: %s", res)
				if err := res.Await(ctx); err != nil {
					if e, ok := err.(*unavailableError); ok { // transient error
						log.Infof("Resource unavailable: %v", e)
					} else { // Maybe transient error
						log.Errorf("Error: failed to await resource: %v", err)
					}
					time.Sleep(retryDelay)
				} else {
					i++ // Next resource
				}
			}
		}

		cancel() // All resources are available
	}()

	switch <-ctx.Done(); ctx.Err() {
	case context.Canceled:
		log.Infoln("All resources available")
	case context.DeadlineExceeded:
		log.Infoln("Timeout exceeded")
		if !*forceFlag {
			os.Exit(1)
		}
	}

	if len(cmdArgs) > 0 {
		log.Infof("Runnning command: %v", cmdArgs)
		if err := execCmd(cmdArgs); err != nil {
			log.Fatalf("Error: failed to execute command: %v", err)
		}
	}
}

func splitArgs(args []string) ([]string, []string) {
	for i, a := range args {
		if a == "--" {
			return args[0:i], args[i+1:]
		}
	}
	return args, []string{}
}

func parseResources(urlArgs []string) ([]url.URL, error) {
	var urls []url.URL
	for _, urlArg := range urlArgs {
		// Leveraging the fact the Go's URL parser matches e.g. `curl -s
		// http://example.com` as url.Path instead of throwing an error.
		u, err := url.Parse(urlArg)
		if err != nil {
			return urls, err
		}
		urls = append(urls, *u)
	}
	return urls, nil
}

func identifyResource(u url.URL) (resource, error) {
	switch u.Scheme {
	case "http", "https":
		return &httpResource{u}, nil
	case "ws", "wss":
		return &websocketResource{u}, nil
	case "tcp", "tcp4", "tcp6":
		return &tcpResource{u}, nil
	case "file":
		return &fileResource{u}, nil
	case "postgres":
		return &postgresqlResource{u}, nil
	case "mysql":
		return &mysqlResource{u}, nil
	case "":
		return &commandResource{u}, nil
	default:
		return nil, fmt.Errorf("unsupported resource scheme: %v", u.Scheme)
	}
}

func execCmd(cmdArgs []string) error {
	path, err := exec.LookPath(cmdArgs[0])
	if err != nil {
		return err
	}
	return syscall.Exec(path, cmdArgs, os.Environ())
}

func parseTags(tag string) map[string]string {
	tags := map[string]string{}
	tagParts := strings.Split(tag, ",")
	for _, t := range tagParts {
		kv := strings.SplitN(t, "=", 2)
		k := kv[0]
		if len(kv) == 1 {
			tags[k] = ""
		} else {
			tags[k] = kv[1]
		}
	}
	return tags
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"os"
	"unicode/utf8"
)

const (
	unknownFormat uint = iota
	jsonFormat
	xmlFormat
)

func main() {
	if err := pretty(os.Stdin, os.Stdout); err != nil {
		log.Fatal(err)
	}
}

func pretty(r io.Reader, w io.Writer) error {

	buf := bufio.NewReaderSize(r, 4)

	var format uint
	for {

		ch, _, err := buf.ReadRune()
		if err != nil {
			return err
		}

		if f, ok := formats(ch); ok {
			format = f
			if err := buf.UnreadRune(); err != nil {
				return err
			}
			break
		}

		if endOfLine(ch) {
			return errors.New("unable to recognize this format")
		}
	}

	b, err := ioutil.ReadAll(buf)
	if err != nil {
		return err
	}

	switch format {
	case jsonFormat:
		var out *bytes.Buffer
		if err := json.Indent(out, b, "", "\t"); err != nil {
			return err
		}
		if _, err := out.WriteTo(w); err != nil {
			return err
		}
	case xmlFormat:
		d := xml.NewDecoder(bytes.NewReader(b))
		e := xml.NewEncoder(w)
		e.Indent("", "\t")
		for {
			t, err := d.Token()
			if err == io.EOF {
				break
			}
			if tok, ok := t.(xml.CharData); ok {
				r, _ := utf8.DecodeRune(tok)
				if whitespace(r) {
					continue
				}
			}
			e.EncodeToken(t)
		}
		return e.Flush()
	default:
		return errors.New("known format error, please file a bug")
	}
	return nil
}

func endOfLine(ch rune) bool {
	return ch == '\n' || ch == '\r'
}

func formats(ch rune) (uint, bool) {
	switch ch {
	case '{':
		return jsonFormat, true
	case '<':
		return xmlFormat, true
	default:
		return unknownFormat, false
	}
}

func whitespace(ch rune) bool {
	return ch == ' ' || ch == '\n' || ch == '\t'
}
<commit_msg>renaming whitespace to blank<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"io/ioutil"
	"log"
	"os"
	"unicode/utf8"
)

const (
	unknownFormat uint = iota
	jsonFormat
	xmlFormat
)

func main() {
	if err := pretty(os.Stdin, os.Stdout); err != nil {
		log.Fatal(err)
	}
}

func pretty(r io.Reader, w io.Writer) error {

	buf := bufio.NewReaderSize(r, 4)

	var format uint
	for {
		ch, _, err := buf.ReadRune()
		if err != nil {
			return err
		}

		if f, ok := formats(ch); ok {
			format = f
			if err := buf.UnreadRune(); err != nil {
				return err
			}
			break
		}

		if endOfLine(ch) {
			return errors.New("unable to recognize this format")
		}
	}

	b, err := ioutil.ReadAll(buf)
	if err != nil {
		return err
	}

	switch format {
	case jsonFormat:
		var out *bytes.Buffer
		if err := json.Indent(out, b, "", "\t"); err != nil {
			return err
		}
		if _, err := out.WriteTo(w); err != nil {
			return err
		}
	case xmlFormat:
		d := xml.NewDecoder(bytes.NewReader(b))
		e := xml.NewEncoder(w)
		e.Indent("", "\t")

		for {
			t, err := d.Token()
			if err == io.EOF {
				break
			}
			if tok, ok := t.(xml.CharData); ok {
				r, _ := utf8.DecodeRune(tok)
				if blank(r) {
					continue
				}
			}
			e.EncodeToken(t)
		}
		return e.Flush()
	default:
		return errors.New("known format error, please file a bug")
	}
	return nil
}

func endOfLine(ch rune) bool {
	return ch == '\n' || ch == '\r'
}

func formats(ch rune) (uint, bool) {
	switch ch {
	case '{':
		return jsonFormat, true
	case '<':
		return xmlFormat, true
	default:
		return unknownFormat, false
	}
}

func blank(ch rune) bool {
	return ch == ' ' || ch == '\n' || ch == '\t'
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"time"

	"os"

	"github.com/42wim/ipisp"
	"github.com/dustin/go-humanize"
	"github.com/miekg/dns"
	"text/tabwriter"
)

var (
	resolver = "8.8.8.8:53"
)

type NSInfo struct {
	Name string
	IP   []net.IP
}

type IPInfo struct {
	Loc string
	ASN ipisp.ASN
	ISP string
}

func ipinfo(ip net.IP) (IPInfo, error) {
	client, _ := ipisp.NewDNSClient()
	resp, err := client.LookupIP(net.ParseIP(ip.String()))
	if err != nil {
		return IPInfo{}, err
	}
	return IPInfo{resp.Country, resp.ASN, resp.Name.Raw}, nil
}

func typeSOA(q string, server string) (time.Duration, *dns.SOA) {
	c := new(dns.Client)
	m := prepMsg()
	m.Question[0] = dns.Question{q + ".", dns.TypeSOA, dns.ClassINET}
	in, rtt, err := c.Exchange(m, net.JoinHostPort(server, "53"))
	if err != nil {
		return 0, new(dns.SOA)
	}
	return rtt, in.Answer[0].(*dns.SOA)
}

func getIP(host string, qtype uint16) []net.IP {
	var ips []net.IP
	c := new(dns.Client)
	m := prepMsg()
	m.Question[0] = dns.Question{host, qtype, dns.ClassINET}
	in, _, err := c.Exchange(m, resolver)
	if err != nil {
		return ips
	}
	for _, a := range in.Answer {
		switch a.(type) {
		case *dns.A:
			ips = append(ips, a.(*dns.A).A)
		case *dns.AAAA:
			ips = append(ips, a.(*dns.AAAA).AAAA)
		}
	}
	return ips
}

func typeA(host string) []net.IP {
	return getIP(host, dns.TypeA)
}

func typeAAAA(host string) []net.IP {
	return getIP(host, dns.TypeAAAA)
}

func typeDNSKEY(q string, server string) (bool, int64, int64) {
	c := new(dns.Client)
	m := prepMsg()
	m.SetEdns0(4096, true)
	m.Question[0] = dns.Question{q + ".", dns.TypeDNSKEY, dns.ClassINET}
	in, _, _ := c.Exchange(m, net.JoinHostPort(server, "53"))
	keys := []*dns.DNSKEY{}
	for _, a := range in.Answer {
		switch a.(type) {
		case *dns.DNSKEY:
			keys = append(keys, a.(*dns.DNSKEY))
		}
	}

	// ask dnssec
	m = prepMsg()
	m.SetEdns0(4096, true)
	m.Question[0] = dns.Question{q + ".", dns.TypeNS, dns.ClassINET}
	in, _, _ = c.Exchange(m, net.JoinHostPort(server, "53"))
	return validateRR(keys, in.Answer)
}

func validateRR(keys []*dns.DNSKEY, rrset []dns.RR) (bool, int64, int64) {
	if len(rrset) == 0 {
		return false, 0, 0
	}
	var sig *dns.RRSIG
	var cleanset []dns.RR
	for _, v := range rrset {
		_, ok := v.(*dns.RRSIG)
		if ok {
			sig = v.(*dns.RRSIG)
		} else {
			cleanset = append(cleanset, v)
		}
	}
	for _, key := range keys {
		// zone signing key
		if key.Flags == 256 {
			err := sig.Verify(key, cleanset)
			if err == nil {
				ti, te := explicitValid(sig)
				if sig.ValidityPeriod(time.Now()) {
					return true, ti, te
				}
				return false, ti, te
			}
		}
	}
	return false, 0, 0
}

func explicitValid(rr *dns.RRSIG) (int64, int64) {
	t := time.Now()
	var utc int64
	var year68 = int64(1 << 31)
	if t.IsZero() {
		utc = time.Now().UTC().Unix()
	} else {
		utc = t.UTC().Unix()
	}
	modi := (int64(rr.Inception) - utc) / year68
	mode := (int64(rr.Expiration) - utc) / year68
	ti := int64(rr.Inception) + (modi * year68)
	te := int64(rr.Expiration) + (mode * year68)
	return ti, te
}

func findNS(domain string) []NSInfo {
	c := new(dns.Client)
	m := prepMsg()
	m.Question[0] = dns.Question{domain, dns.TypeNS, dns.ClassINET}
	in, _, _ := c.Exchange(m, resolver)
	var ips []net.IP
	var nsinfos []NSInfo
	for _, a := range in.Answer {
		nsinfo := NSInfo{}
		nsinfo.Name = a.(*dns.NS).Ns
		ips = append(ips, typeA(a.(*dns.NS).Ns)...)
		ips = append(ips, typeAAAA(a.(*dns.NS).Ns)...)
		nsinfo.IP = ips
		nsinfos = append(nsinfos, nsinfo)
		ips = []net.IP{}
	}
	return nsinfos
}

func prepMsg() *dns.Msg {
	m := new(dns.Msg)
	m.Id = dns.Id()
	m.RecursionDesired = true
	m.Question = make([]dns.Question, 1)
	return m
}

func main() {
	if len(os.Args) == 1 {
		fmt.Println("please enter a domain. (e.g. google.com)")
		return
	}
	domain := os.Args[1]
	nsinfos := findNS(dns.Fqdn(domain))
	if len(nsinfos) == 0 {
		fmt.Println("no nameservers found for", domain)
		return
	}
	const padding = 1
	w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, ' ', tabwriter.Debug)
	fmt.Fprintf(w, "NS\tIP\tLOC\tASN\tISP\trtt\tSerial\tDNSSEC\tValidFrom\tValidUntil\n")
	for _, nsinfo := range nsinfos {
		fmt.Fprintf(w, "%s\t", nsinfo.Name)
		i := 0
		for _, ip := range nsinfo.IP {
			info, _ := ipinfo(ip)
			if i > 0 {
				fmt.Fprintf(w, "\t%s\t", ip.String())
			} else {
				fmt.Fprintf(w, "%s\t", ip.String())
			}
			fmt.Fprintf(w, "%v\tASN %#v\t%v\t", info.Loc, info.ASN, fmt.Sprintf("%.40s", info.ISP))
			rtt, soa := typeSOA(domain, ip.String())
			valid, ti, te := typeDNSKEY(domain, ip.String())
			fmt.Fprintf(w, "%s\t%v\t", rtt.String(), int64(soa.Serial))
			if valid {
				fmt.Fprintf(w, "%v\t%s\t%s", valid, humanize.Time(time.Unix(ti, 0)), humanize.Time(time.Unix(te, 0)))
			} else {
				fmt.Fprintf(w, "%v\t%s\t%s", valid, "", "")
			}
			fmt.Fprintln(w)
			i++
		}
	}
	w.Flush()
	fmt.Println()
}
<commit_msg>Improve error handling<commit_after>package main

import (
	"fmt"
	"net"
	"time"

	"os"

	"github.com/42wim/ipisp"
	"github.com/dustin/go-humanize"
	"github.com/miekg/dns"
	"text/tabwriter"
)

var (
	resolver = "8.8.8.8:53"
)

type NSInfo struct {
	Name string
	IP   []net.IP
}

type IPInfo struct {
	Loc string
	ASN ipisp.ASN
	ISP string
}

type KeyInfo struct {
	Start int64
	End   int64
}

func ipinfo(ip net.IP) (IPInfo, error) {
	client, _ := ipisp.NewDNSClient()
	resp, err := client.LookupIP(net.ParseIP(ip.String()))
	if err != nil {
		return IPInfo{}, err
	}
	return IPInfo{resp.Country, resp.ASN, resp.Name.Raw}, nil
}

func typeSOA(q string, server string) (time.Duration, *dns.SOA, error) {
	c := new(dns.Client)
	m := prepMsg()
	m.Question[0] = dns.Question{q + ".", dns.TypeSOA, dns.ClassINET}
	in, rtt, err := c.Exchange(m, net.JoinHostPort(server, "53"))
	if err != nil {
		return 0, new(dns.SOA), err
	}
	return rtt, in.Answer[0].(*dns.SOA), nil
}

func getIP(host string, qtype uint16) []net.IP {
	var ips []net.IP
	c := new(dns.Client)
	m := prepMsg()
	m.Question[0] = dns.Question{host, qtype, dns.ClassINET}
	in, _, err := c.Exchange(m, resolver)
	if err != nil {
		return ips
	}
	for _, a := range in.Answer {
		switch a.(type) {
		case *dns.A:
			ips = append(ips, a.(*dns.A).A)
		case *dns.AAAA:
			ips = append(ips, a.(*dns.AAAA).AAAA)
		}
	}
	return ips
}

func typeA(host string) []net.IP {
	return getIP(host, dns.TypeA)
}

func typeAAAA(host string) []net.IP {
	return getIP(host, dns.TypeAAAA)
}

func typeDNSKEY(q string, server string) (bool, KeyInfo, error) {
	c := new(dns.Client)
	m := prepMsg()
	m.SetEdns0(4096, true)
	m.Question[0] = dns.Question{q + ".", dns.TypeDNSKEY, dns.ClassINET}
	in, _, err := c.Exchange(m, net.JoinHostPort(server, "53"))
	if err != nil {
		return false, KeyInfo{}, err
	}
	keys := []*dns.DNSKEY{}
	for _, a := range in.Answer {
		switch a.(type) {
		case *dns.DNSKEY:
			keys = append(keys, a.(*dns.DNSKEY))
		}
	}

	// ask dnssec
	m = prepMsg()
	m.SetEdns0(4096, true)
	m.Question[0] = dns.Question{q + ".", dns.TypeNS, dns.ClassINET}
	in, _, err = c.Exchange(m, net.JoinHostPort(server, "53"))
	if err != nil {
		return false, KeyInfo{}, err
	}
	return validateRR(keys, in.Answer)
}

func validateRR(keys []*dns.DNSKEY, rrset []dns.RR) (bool, KeyInfo, error) {
	if len(rrset) == 0 {
		return false, KeyInfo{}, nil
	}
	var sig *dns.RRSIG
	var cleanset []dns.RR
	for _, v := range rrset {
		_, ok := v.(*dns.RRSIG)
		if ok {
			sig = v.(*dns.RRSIG)
		} else {
			cleanset = append(cleanset, v)
		}
	}
	for _, key := range keys {
		// zone signing key
		if key.Flags == 256 {
			err := sig.Verify(key, cleanset)
			if err == nil {
				ti, te := explicitValid(sig)
				if sig.ValidityPeriod(time.Now()) {
					return true, KeyInfo{ti, te}, nil
				}
				return false, KeyInfo{ti, te}, nil
			}
		}
	}
	return false, KeyInfo{}, nil
}

func explicitValid(rr *dns.RRSIG) (int64, int64) {
	t := time.Now()
	var utc int64
	var year68 = int64(1 << 31)
	if t.IsZero() {
		utc = time.Now().UTC().Unix()
	} else {
		utc = t.UTC().Unix()
	}
	modi := (int64(rr.Inception) - utc) / year68
	mode := (int64(rr.Expiration) - utc) / year68
	ti := int64(rr.Inception) + (modi * year68)
	te := int64(rr.Expiration) + (mode * year68)
	return ti, te
}

func findNS(domain string) []NSInfo {
	c := new(dns.Client)
	m := prepMsg()
	m.Question[0] = dns.Question{domain, dns.TypeNS, dns.ClassINET}
	in, _, _ := c.Exchange(m, resolver)
	var ips []net.IP
	var nsinfos []NSInfo
	for _, a := range in.Answer {
		nsinfo := NSInfo{}
		nsinfo.Name = a.(*dns.NS).Ns
		ips = append(ips, typeA(a.(*dns.NS).Ns)...)
		ips = append(ips, typeAAAA(a.(*dns.NS).Ns)...)
		nsinfo.IP = ips
		nsinfos = append(nsinfos, nsinfo)
		ips = []net.IP{}
	}
	return nsinfos
}

func prepMsg() *dns.Msg {
	m := new(dns.Msg)
	m.Id = dns.Id()
	m.RecursionDesired = true
	m.Question = make([]dns.Question, 1)
	return m
}

func main() {
	if len(os.Args) == 1 {
		fmt.Println("please enter a domain. (e.g. google.com)")
		return
	}
	domain := os.Args[1]
	nsinfos := findNS(dns.Fqdn(domain))
	if len(nsinfos) == 0 {
		fmt.Println("no nameservers found for", domain)
		return
	}
	const padding = 1
	w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, ' ', tabwriter.Debug)
	fmt.Fprintf(w, "NS\tIP\tLOC\tASN\tISP\trtt\tSerial\tDNSSEC\tValidFrom\tValidUntil\n")
	for _, nsinfo := range nsinfos {
		fmt.Fprintf(w, "%s\t", nsinfo.Name)
		i := 0
		for _, ip := range nsinfo.IP {
			info, _ := ipinfo(ip)
			if i > 0 {
				fmt.Fprintf(w, "\t%s\t", ip.String())
			} else {
				fmt.Fprintf(w, "%s\t", ip.String())
			}
			fmt.Fprintf(w, "%v\tASN %#v\t%v\t", info.Loc, info.ASN, fmt.Sprintf("%.40s", info.ISP))
			rtt, soa, err := typeSOA(domain, ip.String())
			if err != nil {
				fmt.Fprintf(w, "%s\t%v\t", "error", "error")
			} else {
				fmt.Fprintf(w, "%s\t%v\t", rtt.String(), int64(soa.Serial))
			}
			valid, keyinfo, err := typeDNSKEY(domain, ip.String())
			if valid {
				fmt.Fprintf(w, "%v\t%s\t%s", "valid", humanize.Time(time.Unix(keyinfo.Start, 0)), humanize.Time(time.Unix(keyinfo.End, 0)))
			} else {
				if err != nil {
					fmt.Fprintf(w, "%v\t%s\t%s", "error", "", "")
				} else {
					fmt.Fprintf(w, "%v\t%s\t%s", "invalid", "", "")
				}
			}
			fmt.Fprintln(w)
			i++
		}
	}
	w.Flush()
	fmt.Println()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/representative/scheduler"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/cloudfoundry/storeadapter/etcdstoreadapter"
	"github.com/cloudfoundry/storeadapter/workerpool"
)

var etcdCluster = flag.String(
	"etcdCluster",
	"http://127.0.0.1:4001",
	"comma-separated list of etcd addresses (http://ip:port)",
)

var logLevel = flag.String(
	"logLevel",
	"info",
	"the logging level (none, fatal, error, warn, info, debug, debug1, debug2, all)",
)

var syslogName = flag.String(
	"syslogName",
	"",
	"syslog name",
)

var executorURL = flag.String(
	"executorURL",
	"http://120.0.0.1:1700",
	"location of executor to represent",
)

var schedulerAddress = flag.String(
	"schedulerAddress",
	"0.0.0.0:20515",
	"host:port to listen on for job completion",
)

func main() {
	flag.Parse()

	l, err := steno.GetLogLevel(*logLevel)
	if err != nil {
		log.Fatalf("Invalid loglevel: %s\n", *logLevel)
	}

	stenoConfig := steno.Config{
		Level: l,
		Sinks: []steno.Sink{steno.NewIOSink(os.Stdout)},
	}

	if *syslogName != "" {
		stenoConfig.Sinks = append(stenoConfig.Sinks, steno.NewSyslogSink(*syslogName))
	}

	steno.Init(&stenoConfig)
	logger := steno.NewLogger("representative")

	etcdAdapter := etcdstoreadapter.NewETCDStoreAdapter(
		strings.Split(*etcdCluster, ","),
		workerpool.NewWorkerPool(10),
	)

	bbs := Bbs.New(etcdAdapter, timeprovider.NewTimeProvider())
	err = etcdAdapter.Connect()
	if err != nil {
		logger.Errord(map[string]interface{}{
			"error": err,
		}, "representative.etcd-connect.failed")
		os.Exit(1)
	}

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)

	ready := make(chan struct{})

	rep := scheduler.New(bbs, logger, *schedulerAddress, *executorURL)

	go func() {
		<-ready
		fmt.Println("representative started")
	}()

	err = rep.Run(signals, ready)
	if err != nil {
		logger.Errord(map[string]interface{}{
			"error": err,
		}, "representative.run.failed")
		os.Exit(1)
	}
}
<commit_msg>change a 0 to a 7<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/representative/scheduler"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/gunk/timeprovider"
	"github.com/cloudfoundry/storeadapter/etcdstoreadapter"
	"github.com/cloudfoundry/storeadapter/workerpool"
)

var etcdCluster = flag.String(
	"etcdCluster",
	"http://127.0.0.1:4001",
	"comma-separated list of etcd addresses (http://ip:port)",
)

var logLevel = flag.String(
	"logLevel",
	"info",
	"the logging level (none, fatal, error, warn, info, debug, debug1, debug2, all)",
)

var syslogName = flag.String(
	"syslogName",
	"",
	"syslog name",
)

var executorURL = flag.String(
	"executorURL",
	"http://127.0.0.1:1700",
	"location of executor to represent",
)

var schedulerAddress = flag.String(
	"schedulerAddress",
	"0.0.0.0:20515",
	"host:port to listen on for job completion",
)

func main() {
	flag.Parse()

	l, err := steno.GetLogLevel(*logLevel)
	if err != nil {
		log.Fatalf("Invalid loglevel: %s\n", *logLevel)
	}

	stenoConfig := steno.Config{
		Level: l,
		Sinks: []steno.Sink{steno.NewIOSink(os.Stdout)},
	}

	if *syslogName != "" {
		stenoConfig.Sinks = append(stenoConfig.Sinks, steno.NewSyslogSink(*syslogName))
	}

	steno.Init(&stenoConfig)
	logger := steno.NewLogger("representative")

	etcdAdapter := etcdstoreadapter.NewETCDStoreAdapter(
		strings.Split(*etcdCluster, ","),
		workerpool.NewWorkerPool(10),
	)

	bbs := Bbs.New(etcdAdapter, timeprovider.NewTimeProvider())
	err = etcdAdapter.Connect()
	if err != nil {
		logger.Errord(map[string]interface{}{
			"error": err,
		}, "representative.etcd-connect.failed")
		os.Exit(1)
	}

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)

	ready := make(chan struct{})

	rep := scheduler.New(bbs, logger, *schedulerAddress, *executorURL)

	go func() {
		<-ready
		fmt.Println("representative started")
	}()

	err = rep.Run(signals, ready)
	if err != nil {
		logger.Errord(map[string]interface{}{
			"error": err,
		}, "representative.run.failed")
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"

	"github.com/nchern/red/app"

	color "gopkg.in/fatih/color.v1"
)

const (
	jsonIndent = "   "

	filenameBase = "query"
)

var (
	editor      = env("EDITOR", "vim")
	editorFlags = env("EDITOR_FLAGS", "-O")

	appHomePath = path.Join(os.Getenv("HOME"), ".red")

	queryFilename = filenameBase + ".txt"
	outFilename   = filenameBase + ".out"

	queryFilePath = path.Join(appHomePath, queryFilename)
	outFilePath   = path.Join(appHomePath, outFilename)

	client = &http.Client{
		Timeout: 3 * time.Second,
	}

	flagCmd = flag.String("c", "edit", "Command to exectue. One of: edit, run, example")

	// opens the editor of preference to edit requests
	cmdEdit = "edit"

	// runs a given query, either from stdin or a query file(TODO: make it accept "-")
	cmdRun = "run"

	// prints out example of request file
	cmdExample = "example"
)

func openEditor() error {
	if _, err := os.Stat(queryFilePath); os.IsNotExist(err) {
		if err := os.MkdirAll(appHomePath, 0700); err != nil {
			return err
		}
		// path/to/whatever does not exist
		if err := ioutil.WriteFile(queryFilePath, app.MustAsset(app.TemplateAsset), 0644); err != nil {
			return err
		}
	}

	cmdArgs := strings.Split(editorFlags, " ")
	cmdArgs = append(cmdArgs, queryFilePath, outFilePath)

	cmd := exec.Command(editor, cmdArgs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

func doRequest(req *app.HTTPRequest) (int, []byte, error) {
	src, err := req.JSON()
	if err != nil {
		return 0, nil, err
	}
	httpReq, err := http.NewRequest(req.Method, req.URL(), bytes.NewBufferString(src))
	if err != nil {
		return 0, nil, err
	}
	httpReq.Header = req.Headers
	resp, err := client.Do(httpReq)
	if err != nil {
		return 0, nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, nil, err
	}

	return resp.StatusCode, tryFormatJSON(body), nil
}

func runQuery(srcReader io.Reader) error {
	request, err := app.ParseRequest(srcReader)
	if err != nil {
		return err
	}

	// TODO: get rid of the logic especially if we can accept "-" from cmd line(see corresponding todo)?
	if sel, err := app.TryParseAsync(os.Stdin, os.Stdout); err == nil {
		// got the whole query file or it is enough input to use parsed data from stdin
		if sel.Validate() == nil {
			request = sel
		} else {
			request.URI = sel.URI
			request.Method = sel.Method
			request.CopyBodyFrom(sel)
		}
	}

	if err := request.Validate(); err != nil {
		return err
	}

	w, err := os.Create(outFilePath)
	if err != nil {
		return err
	}
	defer w.Close()

	code, body, err := doRequest(request)
	if err != nil {
		return err
	}

	if _, err := fmt.Fprintf(w, "#> %d %s %s\n\n", code, request.Method, request.URL()); err != nil {
		return err
	}

	_, err = w.Write(body)
	return err
}

func example() error {
	data := app.MustAsset(app.TemplateAsset)
	fmt.Fprintln(os.Stdout, string(data))
	return nil
}

func doCmd() error {
	switch *flagCmd {
	case cmdEdit:
		return openEditor()
	case cmdExample:
		return example()
	case cmdRun:
		srcReader, err := os.Open(queryFilePath)
		if err != nil {
			return err
		}
		defer srcReader.Close()
		return runQuery(srcReader)
	}

	return fmt.Errorf("Unknown action: %s", *flagCmd)
}

func main() {
	flag.Parse()

	if err := doCmd(); err != nil {
		if err == app.ErrFormatFailed {
			os.Exit(1)
		}

		switch err := err.(type) {
		case *exec.ExitError:
		case *app.JsonifyError:
			if syntaxErr, ok := err.Inner.(*json.SyntaxError); ok {
				errorf("Bad JSON query: %s", err)
				fmt.Fprintf(os.Stderr, "%s\n", color.RedString(err.Highlighted(syntaxErr.Offset)))
				break
			}
			errorf("%s", err)
		default:
			errorf("%s", err)
		}
		os.Exit(1)
	}
}

func errorf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "%s ", color.RedString("ERROR"))
	fmt.Fprintf(os.Stderr, format+"\n", args...)
}

func notEmpty(val, defaultVal string) string {
	if val != "" {
		return val
	}
	return defaultVal
}

func env(key, defaultVal string) string {
	return notEmpty(os.Getenv(key), defaultVal)
}

func tryFormatJSON(body []byte) []byte {
	var out bytes.Buffer
	if err := json.Indent(&out, body, "", jsonIndent); err != nil {
		return body
	}
	return out.Bytes()
}
<commit_msg>refactoring<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"
	"time"

	"github.com/nchern/red/app"

	color "gopkg.in/fatih/color.v1"
)

const (
	jsonIndent = "   "

	filenameBase = "query"
)

var (
	editor      = env("EDITOR", "vim")
	editorFlags = env("EDITOR_FLAGS", "-O")

	appHomePath = path.Join(os.Getenv("HOME"), ".red")

	queryFilename = filenameBase + ".txt"
	outFilename   = filenameBase + ".out"

	queryFilePath = path.Join(appHomePath, queryFilename)
	outFilePath   = path.Join(appHomePath, outFilename)

	client = &http.Client{
		Timeout: 3 * time.Second,
	}

	flagCmd = flag.String("c", "edit", "Command to exectue. One of: edit, run, example")

	// opens the editor of preference to edit requests
	cmdEdit = "edit"

	// runs a given query, either from stdin or a query file(TODO: make it accept "-")
	cmdRun = "run"

	// prints out example of request file
	cmdExample = "example"
)

func openEditor() error {
	if _, err := os.Stat(queryFilePath); os.IsNotExist(err) {
		if err := os.MkdirAll(appHomePath, 0700); err != nil {
			return err
		}
		// path/to/whatever does not exist
		if err := ioutil.WriteFile(queryFilePath, app.MustAsset(app.TemplateAsset), 0644); err != nil {
			return err
		}
	}

	cmdArgs := strings.Split(editorFlags, " ")
	cmdArgs = append(cmdArgs, queryFilePath, outFilePath)

	cmd := exec.Command(editor, cmdArgs...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	return cmd.Run()
}

func doRequest(req *app.HTTPRequest) (int, []byte, error) {
	src, err := req.JSON()
	if err != nil {
		return 0, nil, err
	}
	httpReq, err := http.NewRequest(req.Method, req.URL(), bytes.NewBufferString(src))
	if err != nil {
		return 0, nil, err
	}
	httpReq.Header = req.Headers
	resp, err := client.Do(httpReq)
	if err != nil {
		return 0, nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return 0, nil, err
	}

	return resp.StatusCode, tryFormatJSON(body), nil
}

func runQuery(srcReader io.Reader, out io.Writer) error {
	request, err := app.ParseRequest(srcReader)
	if err != nil {
		return err
	}

	// TODO: get rid of the logic especially if we can accept "-" from cmd line(see corresponding todo)?
	if sel, err := app.TryParseAsync(os.Stdin, os.Stdout); err == nil {
		// got the whole query file or it is enough input to use parsed data from stdin
		if sel.Validate() == nil {
			request = sel
		} else {
			request.URI = sel.URI
			request.Method = sel.Method
			request.CopyBodyFrom(sel)
		}
	}

	if err := request.Validate(); err != nil {
		return err
	}

	code, body, err := doRequest(request)
	if err != nil {
		return err
	}

	if _, err := fmt.Fprintf(out, "#> %d %s %s\n\n", code, request.Method, request.URL()); err != nil {
		return err
	}

	_, err = out.Write(body)
	return err
}

func example() error {
	data := app.MustAsset(app.TemplateAsset)
	fmt.Fprintln(os.Stdout, string(data))
	return nil
}

func run() error {
	srcReader, err := os.Open(queryFilePath)
	if err != nil {
		return err
	}
	defer srcReader.Close()

	w, err := os.Create(outFilePath)
	if err != nil {
		return err
	}
	defer w.Close()

	return runQuery(srcReader, w)
}

func doCmd() error {
	switch *flagCmd {
	case cmdEdit:
		return openEditor()
	case cmdExample:
		return example()
	case cmdRun:
		return run()
	}

	return fmt.Errorf("Unknown action: %s", *flagCmd)
}

func main() {
	flag.Parse()

	if err := doCmd(); err != nil {
		if err == app.ErrFormatFailed {
			os.Exit(1)
		}

		switch err := err.(type) {
		case *exec.ExitError:
		case *app.JsonifyError:
			if syntaxErr, ok := err.Inner.(*json.SyntaxError); ok {
				errorf("Bad JSON query: %s", err)
				fmt.Fprintf(os.Stderr, "%s\n", color.RedString(err.Highlighted(syntaxErr.Offset)))
				break
			}
			errorf("%s", err)
		default:
			errorf("%s", err)
		}
		os.Exit(1)
	}
}

func errorf(format string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, "%s ", color.RedString("ERROR"))
	fmt.Fprintf(os.Stderr, format+"\n", args...)
}

func notEmpty(val, defaultVal string) string {
	if val != "" {
		return val
	}
	return defaultVal
}

func env(key, defaultVal string) string {
	return notEmpty(os.Getenv(key), defaultVal)
}

func tryFormatJSON(body []byte) []byte {
	var out bytes.Buffer
	if err := json.Indent(&out, body, "", jsonIndent); err != nil {
		return body
	}
	return out.Bytes()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/42wim/mm-go-irckit"
	"github.com/alexcesaro/log"
	"github.com/alexcesaro/log/golog"
	"net"
	"os"
)

var logger log.Logger = log.NullLogger

func main() {
	flagDebug := flag.Bool("debug", false, "enable debug logging")
	flagBindInterface := flag.String("interface", "127.0.0.1", "interface to bind to")
	flagBindPort := flag.Int("port", 6667, "Port to bind to")
	flag.Parse()

	logger = golog.New(os.Stderr, log.Info)
	if *flagDebug {
		logger.Info("enabling debug")
		logger = golog.New(os.Stderr, log.Debug)
	}

	irckit.SetLogger(logger)
	socket, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *flagBindInterface, *flagBindPort))
	if err != nil {
		logger.Errorf("Failed to listen on socket: %v\n", err)
	}
	defer socket.Close()

	start(socket)
}

func start(socket net.Listener) {
	for {
		conn, err := socket.Accept()
		if err != nil {
			logger.Errorf("Failed to accept connection: %v", err)
			return
		}

		go func() {
			newsrv := irckit.NewServer("matterircd")
			logger.Infof("New connection: %s", conn.RemoteAddr())
			err = newsrv.Connect(irckit.NewUserMM(conn, newsrv))
			if err != nil {
				logger.Errorf("Failed to join: %v", err)
				return
			}
		}()
	}
}
<commit_msg>Add support for restricting mattermost servers. Closes #5<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/42wim/mm-go-irckit"
	"github.com/alexcesaro/log"
	"github.com/alexcesaro/log/golog"
	"net"
	"os"
	"strings"
)

var logger log.Logger = log.NullLogger
var flagRestrict *string

func main() {
	flagDebug := flag.Bool("debug", false, "enable debug logging")
	flagBindInterface := flag.String("interface", "127.0.0.1", "interface to bind to")
	flagBindPort := flag.Int("port", 6667, "Port to bind to")
	flagRestrict = flag.String("restrict", "", "only allow connection to specified mattermost instances. Space delimited")
	flag.Parse()

	logger = golog.New(os.Stderr, log.Info)
	if *flagDebug {
		logger.Info("enabling debug")
		logger = golog.New(os.Stderr, log.Debug)
	}

	irckit.SetLogger(logger)
	socket, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *flagBindInterface, *flagBindPort))
	if err != nil {
		logger.Errorf("Failed to listen on socket: %v\n", err)
	}
	defer socket.Close()

	start(socket)
}

func start(socket net.Listener) {
	for {
		conn, err := socket.Accept()
		if err != nil {
			logger.Errorf("Failed to accept connection: %v", err)
			return
		}

		go func() {
			cfg := &irckit.MmCfg{AllowedServers: strings.Fields(*flagRestrict)}
			newsrv := irckit.NewServer("matterircd")
			logger.Infof("New connection: %s", conn.RemoteAddr())
			err = newsrv.Connect(irckit.NewUserMM(conn, newsrv, cfg))
			if err != nil {
				logger.Errorf("Failed to join: %v", err)
				return
			}
		}()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"os"
	"strings"
	"syscall"
)

type db struct {
	data []byte
}

func (db *db) set(key string, value string) {
	fmt.Println("DB before modification: ", string(db.data))
	s := key + ": " + value
	b := []byte(s)
	for i := 0; i < len(b); i++ {
		db.data[i] = b[i]
	}
	fmt.Println("DB after modification: ", string(db.data))
}

func (db *db) handler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	switch r.Method {
	case "GET":
		fmt.Print(ps.ByName("key"))
		fmt.Fprintf(w, "Getting %s!", ps.ByName("key"))
	case "POST":
		db.set(ps.ByName("key"), r.FormValue("value"))
	}
}

func NewHandler(db *db) func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	return db.handler
}

func openDB() *db {
	filename := "db"

	if _, err := os.Stat(filename); os.IsNotExist(err) {
		os.Create("db")
	}

	f, err := os.OpenFile(filename, os.O_RDWR, 0)
	if err != nil {
		fmt.Println("Could not open file: ", err)
	}

	data, err := syscall.Mmap(int(f.Fd()), 0, 100, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		fmt.Printf("Could not memory map the file (into a byte array): ", err)
	}

	m := &db{data}
	return m
}

func main() {

	m := openDB()
	handler := NewHandler(m)

	router := httprouter.New()
	router.GET("/get/:key", handler)
	router.POST("/set/:key", handler)

	port := strings.TrimSpace(os.Getenv("PORT"))
	if port == "" {
		port = "3001"
	}

	http.ListenAndServe(":"+port, router)
}
<commit_msg>encode using json<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"os"
	"strings"
	"syscall"
)

type db struct {
	data    []byte
	dataMap map[string]string
}

func (db *db) set(key string, value string) {
	fmt.Println("DB before modification: ", string(db.data))
	db.dataMap[key] = value
	b, err := json.Marshal(db.dataMap)
	if err != nil {
		fmt.Println("Error marshalling db: ", err)
	}
	fmt.Printf("previous data size: %d\nneeded size: %d\n", len(db.data), len(b))
	copy(db.data, b)
	fmt.Println("DB after modification: ", string(db.data))
}

func (db *db) get(key string) string {
	return db.dataMap[key]
}

func (db *db) handler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	switch r.Method {
	case "GET":
		key := ps.ByName("key")
		fmt.Printf("Getting %s!\n", key)
		fmt.Fprintln(w, db.get(key))
	case "POST":
		db.set(ps.ByName("key"), r.FormValue("value"))
	}
}

func NewHandler(db *db) func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	return db.handler
}

func openDB() *db {
	filename := "db"

	if _, err := os.Stat(filename); os.IsNotExist(err) {
		os.Create("db")
	}

	f, err := os.OpenFile(filename, os.O_RDWR, 0)
	if err != nil {
		fmt.Println("Could not open file: ", err)
	}

	fi, err := os.Stat(filename)
	if err != nil {
		fmt.Println("Could not stat file: ", err)
	}

	data, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()), syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		fmt.Printf("Could not memory map the file (into a byte array): ", err)
	}

	var dataMap map[string]string
	err = json.Unmarshal(data, &dataMap)
	if err != nil {
		fmt.Println("Error unmarshalling initial data into map: ", err)
	}

	m := &db{data, dataMap}
	return m
}

func main() {

	m := openDB()
	handler := NewHandler(m)

	router := httprouter.New()
	router.GET("/get/:key", handler)
	router.POST("/set/:key", handler)

	port := strings.TrimSpace(os.Getenv("PORT"))
	if port == "" {
		port = "3001"
	}

	http.ListenAndServe(":"+port, router)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/url"
	"os"
	"time"

	"code.cloudfoundry.org/cflager"
	"code.cloudfoundry.org/routing-api/models"
	uaaclient "code.cloudfoundry.org/uaa-go-client"
	uaaconfig "code.cloudfoundry.org/uaa-go-client/config"

	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/routing-api"
	"code.cloudfoundry.org/routing-api-cli/commands"
	trace "code.cloudfoundry.org/trace-logger"
	"github.com/codegangsta/cli"
)

const (
	RTR_TRACE                      = "RTR_TRACE"
	DefaultTokenFetchRetryInterval = 5 * time.Second
	DefaultTokenFetchNumRetries    = uint32(1)
	DefaultExpirationBufferTime    = int64(30)
)

var version string

var skipVerificationFlag = cli.BoolFlag{
	Name:  "skip-tls-verification, k",
	Usage: "Skip OAuth TLS Verification (optional)",
}

var flags = []cli.Flag{
	cli.StringFlag{
		Name:  "api",
		Usage: "Endpoint for the routing-api. (required)",
	},
	cli.StringFlag{
		Name:  "client-id",
		Usage: "Id of the OAuth client. (required)",
	},
	cli.StringFlag{
		Name:  "client-secret",
		Usage: "Secret for OAuth client. (required)",
	},
	cli.StringFlag{
		Name:  "oauth-url",
		Usage: "URL for OAuth client. (required)",
	},
	skipVerificationFlag,
	cli.StringFlag{
		Name:  "ca-certs",
		Usage: "CA for UAA client (optional)",
	},
}

var eventsFlags = []cli.Flag{
	cli.BoolFlag{
		Name:  "http",
		Usage: "Stream HTTP events",
	},
	cli.BoolFlag{
		Name:  "tcp",
		Usage: "Stream TCP events",
	},
}

var cliCommands = []cli.Command{
	{
		Name:  "register",
		Usage: "Registers routes with the routing-api",
		Description: `Routes must be specified in JSON format, like so:
'[{"route":"foo.com", "port":12345, "ip":"1.2.3.4", "ttl":5, "log_guid":"log-guid"}]'`,
		Action: registerRoutes,
		Flags:  flags,
	},
	{
		Name:  "unregister",
		Usage: "Unregisters routes with the routing-api",
		Description: `Routes must be specified in JSON format, like so:
'[{"route":"foo.com", "port":12345, "ip":"1.2.3.4"]'`,
		Action: unregisterRoutes,
		Flags:  flags,
	},
	{
		Name:   "list",
		Usage:  "Lists the currently registered routes",
		Action: listRoutes,
		Flags:  flags,
	},
	{
		Name:   "events",
		Usage:  "Stream events from the Routing API",
		Action: streamEvents,
		Flags:  append(flags, eventsFlags...),
	},
}

var environmentVariableHelp = `ENVIRONMENT VARIABLES:
   RTR_TRACE=true	Print API request diagnostics to stdout`

func main() {
	cflager.AddFlags(flag.CommandLine)
	fmt.Println()
	app := cli.NewApp()
	app.Name = "rtr"
	app.Usage = "A CLI for the Router API server."
	authors := []cli.Author{cli.Author{Name: "Cloud Foundry Routing Team", Email: "cf-dev@lists.cloudfoundry.org"}}
	app.Authors = authors
	app.Commands = cliCommands
	app.CommandNotFound = commandNotFound
	app.Version = version
	app.Flags = []cli.Flag{skipVerificationFlag}

	cli.AppHelpTemplate = cli.AppHelpTemplate + environmentVariableHelp + "\n"

	trace.NewLogger(os.Getenv(RTR_TRACE))

	app.Run(os.Args)
	os.Exit(0)
}

func registerRoutes(c *cli.Context) {
	issues := checkFlags(c)
	errorMessage := "route registration failed:"
	issues = append(issues, checkArguments(c, "register")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "register")
	}

	desiredRoutes := c.Args().First()
	var routes []models.Route

	err := json.Unmarshal([]byte(desiredRoutes), &routes)
	checkError(errorMessage, err)

	client, err := newRoutingApiClient(c)
	checkError(errorMessage, err)

	err = commands.Register(client, routes)
	checkError(errorMessage, err)

	fmt.Printf("Successfully registered routes: %s\n", desiredRoutes)
}

func unregisterRoutes(c *cli.Context) {
	issues := checkFlags(c)
	errorMessage := "route unregistration failed:"
	issues = append(issues, checkArguments(c, "unregister")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "unregister")
	}

	desiredRoutes := c.Args().First()
	var routes []models.Route
	err := json.Unmarshal([]byte(desiredRoutes), &routes)
	checkError(errorMessage, err)

	client, err := newRoutingApiClient(c)
	checkError(errorMessage, err)

	err = commands.UnRegister(client, routes)
	checkError(errorMessage, err)

	fmt.Printf("Successfully unregistered routes: %s\n", desiredRoutes)
}

func listRoutes(c *cli.Context) {
	errorMessage := "listing routes failed:"
	issues := checkFlags(c)
	issues = append(issues, checkArguments(c, "list")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "list")
	}

	client, err := newRoutingApiClient(c)
	checkError(errorMessage, err)

	routes, err := commands.List(client)
	if err != nil {
		fmt.Println("listing routes failed:", err)
		os.Exit(3)
	}

	prettyRoutes, _ := json.Marshal(routes)

	fmt.Printf("%v\n", string(prettyRoutes))
}

func streamEvents(c *cli.Context) {
	issues := checkFlags(c)
	issues = append(issues, checkArguments(c, "events")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "events")
	}

	streamHttp := c.Bool("http")
	streamTcp := c.Bool("tcp")

	if !streamHttp && !streamTcp {
		streamHttp = true
		streamTcp = true
	}

	client, err := newRoutingApiClient(c)
	checkError("streaming events failed:", err)
	errorChan := make(chan error)
	eventChan := make(chan string)

	numOfSubscriptions := 0

	if streamHttp {
		numOfSubscriptions++
		go streamHttpEvents(client, eventChan, errorChan)
	}

	if streamTcp {
		numOfSubscriptions++
		go streamTcpEvents(client, eventChan, errorChan)
	}

	errorCount := 0

loop:
	for {
		select {
		case eventMessage := <-eventChan:
			fmt.Println(eventMessage)
		case err := <-errorChan:
			errorCount++
			fmt.Printf("Connection closed: %s", err.Error())
			if errorCount >= numOfSubscriptions {
				break loop
			}
		}
	}
}

func streamHttpEvents(client routing_api.Client, eventChan chan string, errorChan chan error) {
	eventSource, err := client.SubscribeToEvents()
	if err != nil {
		fmt.Println("streaming events failed:", err)
		return
	}
	for {
		e, err := eventSource.Next()
		if err != nil {
			errorChan <- err
			break
		}

		event, _ := json.Marshal(e)
		eventChan <- fmt.Sprintf("%v\n", string(event))
	}
}

func streamTcpEvents(client routing_api.Client, eventChan chan string, errorChan chan error) {
	eventSource, err := client.SubscribeToTcpEvents()
	if err != nil {
		fmt.Println("streaming events failed:", err)
		return
	}
	for {
		e, err := eventSource.Next()
		if err != nil {
			errorChan <- err
			break
		}

		event, _ := json.Marshal(e)
		eventChan <- fmt.Sprintf("%v\n", string(event))
	}
}

func buildOauthConfig(c *cli.Context) *uaaconfig.Config {

	return &uaaconfig.Config{
		UaaEndpoint:           c.String("oauth-url"),
		SkipVerification:      c.Bool("skip-tls-verification"),
		ClientName:            c.String("client-id"),
		ClientSecret:          c.String("client-secret"),
		MaxNumberOfRetries:    3,
		RetryInterval:         500 * time.Millisecond,
		ExpirationBufferInSec: 30,
		CACerts:               c.String("ca-certs"),
	}

}

func checkFlags(c *cli.Context) []string {
	var issues []string

	if c.String("api") == "" {
		issues = append(issues, "Must provide an API endpoint for the routing-api component.")
	}

	if c.String("client-id") == "" {
		issues = append(issues, "Must provide the id of an OAuth client.")
	}

	if c.String("client-secret") == "" {
		issues = append(issues, "Must provide an OAuth secret.")
	}

	if c.String("oauth-url") == "" {
		issues = append(issues, "Must provide an URL to the OAuth client.")
	}

	_, err := url.Parse(c.String("oauth-url"))
	if err != nil {
		issues = append(issues, "Invalid OAuth client URL")
	}

	return issues
}

func checkArguments(c *cli.Context, cmd string) []string {
	var issues []string

	switch cmd {
	case "register", "unregister":
		if len(c.Args()) > 1 {
			issues = append(issues, "Unexpected arguments.")
		} else if len(c.Args()) < 1 {
			issues = append(issues, "Must provide routes JSON.")
		}
	case "list", "events":
		if len(c.Args()) > 0 {
			issues = append(issues, "Unexpected arguments.")
		}
	}

	return issues
}

func printHelpForCommand(c *cli.Context, issues []string, cmd string) {
	for _, issue := range issues {
		fmt.Println(issue)
	}
	fmt.Println()
	cli.ShowCommandHelp(c, cmd)
	os.Exit(1)
}

func commandNotFound(c *cli.Context, cmd string) {
	fmt.Println("Not a valid command:", cmd)
	os.Exit(1)
}

func newRoutingApiClient(c *cli.Context) (routing_api.Client, error) {

	uaaClient, err := newUaaClient(c)
	if err != nil {
		return nil, err
	}

	token, err := uaaClient.FetchToken(true)
	if err != nil {
		return nil, err
	}

	routingApiClient := routing_api.NewClient(c.String("api"), c.Bool("skip-tls-verification"))
	routingApiClient.SetToken(token.AccessToken)
	return routingApiClient, nil

}

func checkError(message string, err error) {
	if err != nil {
		fmt.Println(message, err.Error())
		os.Exit(3)
	}
}

func newUaaClient(c *cli.Context) (uaaclient.Client, error) {

	logger, _ := cflager.New("rtr")
	cfg := buildOauthConfig(c)
	klok := clock.NewClock()

	uaaClient, err := uaaclient.NewClient(logger, cfg, klok)
	if err != nil {
		return nil, err
	}
	return uaaClient, nil
}
<commit_msg>Remove cflager<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"net/url"
	"os"
	"time"

	"code.cloudfoundry.org/lager/lagerflags"
	"code.cloudfoundry.org/routing-api/models"
	uaaclient "code.cloudfoundry.org/uaa-go-client"
	uaaconfig "code.cloudfoundry.org/uaa-go-client/config"

	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/routing-api"
	"code.cloudfoundry.org/routing-api-cli/commands"
	trace "code.cloudfoundry.org/trace-logger"
	"github.com/codegangsta/cli"
)

const (
	RTR_TRACE                      = "RTR_TRACE"
	DefaultTokenFetchRetryInterval = 5 * time.Second
	DefaultTokenFetchNumRetries    = uint32(1)
	DefaultExpirationBufferTime    = int64(30)
)

var version string

var skipVerificationFlag = cli.BoolFlag{
	Name:  "skip-tls-verification, k",
	Usage: "Skip OAuth TLS Verification (optional)",
}

var flags = []cli.Flag{
	cli.StringFlag{
		Name:  "api",
		Usage: "Endpoint for the routing-api. (required)",
	},
	cli.StringFlag{
		Name:  "client-id",
		Usage: "Id of the OAuth client. (required)",
	},
	cli.StringFlag{
		Name:  "client-secret",
		Usage: "Secret for OAuth client. (required)",
	},
	cli.StringFlag{
		Name:  "oauth-url",
		Usage: "URL for OAuth client. (required)",
	},
	skipVerificationFlag,
	cli.StringFlag{
		Name:  "ca-certs",
		Usage: "CA for UAA client (optional)",
	},
}

var eventsFlags = []cli.Flag{
	cli.BoolFlag{
		Name:  "http",
		Usage: "Stream HTTP events",
	},
	cli.BoolFlag{
		Name:  "tcp",
		Usage: "Stream TCP events",
	},
}

var cliCommands = []cli.Command{
	{
		Name:  "register",
		Usage: "Registers routes with the routing-api",
		Description: `Routes must be specified in JSON format, like so:
'[{"route":"foo.com", "port":12345, "ip":"1.2.3.4", "ttl":5, "log_guid":"log-guid"}]'`,
		Action: registerRoutes,
		Flags:  flags,
	},
	{
		Name:  "unregister",
		Usage: "Unregisters routes with the routing-api",
		Description: `Routes must be specified in JSON format, like so:
'[{"route":"foo.com", "port":12345, "ip":"1.2.3.4"]'`,
		Action: unregisterRoutes,
		Flags:  flags,
	},
	{
		Name:   "list",
		Usage:  "Lists the currently registered routes",
		Action: listRoutes,
		Flags:  flags,
	},
	{
		Name:   "events",
		Usage:  "Stream events from the Routing API",
		Action: streamEvents,
		Flags:  append(flags, eventsFlags...),
	},
}

var environmentVariableHelp = `ENVIRONMENT VARIABLES:
   RTR_TRACE=true	Print API request diagnostics to stdout`

func main() {
	lagerflags.AddFlags(flag.CommandLine)
	fmt.Println()
	app := cli.NewApp()
	app.Name = "rtr"
	app.Usage = "A CLI for the Router API server."
	authors := []cli.Author{cli.Author{Name: "Cloud Foundry Routing Team", Email: "cf-dev@lists.cloudfoundry.org"}}
	app.Authors = authors
	app.Commands = cliCommands
	app.CommandNotFound = commandNotFound
	app.Version = version
	app.Flags = []cli.Flag{skipVerificationFlag}

	cli.AppHelpTemplate = cli.AppHelpTemplate + environmentVariableHelp + "\n"

	trace.NewLogger(os.Getenv(RTR_TRACE))

	app.Run(os.Args)
	os.Exit(0)
}

func registerRoutes(c *cli.Context) {
	issues := checkFlags(c)
	errorMessage := "route registration failed:"
	issues = append(issues, checkArguments(c, "register")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "register")
	}

	desiredRoutes := c.Args().First()
	var routes []models.Route

	err := json.Unmarshal([]byte(desiredRoutes), &routes)
	checkError(errorMessage, err)

	client, err := newRoutingApiClient(c)
	checkError(errorMessage, err)

	err = commands.Register(client, routes)
	checkError(errorMessage, err)

	fmt.Printf("Successfully registered routes: %s\n", desiredRoutes)
}

func unregisterRoutes(c *cli.Context) {
	issues := checkFlags(c)
	errorMessage := "route unregistration failed:"
	issues = append(issues, checkArguments(c, "unregister")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "unregister")
	}

	desiredRoutes := c.Args().First()
	var routes []models.Route
	err := json.Unmarshal([]byte(desiredRoutes), &routes)
	checkError(errorMessage, err)

	client, err := newRoutingApiClient(c)
	checkError(errorMessage, err)

	err = commands.UnRegister(client, routes)
	checkError(errorMessage, err)

	fmt.Printf("Successfully unregistered routes: %s\n", desiredRoutes)
}

func listRoutes(c *cli.Context) {
	errorMessage := "listing routes failed:"
	issues := checkFlags(c)
	issues = append(issues, checkArguments(c, "list")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "list")
	}

	client, err := newRoutingApiClient(c)
	checkError(errorMessage, err)

	routes, err := commands.List(client)
	if err != nil {
		fmt.Println("listing routes failed:", err)
		os.Exit(3)
	}

	prettyRoutes, _ := json.Marshal(routes)

	fmt.Printf("%v\n", string(prettyRoutes))
}

func streamEvents(c *cli.Context) {
	issues := checkFlags(c)
	issues = append(issues, checkArguments(c, "events")...)

	if len(issues) > 0 {
		printHelpForCommand(c, issues, "events")
	}

	streamHttp := c.Bool("http")
	streamTcp := c.Bool("tcp")

	if !streamHttp && !streamTcp {
		streamHttp = true
		streamTcp = true
	}

	client, err := newRoutingApiClient(c)
	checkError("streaming events failed:", err)
	errorChan := make(chan error)
	eventChan := make(chan string)

	numOfSubscriptions := 0

	if streamHttp {
		numOfSubscriptions++
		go streamHttpEvents(client, eventChan, errorChan)
	}

	if streamTcp {
		numOfSubscriptions++
		go streamTcpEvents(client, eventChan, errorChan)
	}

	errorCount := 0

loop:
	for {
		select {
		case eventMessage := <-eventChan:
			fmt.Println(eventMessage)
		case err := <-errorChan:
			errorCount++
			fmt.Printf("Connection closed: %s", err.Error())
			if errorCount >= numOfSubscriptions {
				break loop
			}
		}
	}
}

func streamHttpEvents(client routing_api.Client, eventChan chan string, errorChan chan error) {
	eventSource, err := client.SubscribeToEvents()
	if err != nil {
		fmt.Println("streaming events failed:", err)
		return
	}
	for {
		e, err := eventSource.Next()
		if err != nil {
			errorChan <- err
			break
		}

		event, _ := json.Marshal(e)
		eventChan <- fmt.Sprintf("%v\n", string(event))
	}
}

func streamTcpEvents(client routing_api.Client, eventChan chan string, errorChan chan error) {
	eventSource, err := client.SubscribeToTcpEvents()
	if err != nil {
		fmt.Println("streaming events failed:", err)
		return
	}
	for {
		e, err := eventSource.Next()
		if err != nil {
			errorChan <- err
			break
		}

		event, _ := json.Marshal(e)
		eventChan <- fmt.Sprintf("%v\n", string(event))
	}
}

func buildOauthConfig(c *cli.Context) *uaaconfig.Config {

	return &uaaconfig.Config{
		UaaEndpoint:           c.String("oauth-url"),
		SkipVerification:      c.Bool("skip-tls-verification"),
		ClientName:            c.String("client-id"),
		ClientSecret:          c.String("client-secret"),
		MaxNumberOfRetries:    3,
		RetryInterval:         500 * time.Millisecond,
		ExpirationBufferInSec: 30,
		CACerts:               c.String("ca-certs"),
	}

}

func checkFlags(c *cli.Context) []string {
	var issues []string

	if c.String("api") == "" {
		issues = append(issues, "Must provide an API endpoint for the routing-api component.")
	}

	if c.String("client-id") == "" {
		issues = append(issues, "Must provide the id of an OAuth client.")
	}

	if c.String("client-secret") == "" {
		issues = append(issues, "Must provide an OAuth secret.")
	}

	if c.String("oauth-url") == "" {
		issues = append(issues, "Must provide an URL to the OAuth client.")
	}

	_, err := url.Parse(c.String("oauth-url"))
	if err != nil {
		issues = append(issues, "Invalid OAuth client URL")
	}

	return issues
}

func checkArguments(c *cli.Context, cmd string) []string {
	var issues []string

	switch cmd {
	case "register", "unregister":
		if len(c.Args()) > 1 {
			issues = append(issues, "Unexpected arguments.")
		} else if len(c.Args()) < 1 {
			issues = append(issues, "Must provide routes JSON.")
		}
	case "list", "events":
		if len(c.Args()) > 0 {
			issues = append(issues, "Unexpected arguments.")
		}
	}

	return issues
}

func printHelpForCommand(c *cli.Context, issues []string, cmd string) {
	for _, issue := range issues {
		fmt.Println(issue)
	}
	fmt.Println()
	cli.ShowCommandHelp(c, cmd)
	os.Exit(1)
}

func commandNotFound(c *cli.Context, cmd string) {
	fmt.Println("Not a valid command:", cmd)
	os.Exit(1)
}

func newRoutingApiClient(c *cli.Context) (routing_api.Client, error) {

	uaaClient, err := newUaaClient(c)
	if err != nil {
		return nil, err
	}

	token, err := uaaClient.FetchToken(true)
	if err != nil {
		return nil, err
	}

	routingApiClient := routing_api.NewClient(c.String("api"), c.Bool("skip-tls-verification"))
	routingApiClient.SetToken(token.AccessToken)
	return routingApiClient, nil

}

func checkError(message string, err error) {
	if err != nil {
		fmt.Println(message, err.Error())
		os.Exit(3)
	}
}

func newUaaClient(c *cli.Context) (uaaclient.Client, error) {

	logger, _ := lagerflags.New("rtr")
	cfg := buildOauthConfig(c)
	klok := clock.NewClock()

	uaaClient, err := uaaclient.NewClient(logger, cfg, klok)
	if err != nil {
		return nil, err
	}
	return uaaClient, nil
}
<|endoftext|>


<commit_before>package main

// about using johnniedoe/contrib/gzip:
// johnniedoe's fork fixes a critical issue for which .String resulted in
// an ERR_DECODING_FAILED. This is an actual pull request on the contrib
// repo, but apparently, gin is dead.

import (
	"encoding/gob"
	"fmt"

	"git.zxq.co/ripple/rippleapi/app"
	"git.zxq.co/ripple/schiavolib"
	"git.zxq.co/x/rs"
	"github.com/fatih/structs"
	"github.com/getsentry/raven-go"
	"github.com/gin-gonic/contrib/sessions"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/johnniedoe/contrib/gzip"
	"github.com/thehowl/conf"
	"github.com/thehowl/qsql"
	"gopkg.in/mailgun/mailgun-go.v1"
)

// version is the version of hanayo
const version = "v1.1.0"

var (
	config struct {
		ListenTo string `description:"ip:port from which to take requests."`
		Unix     bool   `description:"Whether ListenTo is an unix socket."`

		DSN string `description:"MySQL server DSN"`

		CookieSecret string

		RedisEnable         bool
		RedisMaxConnections int
		RedisNetwork        string
		RedisAddress        string
		RedisPassword       string

		AvatarURL     string
		BaseURL       string
		DiscordServer string

		API       string
		BanchoAPI string
		APISecret string

		IP_API string

		Offline          bool   `description:"If this is true, files will be served from the local server instead of the CDN."`
		MainRippleFolder string `description:"Folder where all the non-go projects are contained, such as old-frontend, lets, ci-system."`
		AvatarsFolder    string `description:"location folder of avatars"`

		MailgunDomain        string
		MailgunPrivateAPIKey string
		MailgunPublicAPIKey  string
		MailgunFrom          string

		RecaptchaSite    string
		RecaptchaPrivate string

		DiscordOAuthID     string
		DiscordOAuthSecret string
		DonorBotURL        string
		DonorBotSecret     string

		SentryDSN string

		AnalyticsID string
	}
	configMap map[string]interface{}
	db        *sqlx.DB
	qb        *qsql.DB
	mg        mailgun.Mailgun
)

func main() {
	fmt.Println("hanayo " + version)

	err := conf.Load(&config, "hanayo.conf")
	switch err {
	case nil:
		// carry on
	case conf.ErrNoFile:
		conf.Export(config, "hanayo.conf")
		fmt.Println("The configuration file was not found. We created one for you.")
		return
	default:
		panic(err)
	}

	var configDefaults = map[*string]string{
		&config.ListenTo:         ":45221",
		&config.CookieSecret:     rs.String(46),
		&config.AvatarURL:        "https://a.ripple.moe",
		&config.BaseURL:          "https://ripple.moe",
		&config.BanchoAPI:        "https://c.ripple.moe",
		&config.API:              "http://localhost:40001/api/v1/",
		&config.APISecret:        "Potato",
		&config.IP_API:           "https://ip.zxq.co",
		&config.DiscordServer:    "#",
		&config.MainRippleFolder: "/home/ripple/ripple",
		&config.MailgunFrom:      `"Ripple" <noreply@ripple.moe>`,
	}
	for key, value := range configDefaults {
		if *key == "" {
			*key = value
		}
	}

	configMap = structs.Map(config)

	// initialise db
	db, err = sqlx.Open("mysql", config.DSN)
	if err != nil {
		panic(err)
	}
	qb = qsql.New(db.DB)
	if err != nil {
		panic(err)
	}

	// initialise mailgun
	mg = mailgun.NewMailgun(
		config.MailgunDomain,
		config.MailgunPrivateAPIKey,
		config.MailgunPublicAPIKey,
	)

	if gin.Mode() == gin.DebugMode {
		fmt.Println("Development environment detected. Starting fsnotify on template folder...")
		err := reloader()
		if err != nil {
			fmt.Println(err)
		}
	}

	schiavo.Prefix = "hanayo"
	schiavo.Bunker.Send(fmt.Sprintf("STARTUATO, mode: %s", gin.Mode()))

	// even if it's not release, we say that it's release
	// so that gin doesn't spam
	gin.SetMode(gin.ReleaseMode)

	gobRegisters := []interface{}{
		[]message{},
		errorMessage{},
		infoMessage{},
		neutralMessage{},
		warningMessage{},
		successMessage{},
	}
	for _, el := range gobRegisters {
		gob.Register(el)
	}

	fmt.Println("Importing templates...")
	loadTemplates("")

	fmt.Println("Setting up rate limiter...")
	setUpLimiter()

	fmt.Println("Exporting configuration...")

	conf.Export(config, "hanayo.conf")

	httpLoop()
}

func httpLoop() {
	for {
		e := generateEngine()
		fmt.Println("Starting webserver...")
		if !startuato(e) {
			break
		}
	}
}

func generateEngine() *gin.Engine {
	fmt.Println("Starting session system...")
	var store sessions.Store
	if config.RedisMaxConnections != 0 {
		var err error
		store, err = sessions.NewRedisStore(
			config.RedisMaxConnections,
			config.RedisNetwork,
			config.RedisAddress,
			config.RedisPassword,
			[]byte(config.CookieSecret),
		)
		if err != nil {
			fmt.Println(err)
			store = sessions.NewCookieStore([]byte(config.CookieSecret))
		}
	} else {
		store = sessions.NewCookieStore([]byte(config.CookieSecret))
	}

	r := gin.Default()

	// sentry
	if config.SentryDSN != "" {
		ravenClient, err := raven.New(config.SentryDSN)
		if err != nil {
			fmt.Println(err)
		} else {
			r.Use(app.Recovery(ravenClient, false))
		}
	}

	r.Use(
		gzip.Gzip(gzip.DefaultCompression),
		checkRedirect,
		sessions.Sessions("session", store),
		sessionInitializer(),
		rateLimiter(false),
		twoFALock,
	)

	r.Static("/static", "static")
	r.StaticFile("/favicon.ico", "static/favicon.ico")

	r.POST("/login", loginSubmit)
	r.GET("/logout", logout)

	r.GET("/register", register)
	r.POST("/register", registerSubmit)
	r.GET("/register/verify", verifyAccount)
	r.GET("/register/welcome", welcome)

	r.GET("/u/:user", userProfile)

	r.POST("/pwreset", passwordReset)
	r.GET("/pwreset/continue", passwordResetContinue)
	r.POST("/pwreset/continue", passwordResetContinueSubmit)

	r.GET("/2fa_gateway", tfaGateway)
	r.GET("/2fa_gateway/clear", clear2fa)
	r.GET("/2fa_gateway/verify", verify2fa)

	r.GET("/irc/generate", ircGenToken)

	r.GET("/settings/password", changePassword)
	r.POST("/settings/password", changePasswordSubmit)
	r.POST("/settings/userpage/parse", parseBBCode)
	r.POST("/settings/avatar", avatarSubmit)
	r.POST("/settings/2fa/disable", disable2fa)
	r.GET("/settings/discord/finish", discordFinish)
	r.POST("/settings/profbackground/:type", profBackground)

	r.GET("/donate/rates", getRates)

	loadSimplePages(r)

	r.NoRoute(notFound)

	return r
}

const alwaysRespondText = `Ooops! Looks like something went really wrong while trying to process your request.
Perhaps report this to a Ripple developer?
Retrying doing again what you were trying to do might work, too.`
<commit_msg>⬆ v1.1.1 ⬆<commit_after>package main

// about using johnniedoe/contrib/gzip:
// johnniedoe's fork fixes a critical issue for which .String resulted in
// an ERR_DECODING_FAILED. This is an actual pull request on the contrib
// repo, but apparently, gin is dead.

import (
	"encoding/gob"
	"fmt"

	"git.zxq.co/ripple/rippleapi/app"
	"git.zxq.co/ripple/schiavolib"
	"git.zxq.co/x/rs"
	"github.com/fatih/structs"
	"github.com/getsentry/raven-go"
	"github.com/gin-gonic/contrib/sessions"
	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"github.com/johnniedoe/contrib/gzip"
	"github.com/thehowl/conf"
	"github.com/thehowl/qsql"
	"gopkg.in/mailgun/mailgun-go.v1"
)

// version is the version of hanayo
const version = "v1.1.1"

var (
	config struct {
		ListenTo string `description:"ip:port from which to take requests."`
		Unix     bool   `description:"Whether ListenTo is an unix socket."`

		DSN string `description:"MySQL server DSN"`

		CookieSecret string

		RedisEnable         bool
		RedisMaxConnections int
		RedisNetwork        string
		RedisAddress        string
		RedisPassword       string

		AvatarURL     string
		BaseURL       string
		DiscordServer string

		API       string
		BanchoAPI string
		APISecret string

		IP_API string

		Offline          bool   `description:"If this is true, files will be served from the local server instead of the CDN."`
		MainRippleFolder string `description:"Folder where all the non-go projects are contained, such as old-frontend, lets, ci-system."`
		AvatarsFolder    string `description:"location folder of avatars"`

		MailgunDomain        string
		MailgunPrivateAPIKey string
		MailgunPublicAPIKey  string
		MailgunFrom          string

		RecaptchaSite    string
		RecaptchaPrivate string

		DiscordOAuthID     string
		DiscordOAuthSecret string
		DonorBotURL        string
		DonorBotSecret     string

		SentryDSN string

		AnalyticsID string
	}
	configMap map[string]interface{}
	db        *sqlx.DB
	qb        *qsql.DB
	mg        mailgun.Mailgun
)

func main() {
	fmt.Println("hanayo " + version)

	err := conf.Load(&config, "hanayo.conf")
	switch err {
	case nil:
		// carry on
	case conf.ErrNoFile:
		conf.Export(config, "hanayo.conf")
		fmt.Println("The configuration file was not found. We created one for you.")
		return
	default:
		panic(err)
	}

	var configDefaults = map[*string]string{
		&config.ListenTo:         ":45221",
		&config.CookieSecret:     rs.String(46),
		&config.AvatarURL:        "https://a.ripple.moe",
		&config.BaseURL:          "https://ripple.moe",
		&config.BanchoAPI:        "https://c.ripple.moe",
		&config.API:              "http://localhost:40001/api/v1/",
		&config.APISecret:        "Potato",
		&config.IP_API:           "https://ip.zxq.co",
		&config.DiscordServer:    "#",
		&config.MainRippleFolder: "/home/ripple/ripple",
		&config.MailgunFrom:      `"Ripple" <noreply@ripple.moe>`,
	}
	for key, value := range configDefaults {
		if *key == "" {
			*key = value
		}
	}

	configMap = structs.Map(config)

	// initialise db
	db, err = sqlx.Open("mysql", config.DSN)
	if err != nil {
		panic(err)
	}
	qb = qsql.New(db.DB)
	if err != nil {
		panic(err)
	}

	// initialise mailgun
	mg = mailgun.NewMailgun(
		config.MailgunDomain,
		config.MailgunPrivateAPIKey,
		config.MailgunPublicAPIKey,
	)

	if gin.Mode() == gin.DebugMode {
		fmt.Println("Development environment detected. Starting fsnotify on template folder...")
		err := reloader()
		if err != nil {
			fmt.Println(err)
		}
	}

	schiavo.Prefix = "hanayo"
	schiavo.Bunker.Send(fmt.Sprintf("STARTUATO, mode: %s", gin.Mode()))

	// even if it's not release, we say that it's release
	// so that gin doesn't spam
	gin.SetMode(gin.ReleaseMode)

	gobRegisters := []interface{}{
		[]message{},
		errorMessage{},
		infoMessage{},
		neutralMessage{},
		warningMessage{},
		successMessage{},
	}
	for _, el := range gobRegisters {
		gob.Register(el)
	}

	fmt.Println("Importing templates...")
	loadTemplates("")

	fmt.Println("Setting up rate limiter...")
	setUpLimiter()

	fmt.Println("Exporting configuration...")

	conf.Export(config, "hanayo.conf")

	httpLoop()
}

func httpLoop() {
	for {
		e := generateEngine()
		fmt.Println("Starting webserver...")
		if !startuato(e) {
			break
		}
	}
}

func generateEngine() *gin.Engine {
	fmt.Println("Starting session system...")
	var store sessions.Store
	if config.RedisMaxConnections != 0 {
		var err error
		store, err = sessions.NewRedisStore(
			config.RedisMaxConnections,
			config.RedisNetwork,
			config.RedisAddress,
			config.RedisPassword,
			[]byte(config.CookieSecret),
		)
		if err != nil {
			fmt.Println(err)
			store = sessions.NewCookieStore([]byte(config.CookieSecret))
		}
	} else {
		store = sessions.NewCookieStore([]byte(config.CookieSecret))
	}

	r := gin.Default()

	// sentry
	if config.SentryDSN != "" {
		ravenClient, err := raven.New(config.SentryDSN)
		if err != nil {
			fmt.Println(err)
		} else {
			r.Use(app.Recovery(ravenClient, false))
		}
	}

	r.Use(
		gzip.Gzip(gzip.DefaultCompression),
		checkRedirect,
		sessions.Sessions("session", store),
		sessionInitializer(),
		rateLimiter(false),
		twoFALock,
	)

	r.Static("/static", "static")
	r.StaticFile("/favicon.ico", "static/favicon.ico")

	r.POST("/login", loginSubmit)
	r.GET("/logout", logout)

	r.GET("/register", register)
	r.POST("/register", registerSubmit)
	r.GET("/register/verify", verifyAccount)
	r.GET("/register/welcome", welcome)

	r.GET("/u/:user", userProfile)

	r.POST("/pwreset", passwordReset)
	r.GET("/pwreset/continue", passwordResetContinue)
	r.POST("/pwreset/continue", passwordResetContinueSubmit)

	r.GET("/2fa_gateway", tfaGateway)
	r.GET("/2fa_gateway/clear", clear2fa)
	r.GET("/2fa_gateway/verify", verify2fa)

	r.GET("/irc/generate", ircGenToken)

	r.GET("/settings/password", changePassword)
	r.POST("/settings/password", changePasswordSubmit)
	r.POST("/settings/userpage/parse", parseBBCode)
	r.POST("/settings/avatar", avatarSubmit)
	r.POST("/settings/2fa/disable", disable2fa)
	r.GET("/settings/discord/finish", discordFinish)
	r.POST("/settings/profbackground/:type", profBackground)

	r.GET("/donate/rates", getRates)

	loadSimplePages(r)

	r.NoRoute(notFound)

	return r
}

const alwaysRespondText = `Ooops! Looks like something went really wrong while trying to process your request.
Perhaps report this to a Ripple developer?
Retrying doing again what you were trying to do might work, too.`
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"time"

	"github.com/avinashbot/himawari/background"
	"github.com/avinashbot/himawari/download"
)

var (
	satellite string
	depth     int
	every     time.Duration
)

func init() {
	flag.StringVar(&satellite, "satellite", "himawari", `The satellite to use: "himawari" or "dscovr".`)
	flag.IntVar(&depth, "depth", 4, "Resolution of the Himawari image. One of 4, 8, 16, 20.")
	flag.DurationVar(&every, "every", 0, "Time to wait between each rerun.")
}

func main() {
	flag.Parse()

	// Set the satellite.
	var dl download.Downloader
	switch satellite {
	case "himawari":
		dl = download.Himawari{Depth: depth}
	case "dscovr":
		dl = download.Dscovr{}
	default:
		log.Fatalln("Satellite not recognized. Exiting.")
	}

	// Start off with a zero time.
	for lastTime := (time.Time{}); ; time.Sleep(every) {
		// Get the filename to the latest image.
		filename, err := dl.ModifiedSince(lastTime)
		if err != nil {
			log.Println(err)
			continue
		}
		if filename == "" {
			log.Println("No changes since last time. Trying again later...")
			continue
		}

		// There is new image out. Download it.
		log.Println("Starting download...")
		benchmarkTime := time.Now()
		img, err := dl.Download(filename)
		if err != nil {
			log.Println(err)
			continue
		}
		log.Printf("Done! Download took %s.\n", time.Now().Sub(benchmarkTime))

		// Set the image as the background.
		// This one's a serious error, so break if it happens.
		log.Println("Setting image as background...")
		if err := background.Set(img); err != nil {
			log.Println(err)
			break
		}

		// Success. Replace lastTime with the current time.
		lastTime = time.Now()

		// If we're only doing this once, quit.
		if every == 0 {
			break
		}
	}
}
<commit_msg>Fix useless break.<commit_after>package main

import (
	"flag"
	"log"
	"time"

	"github.com/avinashbot/himawari/background"
	"github.com/avinashbot/himawari/download"
)

var (
	satellite string
	depth     int
	every     time.Duration
)

func init() {
	flag.StringVar(&satellite, "satellite", "himawari", `The satellite to use: "himawari" or "dscovr".`)
	flag.IntVar(&depth, "depth", 4, "Resolution of the Himawari image. One of 4, 8, 16, 20.")
	flag.DurationVar(&every, "every", 0, "Time to wait between each rerun.")
}

func main() {
	flag.Parse()

	// Set the satellite.
	var dl download.Downloader
	switch satellite {
	case "himawari":
		dl = download.Himawari{Depth: depth}
	case "dscovr":
		dl = download.Dscovr{}
	default:
		log.Fatalln("Satellite not recognized. Exiting.")
	}

	// Start off with a zero time.
	lastTime := time.Time{}

	for ; ; time.Sleep(every) {
		// Get the filename to the latest image.
		filename, err := dl.ModifiedSince(lastTime)
		if err != nil {
			log.Println(err)
			continue
		}
		if filename == "" {
			log.Println("No changes since last time. Trying again later...")
			continue
		}

		// There is new image out. Download it.
		log.Println("Starting download...")
		benchmarkTime := time.Now()
		img, err := dl.Download(filename)
		if err != nil {
			log.Println(err)
			continue
		}
		log.Printf("Done! Download took %s.\n", time.Now().Sub(benchmarkTime))

		// Set the image as the background.
		// This one's a serious error, so break if it happens.
		log.Println("Setting image as background...")
		if err := background.Set(img); err != nil {
			log.Fatalln(err)
		}

		// Success. Replace lastTime with the current time.
		lastTime = time.Now()

		// If we're only doing this once, quit.
		if every == 0 {
			break
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A fuse file system for Google Cloud Storage buckets.
//
// Usage:
//
//	gcsfuse [flags] bucket mount_point
package main

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"time"

	"github.com/googlecloudplatform/gcsfuse/internal/storage"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"

	"github.com/googlecloudplatform/gcsfuse/internal/auth"
	"github.com/googlecloudplatform/gcsfuse/internal/canned"
	"github.com/googlecloudplatform/gcsfuse/internal/gcsx"
	"github.com/googlecloudplatform/gcsfuse/internal/locker"
	"github.com/googlecloudplatform/gcsfuse/internal/logger"
	"github.com/googlecloudplatform/gcsfuse/internal/monitor"
	"github.com/googlecloudplatform/gcsfuse/internal/perf"
	"github.com/jacobsa/daemonize"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/kardianos/osext"
	"github.com/urfave/cli"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			logger.Info("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				logger.Infof("Failed to unmount in response to SIGINT: %v", err)
			} else {
				logger.Infof("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

func getConn(flags *flagStorage) (c *gcsx.Connection, err error) {
	var tokenSrc oauth2.TokenSource
	if flags.Endpoint.Hostname() == "storage.googleapis.com" {
		tokenSrc, err = auth.GetTokenSource(
			context.Background(),
			flags.KeyFile,
			flags.TokenUrl,
			flags.ReuseTokenFromUrl,
		)
		if err != nil {
			err = fmt.Errorf("GetTokenSource: %w", err)
			return
		}
	} else {
		// Do not use OAuth with non-Google hosts.
		tokenSrc = oauth2.StaticTokenSource(&oauth2.Token{})
	}

	// Create the connection.
	cfg := &gcs.ConnConfig{
		Url:             flags.Endpoint,
		TokenSource:     tokenSrc,
		UserAgent:       fmt.Sprintf("gcsfuse/%s %s", getVersion(), flags.AppName),
		MaxBackoffSleep: flags.MaxRetrySleep,
	}

	// The default HTTP transport uses HTTP/2 with TCP multiplexing, which
	// does not create new TCP connections even when the idle connections
	// run out. To specify multiple connections per host, HTTP/2 is disabled
	// on purpose.
	if flags.DisableHTTP2 {
		cfg.Transport = &http.Transport{
			MaxConnsPerHost: flags.MaxConnsPerHost,
			// This disables HTTP/2 in the transport.
			TLSNextProto: make(
				map[string]func(string, *tls.Conn) http.RoundTripper,
			),
		}
	}

	if flags.DebugHTTP {
		cfg.HTTPDebugLogger = logger.NewDebug("http: ")
	}

	if flags.DebugGCS {
		cfg.GCSDebugLogger = logger.NewDebug("gcs: ")
	}

	return gcsx.NewConnection(cfg)
}

func getConnWithRetry(flags *flagStorage) (c *gcsx.Connection, err error) {
	c, err = getConn(flags)
	for delay := 1 * time.Second; delay <= flags.MaxRetrySleep && err != nil; delay = delay/2 + delay {
		logger.Infof("Waiting for connection: %v\n", err)
		time.Sleep(delay)
		c, err = getConn(flags)
	}
	return
}

////////////////////////////////////////////////////////////////////////
// main logic
////////////////////////////////////////////////////////////////////////

// Mount the file system according to arguments in the supplied context.
func createStorageHandle(flags *flagStorage) (storageHandle storage.StorageHandle, err error) {
	var tokenSrc oauth2.TokenSource

	tokenSrc, err = auth.GetTokenSource(context.Background(), flags.KeyFile, flags.TokenUrl, true)
	if err != nil {
		err = fmt.Errorf("get token source: %w", err)
		return
	}
	var storageClientConfig = storage.StorageClientConfig{
		DisableHTTP2:        flags.DisableHTTP2,
		MaxConnsPerHost:     flags.MaxConnsPerHost,
		MaxIdleConnsPerHost: flags.MaxIdleConnsPerHost,
		TokenSrc:            tokenSrc,
		HttpClientTimeout:   flags.HttpClientTimeout,
		MaxRetryDuration:    flags.MaxRetryDuration,
		RetryMultiplier:     flags.RetryMultiplier,
	}

	storageHandle, err = storage.NewStorageHandle(context.Background(), storageClientConfig)
	return
}

func mountWithArgs(
		bucketName string,
		mountPoint string,
		flags *flagStorage,
		mountStatus *log.Logger) (mfs *fuse.MountedFileSystem, err error) {
	// Enable invariant checking if requested.
	if flags.DebugInvariants {
		locker.EnableInvariantsCheck()
	}
	if flags.DebugMutex {
		locker.EnableDebugMessages()
	}

	// Grab the connection.
	//
	// Special case: if we're mounting the fake bucket, we don't need an actual
	// connection.
	var conn *gcsx.Connection
	var storageHandle storage.StorageHandle
	if bucketName != canned.FakeBucketName {
		mountStatus.Println("Opening GCS connection...")

		if flags.EnableStorageClientLibrary {
			storageHandle, err = createStorageHandle(flags)
		} else {
			conn, err = getConnWithRetry(flags)
		}
		if err != nil {
			mountStatus.Printf("Failed to open connection: %v\n", err)
			err = fmt.Errorf("getConnWithRetry: %w", err)
			return
		}
	}

	// Mount the file system.
	logger.Infof("Creating a mount at %q\n", mountPoint)
	mfs, err = mountWithConn(
		context.Background(),
		bucketName,
		mountPoint,
		flags,
		conn,
		storageHandle,
		mountStatus)

	if err != nil {
		err = fmt.Errorf("mountWithConn: %w", err)
		return
	}

	return
}

func populateArgs(c *cli.Context) (
		bucketName string,
		mountPoint string,
		err error) {
	// Extract arguments.
	switch len(c.Args()) {
	case 1:
		bucketName = ""
		mountPoint = c.Args()[0]

	case 2:
		bucketName = c.Args()[0]
		mountPoint = c.Args()[1]

	default:
		err = fmt.Errorf(
			"%s takes one or two arguments. Run `%s --help` for more info.",
			path.Base(os.Args[0]),
			path.Base(os.Args[0]))

		return
	}

	// Canonicalize the mount point, making it absolute. This is important when
	// daemonizing below, since the daemon will change its working directory
	// before running this code again.
	mountPoint, err = getResolvedPath(mountPoint)
	if err != nil {
		err = fmt.Errorf("canonicalizing mount point: %w", err)
		return
	}
	return
}

func runCLIApp(c *cli.Context) (err error) {
	err = resolvePathForTheFlagsInContext(c)
	if err != nil {
		return fmt.Errorf("Resolving path: %w", err)
	}

	flags := populateFlags(c)

	if flags.Foreground && flags.LogFile != "" {
		err = logger.InitLogFile(flags.LogFile, flags.LogFormat)
		if err != nil {
			return fmt.Errorf("init log file: %w", err)
		}
	}

	var bucketName string
	var mountPoint string
	bucketName, mountPoint, err = populateArgs(c)
	if err != nil {
		return
	}

	logger.Infof("Start gcsfuse/%s for app %q using mount point: %s\n", getVersion(), flags.AppName, mountPoint)

	// If we haven't been asked to run in foreground mode, we should run a daemon
	// with the foreground flag set and wait for it to mount.
	if !flags.Foreground {
		// Find the executable.
		var path string
		path, err = osext.Executable()
		if err != nil {
			err = fmt.Errorf("osext.Executable: %w", err)
			return
		}

		// Set up arguments. Be sure to use foreground mode, and to send along the
		// potentially-modified mount point.
		args := append([]string{"--foreground"}, os.Args[1:]...)
		args[len(args)-1] = mountPoint

		// Pass along PATH so that the daemon can find fusermount on Linux.
		env := []string{
			fmt.Sprintf("PATH=%s", os.Getenv("PATH")),
		}

		// Pass along GOOGLE_APPLICATION_CREDENTIALS, since we document in
		// mounting.md that it can be used for specifying a key file.
		if p, ok := os.LookupEnv("GOOGLE_APPLICATION_CREDENTIALS"); ok {
			env = append(env, fmt.Sprintf("GOOGLE_APPLICATION_CREDENTIALS=%s", p))
		}
		// Pass through the https_proxy/http_proxy environment variable,
		// in case the host requires a proxy server to reach the GCS endpoint.
		// https_proxy has precedence over http_proxy, in case both are set
		if p, ok := os.LookupEnv("https_proxy"); ok {
			env = append(env, fmt.Sprintf("https_proxy=%s", p))
			fmt.Fprintf(
				os.Stdout,
				"Added environment https_proxy: %s\n",
				p)
		} else if p, ok := os.LookupEnv("http_proxy"); ok {
			env = append(env, fmt.Sprintf("http_proxy=%s", p))
			fmt.Fprintf(
				os.Stdout,
				"Added environment http_proxy: %s\n",
				p)
		}
		// Pass through the no_proxy enviroment variable. Whenever
		// using the http(s)_proxy environment variables. This should
		// also be included to know for which hosts the use of proxies
		// should be ignored.
		if p, ok := os.LookupEnv("no_proxy"); ok {
			env = append(env, fmt.Sprintf("no_proxy=%s", p))
			fmt.Fprintf(
				os.Stdout,
				"Added environment no_proxy: %s\n",
				p)
		}

		// Pass the parent process working directory to child process via
		// environment variable. This variable will be used to resolve relative paths.
		if parentProcessExecutionDir, err := os.Getwd(); err == nil {
			env = append(env, fmt.Sprintf("%s=%s", GCSFUSE_PARENT_PROCESS_DIR,
				parentProcessExecutionDir))
		}

		// Here, parent process doesn't pass the $HOME to child process implicitly,
		// hence we need to pass it explicitly.
		if homeDir, _ := os.UserHomeDir(); err == nil {
			env = append(env, fmt.Sprintf("HOME=%s", homeDir))
		}

		// Run.
		err = daemonize.Run(path, args, env, os.Stdout)
		if err != nil {
			err = fmt.Errorf("daemonize.Run: %w", err)
			return
		}

		return
	}

	// The returned error is ignored as we do not enforce monitoring exporters
	monitor.EnableStackdriverExporter(flags.StackdriverExportInterval)
	monitor.EnableOpenTelemetryCollectorExporter(flags.OtelCollectorAddress)

	// Mount, writing information about our progress to the writer that package
	// daemonize gives us and telling it about the outcome.
	var mfs *fuse.MountedFileSystem
	{
		mountStatus := logger.NewNotice("")
		mfs, err = mountWithArgs(bucketName, mountPoint, flags, mountStatus)

		if err == nil {
			mountStatus.Println("File system has been successfully mounted.")
			daemonize.SignalOutcome(nil)
		} else {
			err = fmt.Errorf("mountWithArgs: %w", err)
			daemonize.SignalOutcome(err)
			return
		}
	}

	// Let the user unmount with Ctrl-C (SIGINT).
	registerSIGINTHandler(mfs.Dir())

	// Wait for the file system to be unmounted.
	err = mfs.Join(context.Background())

	monitor.CloseStackdriverExporter()
	monitor.CloseOpenTelemetryCollectorExporter()

	if err != nil {
		err = fmt.Errorf("MountedFileSystem.Join: %w", err)
		return
	}

	return
}

func run() (err error) {
	// Set up the app.
	app := newApp()

	var appErr error
	app.Action = func(c *cli.Context) {
		appErr = runCLIApp(c)
	}

	// Run it.
	err = app.Run(os.Args)
	if err != nil {
		return
	}

	err = appErr
	return
}

func main() {
	// Make logging output better.
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	// Set up profiling handlers.
	go perf.HandleCPUProfileSignals()
	go perf.HandleMemoryProfileSignals()

	// Run.
	err := run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<commit_msg>Create Storage Handle Instance<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A fuse file system for Google Cloud Storage buckets.
//
// Usage:
//
//	gcsfuse [flags] bucket mount_point
package main

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"time"

	"github.com/googlecloudplatform/gcsfuse/internal/storage"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"

	"github.com/googlecloudplatform/gcsfuse/internal/auth"
	"github.com/googlecloudplatform/gcsfuse/internal/canned"
	"github.com/googlecloudplatform/gcsfuse/internal/gcsx"
	"github.com/googlecloudplatform/gcsfuse/internal/locker"
	"github.com/googlecloudplatform/gcsfuse/internal/logger"
	"github.com/googlecloudplatform/gcsfuse/internal/monitor"
	"github.com/googlecloudplatform/gcsfuse/internal/perf"
	"github.com/jacobsa/daemonize"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/kardianos/osext"
	"github.com/urfave/cli"
)

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func registerSIGINTHandler(mountPoint string) {
	// Register for SIGINT.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)

	// Start a goroutine that will unmount when the signal is received.
	go func() {
		for {
			<-signalChan
			logger.Info("Received SIGINT, attempting to unmount...")

			err := fuse.Unmount(mountPoint)
			if err != nil {
				logger.Infof("Failed to unmount in response to SIGINT: %v", err)
			} else {
				logger.Infof("Successfully unmounted in response to SIGINT.")
				return
			}
		}
	}()
}

func getConn(flags *flagStorage) (c *gcsx.Connection, err error) {
	var tokenSrc oauth2.TokenSource
	if flags.Endpoint.Hostname() == "storage.googleapis.com" {
		tokenSrc, err = auth.GetTokenSource(
			context.Background(),
			flags.KeyFile,
			flags.TokenUrl,
			flags.ReuseTokenFromUrl,
		)
		if err != nil {
			err = fmt.Errorf("GetTokenSource: %w", err)
			return
		}
	} else {
		// Do not use OAuth with non-Google hosts.
		tokenSrc = oauth2.StaticTokenSource(&oauth2.Token{})
	}

	// Create the connection.
	cfg := &gcs.ConnConfig{
		Url:             flags.Endpoint,
		TokenSource:     tokenSrc,
		UserAgent:       fmt.Sprintf("gcsfuse/%s %s", getVersion(), flags.AppName),
		MaxBackoffSleep: flags.MaxRetrySleep,
	}

	// The default HTTP transport uses HTTP/2 with TCP multiplexing, which
	// does not create new TCP connections even when the idle connections
	// run out. To specify multiple connections per host, HTTP/2 is disabled
	// on purpose.
	if flags.DisableHTTP2 {
		cfg.Transport = &http.Transport{
			MaxConnsPerHost: flags.MaxConnsPerHost,
			// This disables HTTP/2 in the transport.
			TLSNextProto: make(
				map[string]func(string, *tls.Conn) http.RoundTripper,
			),
		}
	}

	if flags.DebugHTTP {
		cfg.HTTPDebugLogger = logger.NewDebug("http: ")
	}

	if flags.DebugGCS {
		cfg.GCSDebugLogger = logger.NewDebug("gcs: ")
	}

	return gcsx.NewConnection(cfg)
}

func getConnWithRetry(flags *flagStorage) (c *gcsx.Connection, err error) {
	c, err = getConn(flags)
	for delay := 1 * time.Second; delay <= flags.MaxRetrySleep && err != nil; delay = delay/2 + delay {
		logger.Infof("Waiting for connection: %v\n", err)
		time.Sleep(delay)
		c, err = getConn(flags)
	}
	return
}

////////////////////////////////////////////////////////////////////////
// main logic
////////////////////////////////////////////////////////////////////////

// Mount the file system according to arguments in the supplied context.
func createStorageHandle(flags *flagStorage) (storageHandle storage.StorageHandle, err error) {
	var tokenSrc oauth2.TokenSource

	tokenSrc, err = auth.GetTokenSource(context.Background(), flags.KeyFile, flags.TokenUrl, true)
	if err != nil {
		err = fmt.Errorf("get token source: %w", err)
		return
	}
	var storageClientConfig = storage.StorageClientConfig{
		DisableHTTP2:        flags.DisableHTTP2,
		MaxConnsPerHost:     flags.MaxConnsPerHost,
		MaxIdleConnsPerHost: flags.MaxIdleConnsPerHost,
		TokenSrc:            tokenSrc,
		HttpClientTimeout:   flags.HttpClientTimeout,
		MaxRetryDuration:    flags.MaxRetryDuration,
		RetryMultiplier:     flags.RetryMultiplier,
	}

	storageHandle, err = storage.NewStorageHandle(context.Background(), storageClientConfig)
	return
}

func mountWithArgs(
	bucketName string,
	mountPoint string,
	flags *flagStorage,
	mountStatus *log.Logger) (mfs *fuse.MountedFileSystem, err error) {
	// Enable invariant checking if requested.
	if flags.DebugInvariants {
		locker.EnableInvariantsCheck()
	}
	if flags.DebugMutex {
		locker.EnableDebugMessages()
	}

	// Grab the connection.
	//
	// Special case: if we're mounting the fake bucket, we don't need an actual
	// connection.
	var conn *gcsx.Connection
	var storageHandle storage.StorageHandle
	if bucketName != canned.FakeBucketName {
		mountStatus.Println("Opening GCS connection...")

		if flags.EnableStorageClientLibrary {
			storageHandle, err = createStorageHandle(flags)
		} else {
			conn, err = getConnWithRetry(flags)
		}
		if err != nil {
			mountStatus.Printf("Failed to open connection: %v\n", err)
			err = fmt.Errorf("getConnWithRetry: %w", err)
			return
		}
	}

	// Mount the file system.
	logger.Infof("Creating a mount at %q\n", mountPoint)
	mfs, err = mountWithConn(
		context.Background(),
		bucketName,
		mountPoint,
		flags,
		conn,
		storageHandle,
		mountStatus)

	if err != nil {
		err = fmt.Errorf("mountWithConn: %w", err)
		return
	}

	return
}

func populateArgs(c *cli.Context) (
	bucketName string,
	mountPoint string,
	err error) {
	// Extract arguments.
	switch len(c.Args()) {
	case 1:
		bucketName = ""
		mountPoint = c.Args()[0]

	case 2:
		bucketName = c.Args()[0]
		mountPoint = c.Args()[1]

	default:
		err = fmt.Errorf(
			"%s takes one or two arguments. Run `%s --help` for more info.",
			path.Base(os.Args[0]),
			path.Base(os.Args[0]))

		return
	}

	// Canonicalize the mount point, making it absolute. This is important when
	// daemonizing below, since the daemon will change its working directory
	// before running this code again.
	mountPoint, err = getResolvedPath(mountPoint)
	if err != nil {
		err = fmt.Errorf("canonicalizing mount point: %w", err)
		return
	}
	return
}

func runCLIApp(c *cli.Context) (err error) {
	err = resolvePathForTheFlagsInContext(c)
	if err != nil {
		return fmt.Errorf("Resolving path: %w", err)
	}

	flags := populateFlags(c)

	if flags.Foreground && flags.LogFile != "" {
		err = logger.InitLogFile(flags.LogFile, flags.LogFormat)
		if err != nil {
			return fmt.Errorf("init log file: %w", err)
		}
	}

	var bucketName string
	var mountPoint string
	bucketName, mountPoint, err = populateArgs(c)
	if err != nil {
		return
	}

	logger.Infof("Start gcsfuse/%s for app %q using mount point: %s\n", getVersion(), flags.AppName, mountPoint)

	// If we haven't been asked to run in foreground mode, we should run a daemon
	// with the foreground flag set and wait for it to mount.
	if !flags.Foreground {
		// Find the executable.
		var path string
		path, err = osext.Executable()
		if err != nil {
			err = fmt.Errorf("osext.Executable: %w", err)
			return
		}

		// Set up arguments. Be sure to use foreground mode, and to send along the
		// potentially-modified mount point.
		args := append([]string{"--foreground"}, os.Args[1:]...)
		args[len(args)-1] = mountPoint

		// Pass along PATH so that the daemon can find fusermount on Linux.
		env := []string{
			fmt.Sprintf("PATH=%s", os.Getenv("PATH")),
		}

		// Pass along GOOGLE_APPLICATION_CREDENTIALS, since we document in
		// mounting.md that it can be used for specifying a key file.
		if p, ok := os.LookupEnv("GOOGLE_APPLICATION_CREDENTIALS"); ok {
			env = append(env, fmt.Sprintf("GOOGLE_APPLICATION_CREDENTIALS=%s", p))
		}
		// Pass through the https_proxy/http_proxy environment variable,
		// in case the host requires a proxy server to reach the GCS endpoint.
		// https_proxy has precedence over http_proxy, in case both are set
		if p, ok := os.LookupEnv("https_proxy"); ok {
			env = append(env, fmt.Sprintf("https_proxy=%s", p))
			fmt.Fprintf(
				os.Stdout,
				"Added environment https_proxy: %s\n",
				p)
		} else if p, ok := os.LookupEnv("http_proxy"); ok {
			env = append(env, fmt.Sprintf("http_proxy=%s", p))
			fmt.Fprintf(
				os.Stdout,
				"Added environment http_proxy: %s\n",
				p)
		}
		// Pass through the no_proxy enviroment variable. Whenever
		// using the http(s)_proxy environment variables. This should
		// also be included to know for which hosts the use of proxies
		// should be ignored.
		if p, ok := os.LookupEnv("no_proxy"); ok {
			env = append(env, fmt.Sprintf("no_proxy=%s", p))
			fmt.Fprintf(
				os.Stdout,
				"Added environment no_proxy: %s\n",
				p)
		}

		// Pass the parent process working directory to child process via
		// environment variable. This variable will be used to resolve relative paths.
		if parentProcessExecutionDir, err := os.Getwd(); err == nil {
			env = append(env, fmt.Sprintf("%s=%s", GCSFUSE_PARENT_PROCESS_DIR,
				parentProcessExecutionDir))
		}

		// Here, parent process doesn't pass the $HOME to child process implicitly,
		// hence we need to pass it explicitly.
		if homeDir, _ := os.UserHomeDir(); err == nil {
			env = append(env, fmt.Sprintf("HOME=%s", homeDir))
		}

		// Run.
		err = daemonize.Run(path, args, env, os.Stdout)
		if err != nil {
			err = fmt.Errorf("daemonize.Run: %w", err)
			return
		}

		return
	}

	// The returned error is ignored as we do not enforce monitoring exporters
	monitor.EnableStackdriverExporter(flags.StackdriverExportInterval)
	monitor.EnableOpenTelemetryCollectorExporter(flags.OtelCollectorAddress)

	// Mount, writing information about our progress to the writer that package
	// daemonize gives us and telling it about the outcome.
	var mfs *fuse.MountedFileSystem
	{
		mountStatus := logger.NewNotice("")
		mfs, err = mountWithArgs(bucketName, mountPoint, flags, mountStatus)

		if err == nil {
			mountStatus.Println("File system has been successfully mounted.")
			daemonize.SignalOutcome(nil)
		} else {
			err = fmt.Errorf("mountWithArgs: %w", err)
			daemonize.SignalOutcome(err)
			return
		}
	}

	// Let the user unmount with Ctrl-C (SIGINT).
	registerSIGINTHandler(mfs.Dir())

	// Wait for the file system to be unmounted.
	err = mfs.Join(context.Background())

	monitor.CloseStackdriverExporter()
	monitor.CloseOpenTelemetryCollectorExporter()

	if err != nil {
		err = fmt.Errorf("MountedFileSystem.Join: %w", err)
		return
	}

	return
}

func run() (err error) {
	// Set up the app.
	app := newApp()

	var appErr error
	app.Action = func(c *cli.Context) {
		appErr = runCLIApp(c)
	}

	// Run it.
	err = app.Run(os.Args)
	if err != nil {
		return
	}

	err = appErr
	return
}

func main() {
	// Make logging output better.
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)

	// Set up profiling handlers.
	go perf.HandleCPUProfileSignals()
	go perf.HandleMemoryProfileSignals()

	// Run.
	err := run()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
<|endoftext|>