<commit_before>/*
package gosdc enables Go programs to interact with the Joyent CloudAPI.

The gosdc package is structured as follow:

	- gosdc/cloudapi. This package interacts with the Cloud API (http://apidocs.joyent.com/cloudapi/).
	- gosdc/localservices. This package provides local services to be used for testing.

Licensed under the Mozilla Public License version 2.0

Copyright (c) Joyent Inc.

*/
package gosdc
<commit_msg>docs: picky picky<commit_after>/*
Package gosdc enables Go programs to interact with the Joyent CloudAPI.

The gosdc package is structured as follow:

	- gosdc/cloudapi. This package interacts with the Cloud API (http://apidocs.joyent.com/cloudapi/).
	- gosdc/localservices. This package provides local services to be used for testing.

Licensed under the Mozilla Public License version 2.0

Copyright (c) Joyent Inc.

*/
package gosdc
<|endoftext|>


<commit_before>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
// Licensed under the same terms as Go itself:
// https://code.google.com/p/go/source/browse/LICENSE

// Package http2 implements the HTTP/2 protocol.
//
// It currently targets draft-14. See http://http2.github.io/
package http2

import (
	"bytes"
	"crypto/tls"
	"io"
	"log"
	"net/http"
	"sync"
)

const (
	// ClientPreface is the string that must be sent by new
	// connections from clients.
	ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
)

var (
	clientPreface = []byte(ClientPreface)
)

const npnProto = "h2-14"

// Server is an HTTP2 server.
type Server struct {
	// MaxStreams optionally ...
	MaxStreams int

	mu sync.Mutex
}

func (srv *Server) handleClientConn(hs *http.Server, c *tls.Conn, h http.Handler) {
	cc := &clientConn{hs, c, h, NewFramer(c, c)}
	cc.serve()
}

type clientConn struct {
	hs *http.Server
	c  *tls.Conn
	h  http.Handler
	fr *Framer
}

func (cc *clientConn) logf(format string, args ...interface{}) {
	if lg := cc.hs.ErrorLog; lg != nil {
		lg.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

func (cc *clientConn) serve() {
	defer cc.c.Close()
	log.Printf("HTTP/2 connection from %v on %p", cc.c.RemoteAddr(), cc.hs)

	buf := make([]byte, len(ClientPreface))
	// TODO: timeout reading from the client
	if _, err := io.ReadFull(cc.c, buf); err != nil {
		cc.logf("error reading client preface: %v", err)
		return
	}
	if !bytes.Equal(buf, clientPreface) {
		cc.logf("bogus greeting from client: %q", buf)
		return
	}
	log.Printf("client %v said hello", cc.c.RemoteAddr())
	for {

		f, err := cc.fr.ReadFrame()
		if h2e, ok := err.(Error); ok {
			if h2e.IsConnectionError() {
				log.Printf("Disconnection; connection error: %v", err)
				return
			}
			// TODO: stream errors, etc
		}
		if err != nil {
			log.Printf("Disconnection due to other error: %v", err)
			return
		}
		log.Printf("got %v: %#v", f.Header(), f)
		if sf, ok := f.(*SettingsFrame); ok {
			log.Printf("Is a settings frame")
			sf.ForeachSetting(func(s SettingID, v uint32) {
				log.Printf("  setting %s = %v", s, v)
			})
		}
	}
}

// ConfigureServer adds HTTP2 support to s as configured by the HTTP/2
// server configuration in conf. The configuration may be nil.
//
// ConfigureServer must be called before s begins serving.
func ConfigureServer(s *http.Server, conf *Server) {
	if conf == nil {
		conf = new(Server)
	}
	if s.TLSConfig == nil {
		s.TLSConfig = new(tls.Config)
	}
	haveNPN := false
	for _, p := range s.TLSConfig.NextProtos {
		if p == npnProto {
			haveNPN = true
			break
		}
	}
	if !haveNPN {
		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, npnProto)
	}

	if s.TLSNextProto == nil {
		s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
	}
	s.TLSNextProto[npnProto] = func(hs *http.Server, c *tls.Conn, h http.Handler) {
		if testHookOnConn != nil {
			testHookOnConn()
		}
		conf.handleClientConn(hs, c, h)
	}
}

var testHookOnConn func() // for testing
<commit_msg>Make some clientConn field names longer<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
// Licensed under the same terms as Go itself:
// https://code.google.com/p/go/source/browse/LICENSE

// Package http2 implements the HTTP/2 protocol.
//
// It currently targets draft-14. See http://http2.github.io/
package http2

import (
	"bytes"
	"crypto/tls"
	"io"
	"log"
	"net/http"
)

const (
	// ClientPreface is the string that must be sent by new
	// connections from clients.
	ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
)

var (
	clientPreface = []byte(ClientPreface)
)

const npnProto = "h2-14"

// Server is an HTTP2 server.
type Server struct {
	// MaxStreams optionally ...
	MaxStreams int
}

func (srv *Server) handleClientConn(hs *http.Server, c *tls.Conn, h http.Handler) {
	cc := &clientConn{
		hs:      hs,
		conn:    c,
		handler: h,
		framer:  NewFramer(c, c),
	}
	cc.serve()
}

type clientConn struct {
	hs      *http.Server
	conn    *tls.Conn
	handler http.Handler
	framer  *Framer
}

func (cc *clientConn) logf(format string, args ...interface{}) {
	if lg := cc.hs.ErrorLog; lg != nil {
		lg.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

func (cc *clientConn) serve() {
	defer cc.conn.Close()
	log.Printf("HTTP/2 connection from %v on %p", cc.conn.RemoteAddr(), cc.hs)

	buf := make([]byte, len(ClientPreface))
	// TODO: timeout reading from the client
	if _, err := io.ReadFull(cc.conn, buf); err != nil {
		cc.logf("error reading client preface: %v", err)
		return
	}
	if !bytes.Equal(buf, clientPreface) {
		cc.logf("bogus greeting from client: %q", buf)
		return
	}
	log.Printf("client %v said hello", cc.conn.RemoteAddr())
	for {

		f, err := cc.framer.ReadFrame()
		if h2e, ok := err.(Error); ok {
			if h2e.IsConnectionError() {
				log.Printf("Disconnection; connection error: %v", err)
				return
			}
			// TODO: stream errors, etc
		}
		if err != nil {
			log.Printf("Disconnection due to other error: %v", err)
			return
		}
		log.Printf("got %v: %#v", f.Header(), f)
		if sf, ok := f.(*SettingsFrame); ok {
			log.Printf("Is a settings frame")
			sf.ForeachSetting(func(s SettingID, v uint32) {
				log.Printf("  setting %s = %v", s, v)
			})
		}
	}
}

// ConfigureServer adds HTTP2 support to s as configured by the HTTP/2
// server configuration in conf. The configuration may be nil.
//
// ConfigureServer must be called before s begins serving.
func ConfigureServer(s *http.Server, conf *Server) {
	if conf == nil {
		conf = new(Server)
	}
	if s.TLSConfig == nil {
		s.TLSConfig = new(tls.Config)
	}
	haveNPN := false
	for _, p := range s.TLSConfig.NextProtos {
		if p == npnProto {
			haveNPN = true
			break
		}
	}
	if !haveNPN {
		s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, npnProto)
	}

	if s.TLSNextProto == nil {
		s.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
	}
	s.TLSNextProto[npnProto] = func(hs *http.Server, c *tls.Conn, h http.Handler) {
		if testHookOnConn != nil {
			testHookOnConn()
		}
		conf.handleClientConn(hs, c, h)
	}
}

var testHookOnConn func() // for testing
<|endoftext|>


<commit_before>package main

import(
    "fmt"
    "os"

    "strings"
    "strconv"
    "bufio"

    "net/http"

    "github.com/wsxiaoys/terminal/color"
)

/* holds our palette, or 16 ANSI colors (8 normal colors + bright complements)
   and two foreground/background colors. colors are 3 byte arrays (RGB) */
type ktPalette struct {

    black    [3]byte
    bblack   [3]byte

    red      [3]byte
    bred     [3]byte

    green    [3]byte
    bgreen   [3]byte

    yellow   [3]byte
    byellow  [3]byte

    blue     [3]byte
    bblue    [3]byte

    purple   [3]byte
    bpurple  [3]byte

    cyan     [3]byte
    bcyan    [3]byte

    white    [3]byte
    bwhite   [3]byte

    fg       [3]byte
    bg       [3]byte
}

/* the default "control" ANSI color set (boring) */
var ansiColors = ktPalette {

    black   : [3]byte {0,0,0},
    bblack  : [3]byte {128,128,128},

    red     : [3]byte {128,0,0},
    bred    : [3]byte {255,0,0},

    green   : [3]byte {0,128,0},
    bgreen  : [3]byte {0,255,0},

    yellow  : [3]byte {128,128,0},
    byellow : [3]byte {255,255,0},

    blue    : [3]byte {0,0,128},
    bblue   : [3]byte {0,0,255},

    purple  : [3]byte {128,0,128},
    bpurple : [3]byte {255,0,255},

    cyan    : [3]byte {0,128,128},
    bcyan   : [3]byte {0,255,255},

    white   : [3]byte {128,128,128},
    bwhite  : [3]byte {255,255,255},

    fg      : [3]byte {0,0,0},
    bg      : [3]byte {255,255,255},
}

/* lets get our money's worth out of this utf-8 crap */
var checkM = "✓"
var xM     = "✗"

/* parses a colorfile, returns palette struct. given a nil file pointer,
   returns standard ANSI color set (our "control") */
func parseColors(colorfile *os.File) (pal ktPalette, err error) {

    if colorfile == nil { return ansiColors, nil }

    ret := ktPalette {}
    var e errConsumer

    scanner := bufio.NewScanner(colorfile)
    for scanner.Scan() {

        if strings.Contains(scanner.Text(), "color") &&
            !strings.Contains(scanner.Text(), "!") {

            /* i am so sorry */
            cur      := strings.Replace(scanner.Text(), " ", "", -1)
            split    := strings.Split(cur, ":")
            hexColor := strings.Replace(split[1], "#", "", -1)
            coNumStr := strings.Replace(split[0], "URxvt*color", "", -1)

            r, err := strconv.ParseUint(hexColor[0:2], 16, 8); e.Consume(err)
            g, err := strconv.ParseUint(hexColor[2:4], 16, 8); e.Consume(err)
            b, err := strconv.ParseUint(hexColor[4:], 16, 8);  e.Consume(err)

            colorNo, err := strconv.Atoi(coNumStr); e.Consume(err)

            if e.err != nil {
                return ktPalette{}, e.err
            }

            switch(colorNo) {
                case 0:  ret.black[0]   = byte(r); ret.black[1]   = byte(g); ret.black[2]   = byte(b)
                case 1:  ret.red[0]     = byte(r); ret.red[1]     = byte(g); ret.red[2]     = byte(b)
                case 2:  ret.green[0]   = byte(r); ret.green[1]   = byte(g); ret.green[2]   = byte(b)
                case 3:  ret.yellow[0]  = byte(r); ret.yellow[1]  = byte(g); ret.yellow[2]  = byte(b)
                case 4:  ret.blue[0]    = byte(r); ret.blue[1]    = byte(g); ret.blue[2]    = byte(b)
                case 5:  ret.purple[0]  = byte(r); ret.purple[1]  = byte(g); ret.purple[2]  = byte(b)
                case 6:  ret.cyan[0]    = byte(r); ret.cyan[1]    = byte(g); ret.cyan[2]    = byte(b)
                case 7:  ret.white[0]   = byte(r); ret.white[1]   = byte(g); ret.white[2]   = byte(b)
                case 8:  ret.bblack[0]  = byte(r); ret.bblack[1]  = byte(g); ret.bblack[2]  = byte(b)
                case 9:  ret.bred[0]    = byte(r); ret.bred[1]    = byte(g); ret.bred[2]    = byte(b)
                case 10: ret.bgreen[0]  = byte(r); ret.bgreen[1]  = byte(g); ret.bgreen[2]  = byte(b)
                case 11: ret.byellow[0] = byte(r); ret.byellow[1] = byte(g); ret.byellow[2] = byte(b)
                case 12: ret.bblue[0]   = byte(r); ret.bblue[1]   = byte(g); ret.bblue[2]   = byte(b)
                case 13: ret.bpurple[0] = byte(r); ret.bpurple[1] = byte(g); ret.bpurple[2] = byte(b)
                case 14: ret.bcyan[0]   = byte(r); ret.bcyan[1]   = byte(g); ret.bcyan[2]   = byte(b)
                case 15: ret.bwhite[0]  = byte(r); ret.bwhite[1]  = byte(g); ret.bwhite[2]  = byte(b)
            }

        } else if strings.Contains(scanner.Text(), "background") {

            hex := strings.Split(scanner.Text(), "#")
            het := hex[1]

            r, err := strconv.ParseUint(het[0:2], 16, 8); e.Consume(err)
            g, err := strconv.ParseUint(het[2:4], 16, 8); e.Consume(err)
            b, err := strconv.ParseUint(het[4:], 16, 8); e.Consume(err)

            if e.err != nil {
                return ktPalette{}, e.err
            }

            ret.bg[0] = byte(r)
            ret.bg[1] = byte(g)
            ret.bg[2] = byte(b)

        } else if strings.Contains(scanner.Text(), "foreground") {

            hex := strings.Split(scanner.Text(), "#")
            het := hex[1]

            r, err := strconv.ParseUint(het[0:2], 16, 8); e.Consume(err)
            g, err := strconv.ParseUint(het[2:4], 16, 8); e.Consume(err)
            b, err := strconv.ParseUint(het[4:], 16, 8); e.Consume(err)

            if e.err != nil {
                return ktPalette{}, e.err
            }

            ret.fg[0] = byte(r)
            ret.fg[1] = byte(g)
            ret.fg[2] = byte(b)
        }
    }

    return ret, e.err
}

func ktInit(dirPrepend string, port int, colorfilePath string) error {

    color.Print("@yparsing colorfile :: @{|}")
    file, err := os.Open(colorfilePath)
    if err != nil {
        color.Printf("@r[%s]@{|} - bad colorfile path\n", xM)
        return fmt.Errorf("%s\n", "bad colorfile path")
    }

    pal, err := parseColors(file)

    if err != nil {
        color.Printf("@r[%s]@{|} - malformed colorfile [%s]\n", xM, err)
        return fmt.Errorf("%s\n", "malformed colorfile")
    }

    color.Printf("@g[%s]@{|}\n", checkM)

    if pal == ansiColors {}

    color.Printf("@ystarting httpd on port @b%d@{|} :: ", port)

    return nil
}

func main() {

    err := ktInit("kolors", 999, "/home/kremlin/.Xresources")

    /* make sure to close() anything you need to (you need to) */
    _, err = http.Get("http://kremlin.cc")

    if err != nil {}
}

type errConsumer struct {
    err error
}

func (e *errConsumer) Consume(err error) {
    if e.err == nil && err != nil {
        e.err = err
    }
}

<commit_msg>begin url host swap code<commit_after>package main

import(
    "fmt"
    "os"

    "io"
//    "io/ioutil"
    "bufio"

    "strings"
    "strconv"
    "text/scanner"

    "net/http"

    "github.com/wsxiaoys/terminal/color"
)

/* holds our palette, or 16 ANSI colors (8 normal colors + bright complements)
   and two foreground/background colors. colors are 3 byte arrays (RGB) */
type ktPalette struct {

    black    [3]byte
    bblack   [3]byte

    red      [3]byte
    bred     [3]byte

    green    [3]byte
    bgreen   [3]byte

    yellow   [3]byte
    byellow  [3]byte

    blue     [3]byte
    bblue    [3]byte

    purple   [3]byte
    bpurple  [3]byte

    cyan     [3]byte
    bcyan    [3]byte

    white    [3]byte
    bwhite   [3]byte

    fg       [3]byte
    bg       [3]byte
}

/* the default "control" ANSI color set (boring) */
var ansiColors = ktPalette {

    black   : [3]byte {0,0,0},
    bblack  : [3]byte {128,128,128},

    red     : [3]byte {128,0,0},
    bred    : [3]byte {255,0,0},

    green   : [3]byte {0,128,0},
    bgreen  : [3]byte {0,255,0},

    yellow  : [3]byte {128,128,0},
    byellow : [3]byte {255,255,0},

    blue    : [3]byte {0,0,128},
    bblue   : [3]byte {0,0,255},

    purple  : [3]byte {128,0,128},
    bpurple : [3]byte {255,0,255},

    cyan    : [3]byte {0,128,128},
    bcyan   : [3]byte {0,255,255},

    white   : [3]byte {128,128,128},
    bwhite  : [3]byte {255,255,255},

    fg      : [3]byte {0,0,0},
    bg      : [3]byte {255,255,255},
}

/* lets get our money's worth out of this utf-8 crap */
var checkM = "✓"
var xM     = "✗"

/* parses a colorfile, returns palette struct. given a nil file pointer,
   returns standard ANSI color set (our "control") */
func parseColors(colorfile *os.File) (pal ktPalette, err error) {

    if colorfile == nil { return ansiColors, nil }

    ret := ktPalette {}
    var e errConsumer

    scanner := bufio.NewScanner(colorfile)
    for scanner.Scan() {

        if strings.Contains(scanner.Text(), "color") &&
            !strings.Contains(scanner.Text(), "!") {

            /* i am so sorry */
            cur      := strings.Replace(scanner.Text(), " ", "", -1)
            split    := strings.Split(cur, ":")
            hexColor := strings.Replace(split[1], "#", "", -1)
            coNumStr := strings.Replace(split[0], "URxvt*color", "", -1)

            r, err := strconv.ParseUint(hexColor[0:2], 16, 8); e.Consume(err)
            g, err := strconv.ParseUint(hexColor[2:4], 16, 8); e.Consume(err)
            b, err := strconv.ParseUint(hexColor[4:], 16, 8);  e.Consume(err)

            colorNo, err := strconv.Atoi(coNumStr); e.Consume(err)

            if e.err != nil {
                return ktPalette{}, e.err
            }

            switch(colorNo) {
                case 0:  ret.black[0]   = byte(r); ret.black[1]   = byte(g); ret.black[2]   = byte(b)
                case 1:  ret.red[0]     = byte(r); ret.red[1]     = byte(g); ret.red[2]     = byte(b)
                case 2:  ret.green[0]   = byte(r); ret.green[1]   = byte(g); ret.green[2]   = byte(b)
                case 3:  ret.yellow[0]  = byte(r); ret.yellow[1]  = byte(g); ret.yellow[2]  = byte(b)
                case 4:  ret.blue[0]    = byte(r); ret.blue[1]    = byte(g); ret.blue[2]    = byte(b)
                case 5:  ret.purple[0]  = byte(r); ret.purple[1]  = byte(g); ret.purple[2]  = byte(b)
                case 6:  ret.cyan[0]    = byte(r); ret.cyan[1]    = byte(g); ret.cyan[2]    = byte(b)
                case 7:  ret.white[0]   = byte(r); ret.white[1]   = byte(g); ret.white[2]   = byte(b)
                case 8:  ret.bblack[0]  = byte(r); ret.bblack[1]  = byte(g); ret.bblack[2]  = byte(b)
                case 9:  ret.bred[0]    = byte(r); ret.bred[1]    = byte(g); ret.bred[2]    = byte(b)
                case 10: ret.bgreen[0]  = byte(r); ret.bgreen[1]  = byte(g); ret.bgreen[2]  = byte(b)
                case 11: ret.byellow[0] = byte(r); ret.byellow[1] = byte(g); ret.byellow[2] = byte(b)
                case 12: ret.bblue[0]   = byte(r); ret.bblue[1]   = byte(g); ret.bblue[2]   = byte(b)
                case 13: ret.bpurple[0] = byte(r); ret.bpurple[1] = byte(g); ret.bpurple[2] = byte(b)
                case 14: ret.bcyan[0]   = byte(r); ret.bcyan[1]   = byte(g); ret.bcyan[2]   = byte(b)
                case 15: ret.bwhite[0]  = byte(r); ret.bwhite[1]  = byte(g); ret.bwhite[2]  = byte(b)
            }

        } else if strings.Contains(scanner.Text(), "background") {

            hex := strings.Split(scanner.Text(), "#")
            het := hex[1]

            r, err := strconv.ParseUint(het[0:2], 16, 8); e.Consume(err)
            g, err := strconv.ParseUint(het[2:4], 16, 8); e.Consume(err)
            b, err := strconv.ParseUint(het[4:], 16, 8); e.Consume(err)

            if e.err != nil {
                return ktPalette{}, e.err
            }

            ret.bg[0] = byte(r)
            ret.bg[1] = byte(g)
            ret.bg[2] = byte(b)

        } else if strings.Contains(scanner.Text(), "foreground") {

            hex := strings.Split(scanner.Text(), "#")
            het := hex[1]

            r, err := strconv.ParseUint(het[0:2], 16, 8); e.Consume(err)
            g, err := strconv.ParseUint(het[2:4], 16, 8); e.Consume(err)
            b, err := strconv.ParseUint(het[4:], 16, 8); e.Consume(err)

            if e.err != nil {
                return ktPalette{}, e.err
            }

            ret.fg[0] = byte(r)
            ret.fg[1] = byte(g)
            ret.fg[2] = byte(b)
        }
    }

    return ret, e.err
}

func ktInit(dirPrepend string, port int, colorfilePath string) error {

    color.Print("@yparsing colorfile :: @{|}")
    file, err := os.Open(colorfilePath)
    if err != nil {
        color.Printf("@r[%s]@{|} - bad colorfile path\n", xM)
        return fmt.Errorf("%s\n", "bad colorfile path")
    }

    pal, err := parseColors(file)

    if err != nil {
        color.Printf("@r[%s]@{|} - malformed colorfile [%s]\n", xM, err)
        return fmt.Errorf("%s\n", "malformed colorfile")
    }

    color.Printf("@g[%s]@{|}\n", checkM)

    if pal == ansiColors {}

    color.Printf("@yverifying & preprocessing colorsets@{|} :: @y[SKIP]\n")
    color.Printf("@ygenerating transpositional colorspace@{|} :: @y[SKIP]\n")

    color.Printf("@ystarting httpd on port @b%d@{|} :: ", port)
    http.HandleFunc("/kt/", transposePage)

    var portString string
    fmt.Sprintf(portString, ":%d", port)
    err = http.ListenAndServe(portString, nil)
    if err != nil {

        color.Printf("@r[%s]@{-} - run me as root!\n", xM)
        return fmt.Errorf("%s\n", "failed to start httpd")
    }

    color.Printf("@g[%s]@{-}\n", checkM)

    return nil
}

func transposePage(writer http.ResponseWriter, req *http.Request) {

    fqdn      := req.URL.Path[4:]
    targetURL := fmt.Sprintf("http://%s", fqdn)

    resp, err := http.Get(targetURL)
    if err != nil {

        io.WriteString(writer, "failed to get that page! -kt\n")
        io.WriteString(writer, targetURL)
        return
    }

    var s scanner.Scanner
    s.Init(req.Body)
    //tok := s.Scan

    resp.Body.Close()
}

func main() {

    err := ktInit("kolors", 999, "/home/kremlin/.Xresources")

    if err != nil {}
}

type errConsumer struct {
    err error
}

func (e *errConsumer) Consume(err error) {
    if e.err == nil && err != nil {
        e.err = err
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2015 Andrea Masi. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE.txt file.

// Package httph exposes functions & types usefull
// when dealing with net/http.
package httph

import (
	"log"
	"net/http"

	"gopkg.in/mgo.v2"
)

// WithCORS is a decorator function that adds relevant headers to response
// to permit CORS requests.
func WithCORS(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		fn(w, r)
	}
}

// WithSharedData is a decorator function that initializes SharedData
// for the given http.Request freeing memory when possible.
func WithSharedData(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		SharedData.init(r)
		defer SharedData.drop(r)
		fn(w, r)
	}
}

// WithMongo is a decorator function that let passed HandlerFunc
// to use a session to MongoDB.
func WithMongo(session *mgo.Session, fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		s := session.Copy()
		defer s.Close()
		SharedData.Insert(r, MongoSession, s)
		defer SharedData.Delete(r, MongoSession)
		fn(w, r)
	}
}

// WithLog is a decorator that calls Println method
// of provided logger to log received requests.
// Format is:
// <http method> <remote addr> <requested url>
func WithLog(logger *log.Logger, fn http.HandlerFunc) http.HandlerFunc {
	//TODO use constants to define format like in log package.
	return func(w http.ResponseWriter, r *http.Request) {
		logger.Println(r.Method, r.RemoteAddr, r.URL)
		fn(w, r)
	}
}

// HeaderJSON sets http header for json.
func HeaderJSON(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
}
<commit_msg>Detect X-Real-IP header when logging<commit_after>// Copyright (c) 2015 Andrea Masi. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE.txt file.

// Package httph exposes functions & types usefull
// when dealing with net/http.
package httph

import (
	"log"
	"net/http"

	"gopkg.in/mgo.v2"
)

// WithCORS is a decorator function that adds relevant headers to response
// to permit CORS requests.
func WithCORS(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		fn(w, r)
	}
}

// WithSharedData is a decorator function that initializes SharedData
// for the given http.Request freeing memory when possible.
func WithSharedData(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		SharedData.init(r)
		defer SharedData.drop(r)
		fn(w, r)
	}
}

// WithMongo is a decorator function that let passed HandlerFunc
// to use a session to MongoDB.
func WithMongo(session *mgo.Session, fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		s := session.Copy()
		defer s.Close()
		SharedData.Insert(r, MongoSession, s)
		defer SharedData.Delete(r, MongoSession)
		fn(w, r)
	}
}

// WithLog is a decorator that calls Println method
// of provided logger to log received requests.
// Format is:
// <http method> <remote addr> <requested url>
// If X-Real-IP is found in headers it is used as <remote addr>
// with (X-Real-IP) added.
func WithLog(logger *log.Logger, fn http.HandlerFunc) http.HandlerFunc {
	//TODO use constants to define format like in log package.
	return func(w http.ResponseWriter, r *http.Request) {
		remoteAddr := r.Header.Get("X-Real-IP")
		if remoteAddr == "" {
			remoteAddr = r.RemoteAddr
		} else {
			remoteAddr += " (X-Real-IP)"
		}
		logger.Println(r.Method, remoteAddr, r.URL)
		fn(w, r)
	}
}

// HeaderJSON sets http header for json.
func HeaderJSON(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
}
<|endoftext|>


<commit_before>package gsd

import (
	"crypto/tls"
	"net/http"
	"net/http/httputil"
	"strconv"
	"time"
)

type HttpsService struct {
	name string
}

func NewHttpsService() *HttpsService {
	return &HttpsService{name: "HTTPS"}
}

func (s *HttpsService) Name() string {
	return s.name
}

func (s *HttpsService) GetBanner(ip string, port int) Banner {
	banner := Banner{
		Ip:      ip,
		Port:    port,
		Service: s.Name(),
	}

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	c := &http.Client{Timeout: 5 * time.Second, Transport: tr}
	res, err := c.Get("https://" + ip + ":" + strconv.Itoa(port))
	if err != nil {
		banner.Error = err.Error()
		return banner
	}

	dump, err := httputil.DumpResponse(res, true)
	if err != nil {
		banner.Error = err.Error()
		return banner
	}

	banner.Content = string(dump)

	return banner
}
<commit_msg>HTTPS service now saves the server certificate<commit_after>package gsd

import (
	"crypto/tls"
	"encoding/base64"
	"net/http"
	"net/http/httputil"
	"strconv"
	"time"
)

type HttpsService struct {
	name string
}

func NewHttpsService() *HttpsService {
	return &HttpsService{name: "HTTPS"}
}

func (s *HttpsService) Name() string {
	return s.name
}

func (s *HttpsService) GetBanner(ip string, port int) Banner {
	banner := Banner{
		Ip:      ip,
		Port:    port,
		Service: s.Name(),
	}

	// Connect and make a GET request
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	c := &http.Client{Timeout: 5 * time.Second, Transport: tr}
	res, err := c.Get("https://" + ip + ":" + strconv.Itoa(port))
	if err != nil {
		banner.Error = err.Error()
		return banner
	}

	// Get the server certificate and base64 it
	rawCert := res.TLS.PeerCertificates[0].Raw
	b64Cert := base64.StdEncoding.EncodeToString(rawCert)

	dump, err := httputil.DumpResponse(res, true)
	if err != nil {
		banner.Error = err.Error()
		return banner
	}

	banner.Content = "---- BEGIN CERTIFICATE ----\n" + b64Cert +
		"---- END CERTIFICATE ----\n\n" + string(dump)

	return banner
}
<|endoftext|>


<commit_before>package worker

import (
	"github.com/ofux/deluge/core"
	"github.com/ofux/deluge/core/recording"
	"github.com/ofux/deluge/core/status"
	"github.com/ofux/deluge/repov2"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"time"
)

type Manager interface {
	CreateAll(jobShell *JobShell) error
	StartAll(jobShell *JobShell) error
	InterruptAll(jobShellID string) error
}

type JobShell struct {
	ID       string
	DelugeID string
}

var managerInstance Manager = &inMemoryManager{
	workers: make([]*worker, 1),
}

func GetManager() Manager {
	return managerInstance
}

type worker struct {
	ID            string
	jobShell      *JobShell
	runningDeluge *core.RunnableDeluge
	repository    repov2.Repository

	regularReportFrequency time.Duration
	finalReportRetryCount  int
	finalReportRetryDelay  time.Duration

	logger *logrus.Entry
}

func newWorker(ID string, jobShell *JobShell, repository repov2.Repository) *worker {
	return &worker{
		ID:         ID,
		jobShell:   jobShell,
		repository: repository,

		regularReportFrequency: 20 * time.Second,
		finalReportRetryCount:  3,
		finalReportRetryDelay:  10 * time.Second,

		logger: logrus.WithField("workerId", ID).WithField("jobId", jobShell.ID).WithField("delugeId", jobShell.DelugeID),
	}
}

func (w *worker) interrupt() {
	w.runningDeluge.Interrupt()
}

func (w *worker) start() error {
	dlg, err := core.NewRunnableDeluge(w.jobShell.DelugeID)
	if err != nil {
		return errors.Wrapf(err, "failed to create runnable deluge from jobShell %s (delugeId %s)", w.jobShell.ID, w.jobShell.DelugeID)
	}
	w.runningDeluge = dlg

	go func() {
		w.listenToStatusChanges()
	}()

	go func() {
		w.reportRecordsRegularly()
	}()

	dlg.Run()

	return nil
}

func (w *worker) listenToStatusChanges() {
	for newStatus := range w.runningDeluge.OnStatusChangeChan() {
		w.logger.Debugf("Received status %s", newStatus)

		report := &repov2.PersistedWorkerReport{
			WorkerID:  w.ID,
			JobID:     w.jobShell.ID,
			Status:    newStatus,
			Scenarios: make(map[string]*repov2.PersistedWorkerScenarioReport),
		}
		if newStatus == status.DelugeDoneSuccess || newStatus == status.DelugeDoneError || newStatus == status.DelugeInterrupted {
			for scenarioID, scenario := range w.runningDeluge.Scenarios {
				if scenario.Records == nil {
					continue
				}

				logger := w.logger.WithField("scenarioId", scenarioID)
				logger.Debug("Adding records of scenario")

				records, err := recording.MapHTTPRecords(scenario.Records)
				if err != nil {
					logger.WithError(err).Error("Failed to map records of worker for scenario")
					continue
				}

				report.Scenarios[scenarioID] = &repov2.PersistedWorkerScenarioReport{
					Status:            scenario.Status,
					Errors:            scenario.Errors,
					IterationDuration: scenario.IterationDuration,
					Records:           records,
				}
				logger.Debug("Added records of scenario")
			}
			w.saveWorkerReportWithRetry(report)
		} else {
			w.saveWorkerReport(report)
		}
		//TODO: tell orchestrator that this worker is done
	}
}

func (w *worker) saveWorkerReport(report *repov2.PersistedWorkerReport) {
	err := w.repository.SaveWorkerReport(report)
	if err != nil {
		w.logger.WithError(err).Error("Failed to save records of worker")
	}
	w.logger.Debug("Successfully saved records of worker")
}

func (w *worker) saveWorkerReportWithRetry(report *repov2.PersistedWorkerReport) {
	err := w.repository.SaveWorkerReport(report)

	const retryDelayMultiply = 3

	delay := w.finalReportRetryDelay
	for retry := 1; err != nil && retry <= w.finalReportRetryCount; retry++ {
		w.logger.WithError(err).Errorf("Failed to save records of worker. Retrying in %s", delay)
		time.Sleep(delay)
		err = w.repository.SaveWorkerReport(report)
		delay *= retryDelayMultiply
	}
	w.logger.Debug("Successfully saved records of worker")
}

func (w *worker) reportRecordsRegularly() {
	ticker := time.NewTicker(w.regularReportFrequency)

	allRecords := make(map[string]*recording.HTTPRecordsOverTime)

	for range ticker.C {
		snapshot, err := w.runningDeluge.GetRecordsSnapshot()
		if err != nil {
			ticker.Stop()
			break
		}
		for scenarioID, scenarioSnapshot := range snapshot {
			scenarioRecords, ok := allRecords[scenarioID]
			if !ok {
				scenarioRecords = &recording.HTTPRecordsOverTime{}
				allRecords[scenarioID] = scenarioRecords
			}
			if scenarioSnapshot.Err != nil {
				continue
			}
			scenarioRecords.Global = scenarioSnapshot.HTTPRecordsOverTimeSnapshot.Global
			for overTimeIndex, rec := range scenarioSnapshot.HTTPRecordsOverTimeSnapshot.OverTime {
				if len(scenarioRecords.OverTime) <= overTimeIndex {
					scenarioRecords.OverTime = append(scenarioRecords.OverTime, make([]*recording.HTTPRecord, overTimeIndex+1-len(scenarioRecords.OverTime))...)
				}
				scenarioRecords.OverTime[overTimeIndex] = rec
			}
		}

		report := &repov2.PersistedWorkerReport{
			WorkerID:  w.ID,
			JobID:     w.jobShell.ID,
			Scenarios: make(map[string]*repov2.PersistedWorkerScenarioReport),
		}
		for scenarioID, records := range allRecords {
			if records == nil {
				continue
			}

			logger := w.logger.WithField("scenarioId", scenarioID)

			records, err := recording.MapHTTPRecords(records)
			if err != nil {
				logger.WithError(err).Error("Failed to map records of worker for scenario")
				continue
			}

			report.Scenarios[scenarioID] = &repov2.PersistedWorkerScenarioReport{
				Records: records,
			}
		}
		w.saveWorkerReport(report)
	}
}
<commit_msg>improve logs of worker<commit_after>package worker

import (
	"github.com/ofux/deluge/core"
	"github.com/ofux/deluge/core/recording"
	"github.com/ofux/deluge/core/status"
	"github.com/ofux/deluge/repov2"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"time"
)

type Manager interface {
	CreateAll(jobShell *JobShell) error
	StartAll(jobShell *JobShell) error
	InterruptAll(jobShellID string) error
}

type JobShell struct {
	ID       string
	DelugeID string
}

var managerInstance Manager = &inMemoryManager{
	workers: make([]*worker, 1),
}

func GetManager() Manager {
	return managerInstance
}

type worker struct {
	ID            string
	jobShell      *JobShell
	runningDeluge *core.RunnableDeluge
	repository    repov2.Repository

	regularReportFrequency time.Duration
	finalReportRetryCount  int
	finalReportRetryDelay  time.Duration

	logger *logrus.Entry
}

func newWorker(ID string, jobShell *JobShell, repository repov2.Repository) *worker {
	return &worker{
		ID:         ID,
		jobShell:   jobShell,
		repository: repository,

		regularReportFrequency: 20 * time.Second,
		finalReportRetryCount:  3,
		finalReportRetryDelay:  10 * time.Second,

		logger: logrus.WithField("workerId", ID).WithField("jobId", jobShell.ID).WithField("delugeId", jobShell.DelugeID),
	}
}

func (w *worker) interrupt() {
	w.runningDeluge.Interrupt()
}

func (w *worker) start() error {
	dlg, err := core.NewRunnableDeluge(w.jobShell.DelugeID)
	if err != nil {
		return errors.Wrapf(err, "failed to create runnable deluge from jobShell %s (delugeId %s)", w.jobShell.ID, w.jobShell.DelugeID)
	}
	w.runningDeluge = dlg

	go func() {
		w.listenToStatusChanges()
	}()

	go func() {
		w.reportRecordsRegularly()
	}()

	dlg.Run()

	return nil
}

func (w *worker) listenToStatusChanges() {
	for newStatus := range w.runningDeluge.OnStatusChangeChan() {
		w.logger.Debugf("Received status %s", newStatus)

		report := &repov2.PersistedWorkerReport{
			WorkerID:  w.ID,
			JobID:     w.jobShell.ID,
			Status:    newStatus,
			Scenarios: make(map[string]*repov2.PersistedWorkerScenarioReport),
		}
		if newStatus == status.DelugeDoneSuccess || newStatus == status.DelugeDoneError || newStatus == status.DelugeInterrupted {
			for scenarioID, scenario := range w.runningDeluge.Scenarios {
				logger := w.logger.WithField("scenarioId", scenarioID)
				logger.Debug("Adding records of scenario")

				if scenario.Records == nil {
					logger.Debug("Scenario has no record")
					continue
				}

				records, err := recording.MapHTTPRecords(scenario.Records)
				if err != nil {
					logger.WithError(err).Error("Failed to map records of worker for scenario")
					continue
				}

				report.Scenarios[scenarioID] = &repov2.PersistedWorkerScenarioReport{
					Status:            scenario.Status,
					Errors:            scenario.Errors,
					IterationDuration: scenario.IterationDuration,
					Records:           records,
				}
				logger.Debug("Added records of scenario")
			}
			w.saveWorkerReportWithRetry(report)
		} else {
			w.saveWorkerReport(report)
		}
		//TODO: tell orchestrator that this worker is done
	}
}

func (w *worker) saveWorkerReport(report *repov2.PersistedWorkerReport) {
	err := w.repository.SaveWorkerReport(report)
	if err != nil {
		w.logger.WithError(err).Error("Failed to save records of worker")
	} else {
		w.logger.Debug("Successfully saved records of worker")
	}
}

func (w *worker) saveWorkerReportWithRetry(report *repov2.PersistedWorkerReport) {
	err := w.repository.SaveWorkerReport(report)

	const retryDelayMultiply = 3

	delay := w.finalReportRetryDelay
	for retry := 1; err != nil && retry <= w.finalReportRetryCount; retry++ {
		w.logger.WithError(err).Errorf("Failed to save records of worker. Retrying in %s", delay)
		time.Sleep(delay)
		err = w.repository.SaveWorkerReport(report)
		delay *= retryDelayMultiply
	}

	if err != nil {
		w.logger.WithError(err).Error("Failed to save records of worker")
	} else {
		w.logger.Debug("Successfully saved records of worker")
	}
}

func (w *worker) reportRecordsRegularly() {
	ticker := time.NewTicker(w.regularReportFrequency)

	allRecords := make(map[string]*recording.HTTPRecordsOverTime)

	for range ticker.C {
		snapshot, err := w.runningDeluge.GetRecordsSnapshot()
		if err != nil {
			ticker.Stop()
			break
		}
		for scenarioID, scenarioSnapshot := range snapshot {
			scenarioRecords, ok := allRecords[scenarioID]
			if !ok {
				scenarioRecords = &recording.HTTPRecordsOverTime{}
				allRecords[scenarioID] = scenarioRecords
			}
			if scenarioSnapshot.Err != nil || scenarioSnapshot.HTTPRecordsOverTimeSnapshot == nil {
				continue
			}
			scenarioRecords.Global = scenarioSnapshot.HTTPRecordsOverTimeSnapshot.Global
			for overTimeIndex, rec := range scenarioSnapshot.HTTPRecordsOverTimeSnapshot.OverTime {
				if len(scenarioRecords.OverTime) <= overTimeIndex {
					scenarioRecords.OverTime = append(scenarioRecords.OverTime, make([]*recording.HTTPRecord, overTimeIndex+1-len(scenarioRecords.OverTime))...)
				}
				scenarioRecords.OverTime[overTimeIndex] = rec
			}
		}

		report := &repov2.PersistedWorkerReport{
			WorkerID:  w.ID,
			JobID:     w.jobShell.ID,
			Scenarios: make(map[string]*repov2.PersistedWorkerScenarioReport),
		}
		for scenarioID, records := range allRecords {
			if records == nil {
				continue
			}

			logger := w.logger.WithField("scenarioId", scenarioID)

			records, err := recording.MapHTTPRecords(records)
			if err != nil {
				logger.WithError(err).Error("Failed to map records of worker for scenario")
				continue
			}

			report.Scenarios[scenarioID] = &repov2.PersistedWorkerScenarioReport{
				Records: records,
			}
		}
		w.saveWorkerReport(report)
	}
}
<|endoftext|>


<commit_before>package worker

import (
	"errors"
	"github.com/Sirupsen/logrus"
	"sync"
)

/*
Worker holds desired number of child workers when Run is called.
*/
type Worker struct {
	jobReceiver chan func()
	mutex       *sync.Mutex
	isRunning   bool
}

/*
New is a helper function that construct and return new Worker instance.
*/
func New() *Worker {
	return &Worker{
		jobReceiver: make(chan func(), 100),
		mutex:       &sync.Mutex{},
		isRunning:   false,
	}
}

/*
Run creates as many child workers as specified and start those child workers.
First argument, cancel channel, can be context.Context.Done to propagate upstream status change.
*/
func (worker *Worker) Run(cancel <-chan struct{}, workerNum uint) error {
	logrus.Infof("start workers")
	worker.mutex.Lock()
	defer worker.mutex.Unlock()

	if worker.isRunning == true {
		return errors.New("workers are already running")
	}

	var i uint
	for i = 1; i <= workerNum; i++ {
		go worker.runChild(cancel, i)
	}
	worker.isRunning = true

	// update status to false on cancellation
	go func() {
		<-cancel
		worker.isRunning = false
	}()

	return nil
}

func (worker *Worker) runChild(cancel <-chan struct{}, workerId uint) {
	logrus.Infof("start worker id: %d.", workerId)

	for {
		select {
		case <-cancel:
			logrus.Infof("stopping worker id: %d", workerId)
			return
		case job := <-worker.jobReceiver:
			logrus.Debugf("receiving job on worker: %d", workerId)
			// To avoid given job's panic affect later jobs, wrap them with recover.
			func() {
				defer func() {
					if r := recover(); r != nil {
						logrus.Warnf("panic in given job. recovered: %#v", r)
					}
				}()
				job()
			}()
		}
	}
}

/*
IsRunning returns current status of worker.
*/
func (worker *Worker) IsRunning() bool {
	return worker.isRunning
}

/*
EnqueueJob appends new job to be executed.
*/
func (worker *Worker) EnqueueJob(job func()) {
	worker.jobReceiver <- job
}
<commit_msg>Print stack trace on panic<commit_after>package worker

import (
	"errors"
	"github.com/Sirupsen/logrus"
	"runtime"
	"sync"
)

/*
Worker holds desired number of child workers when Run is called.
*/
type Worker struct {
	jobReceiver chan func()
	mutex       *sync.Mutex
	isRunning   bool
}

/*
New is a helper function that construct and return new Worker instance.
*/
func New() *Worker {
	return &Worker{
		jobReceiver: make(chan func(), 100),
		mutex:       &sync.Mutex{},
		isRunning:   false,
	}
}

/*
Run creates as many child workers as specified and start those child workers.
First argument, cancel channel, can be context.Context.Done to propagate upstream status change.
*/
func (worker *Worker) Run(cancel <-chan struct{}, workerNum uint) error {
	logrus.Infof("start workers")
	worker.mutex.Lock()
	defer worker.mutex.Unlock()

	if worker.isRunning == true {
		return errors.New("workers are already running")
	}

	var i uint
	for i = 1; i <= workerNum; i++ {
		go worker.runChild(cancel, i)
	}
	worker.isRunning = true

	// update status to false on cancellation
	go func() {
		<-cancel
		worker.isRunning = false
	}()

	return nil
}

func (worker *Worker) runChild(cancel <-chan struct{}, workerId uint) {
	logrus.Infof("start worker id: %d.", workerId)

	for {
		select {
		case <-cancel:
			logrus.Infof("stopping worker id: %d", workerId)
			return
		case job := <-worker.jobReceiver:
			logrus.Debugf("receiving job on worker: %d", workerId)
			// To avoid given job's panic affect later jobs, wrap them with recover.
			func() {
				defer func() {
					if r := recover(); r != nil {
						logrus.Warnf("panic in given job. recovered: %#v", r)

						// Display stack trace
						for depth := 0; ; depth++ {
							_, src, line, ok := runtime.Caller(depth)
							if !ok {
								break
							}
							logrus.Warnf(" -> depth:%d. file:%s. line:%d.", depth, src, line)
						}
					}

				}()
				job()
			}()
		}
	}
}

/*
IsRunning returns current status of worker.
*/
func (worker *Worker) IsRunning() bool {
	return worker.isRunning
}

/*
EnqueueJob appends new job to be executed.
*/
func (worker *Worker) EnqueueJob(job func()) {
	worker.jobReceiver <- job
}
<|endoftext|>


<commit_before>// Package grace allows for gracefully waiting for a listener to
// finish serving it's active requests.
package grace

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	// This error is returned by Inherits() when we're not inheriting any fds.
	ErrNotInheriting = errors.New("no inherited listeners")

	// This error is returned by Listener.Accept() when Close is in progress.
	ErrAlreadyClosed = errors.New("already closed")

	// Time in the past to trigger immediate deadline.
	timeInPast = time.Date(1983, time.November, 6, 0, 0, 0, 0, time.UTC)
)

const (
	// Used to indicate a graceful restart in the new process.
	envCountKey       = "LISTEN_FDS"
	envCountKeyPrefix = envCountKey + "="

	// The error returned by the standard library when the socket is closed.
	errClosed = "use of closed network connection"
)

// A Listener providing a graceful Close process and can be sent
// across processes using the underlying File descriptor.
type Listener interface {
	net.Listener

	// Will return the underlying file representing this Listener.
	File() (f *os.File, err error)
}

type listener struct {
	Listener
	closed      bool
	closedMutex sync.RWMutex
	wg          sync.WaitGroup
}

type deadliner interface {
	SetDeadline(t time.Time) error
}

// Allows for us to notice when the connection is closed.
type conn struct {
	net.Conn
	wg *sync.WaitGroup
}

func (c conn) Close() error {
	defer c.wg.Done()
	return c.Conn.Close()
}

// Wraps an existing File listener to provide a graceful Close() process.
func NewListener(l Listener) Listener {
	return &listener{Listener: l}
}

func (l *listener) Close() error {
	l.closedMutex.Lock()
	l.closed = true
	l.closedMutex.Unlock()

	var err error
	// Init provided sockets dont actually close so we trigger Accept to return
	// by setting the deadline.
	if os.Getppid() == 1 {
		if ld, ok := l.Listener.(deadliner); ok {
			err = ld.SetDeadline(timeInPast)
		} else {
			fmt.Fprintln(os.Stderr, "init activated server did not have SetDeadline")
		}
	} else {
		err = l.Listener.Close()
	}
	l.wg.Wait()
	return err
}

func (l *listener) Accept() (net.Conn, error) {
	// Presume we'll accept and decrement in defer if we don't. If we did this
	// after a successful accept we would have a race condition where we may end
	// up incorrectly shutting down between the time we do a successful accept
	// and the increment.
	var c net.Conn
	l.wg.Add(1)
	defer func() {
		// If we didn't accept, we decrement our presumptuous count above.
		if c == nil {
			l.wg.Done()
		}
	}()

	l.closedMutex.RLock()
	if l.closed {
		l.closedMutex.RUnlock()
		return nil, ErrAlreadyClosed
	}
	l.closedMutex.RUnlock()

	c, err := l.Listener.Accept()
	if err != nil {
		if strings.HasSuffix(err.Error(), errClosed) {
			return nil, ErrAlreadyClosed
		}

		// We use SetDeadline above to trigger Accept to return when we're trying
		// to handoff to a child as part of our restart process. In this scenario
		// we want to treat the timeout the same as a Close.
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			l.closedMutex.RLock()
			if l.closed {
				l.closedMutex.RUnlock()
				return nil, ErrAlreadyClosed
			}
			l.closedMutex.RUnlock()
		}
		return nil, err
	}
	return conn{Conn: c, wg: &l.wg}, nil
}

// Wait for signals to gracefully terminate or restart the process.
func Wait(listeners []Listener) (err error) {
	ch := make(chan os.Signal, 2)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR2)
	for {
		sig := <-ch
		switch sig {
		case syscall.SIGTERM:
			var wg sync.WaitGroup
			wg.Add(len(listeners))
			for _, l := range listeners {
				go func(l Listener) {
					cErr := l.Close()
					if cErr != nil {
						err = cErr
					}
					wg.Done()
				}(l)
			}
			wg.Wait()
			return
		case syscall.SIGUSR2:
			rErr := Restart(listeners)
			if rErr != nil {
				return rErr
			}
		}
	}
}

// Try to inherit listeners from the parent process.
func Inherit() (listeners []Listener, err error) {
	countStr := os.Getenv(envCountKey)
	if countStr == "" {
		return nil, ErrNotInheriting
	}
	count, err := strconv.Atoi(countStr)
	if err != nil {
		return nil, err
	}
	// If we are inheriting, the listeners will begin at fd 3
	for i := 3; i < 3+count; i++ {
		file := os.NewFile(uintptr(i), "listener")
		tmp, err := net.FileListener(file)
		file.Close()
		if err != nil {
			return nil, err
		}
		l := tmp.(Listener)
		listeners = append(listeners, NewListener(l))
	}
	return
}

// Start the Close process in the parent. This does not wait for the
// parent to close and simply sends it the TERM signal.
func CloseParent() error {
	ppid := os.Getppid()
	if ppid == 1 { // init provided sockets, for example systemd
		return nil
	}
	return syscall.Kill(ppid, syscall.SIGTERM)
}

// Restart the process passing the given listeners to the new process.
func Restart(listeners []Listener) (err error) {
	if len(listeners) == 0 {
		return errors.New("restart must be given listeners.")
	}
	files := make([]*os.File, len(listeners))
	for i, l := range listeners {
		files[i], err = l.File()
		if err != nil {
			return err
		}
		defer files[i].Close()
		syscall.CloseOnExec(int(files[i].Fd()))
	}
	argv0, err := exec.LookPath(os.Args[0])
	if err != nil {
		return err
	}
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	var env []string
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, envCountKeyPrefix) {
			env = append(env, v)
		}
	}
	env = append(env, fmt.Sprintf("%s%d", envCountKeyPrefix, len(listeners)))

	allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...)
	_, err = os.StartProcess(argv0, os.Args, &os.ProcAttr{
		Dir:   wd,
		Env:   env,
		Files: allFiles,
	})
	return err
}
<commit_msg>use defer for wg.Done to ensure its called<commit_after>// Package grace allows for gracefully waiting for a listener to
// finish serving it's active requests.
package grace

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	// This error is returned by Inherits() when we're not inheriting any fds.
	ErrNotInheriting = errors.New("no inherited listeners")

	// This error is returned by Listener.Accept() when Close is in progress.
	ErrAlreadyClosed = errors.New("already closed")

	// Time in the past to trigger immediate deadline.
	timeInPast = time.Date(1983, time.November, 6, 0, 0, 0, 0, time.UTC)
)

const (
	// Used to indicate a graceful restart in the new process.
	envCountKey       = "LISTEN_FDS"
	envCountKeyPrefix = envCountKey + "="

	// The error returned by the standard library when the socket is closed.
	errClosed = "use of closed network connection"
)

// A Listener providing a graceful Close process and can be sent
// across processes using the underlying File descriptor.
type Listener interface {
	net.Listener

	// Will return the underlying file representing this Listener.
	File() (f *os.File, err error)
}

type listener struct {
	Listener
	closed      bool
	closedMutex sync.RWMutex
	wg          sync.WaitGroup
}

type deadliner interface {
	SetDeadline(t time.Time) error
}

// Allows for us to notice when the connection is closed.
type conn struct {
	net.Conn
	wg *sync.WaitGroup
}

func (c conn) Close() error {
	defer c.wg.Done()
	return c.Conn.Close()
}

// Wraps an existing File listener to provide a graceful Close() process.
func NewListener(l Listener) Listener {
	return &listener{Listener: l}
}

func (l *listener) Close() error {
	l.closedMutex.Lock()
	l.closed = true
	l.closedMutex.Unlock()

	var err error
	// Init provided sockets dont actually close so we trigger Accept to return
	// by setting the deadline.
	if os.Getppid() == 1 {
		if ld, ok := l.Listener.(deadliner); ok {
			err = ld.SetDeadline(timeInPast)
		} else {
			fmt.Fprintln(os.Stderr, "init activated server did not have SetDeadline")
		}
	} else {
		err = l.Listener.Close()
	}
	l.wg.Wait()
	return err
}

func (l *listener) Accept() (net.Conn, error) {
	// Presume we'll accept and decrement in defer if we don't. If we did this
	// after a successful accept we would have a race condition where we may end
	// up incorrectly shutting down between the time we do a successful accept
	// and the increment.
	var c net.Conn
	l.wg.Add(1)
	defer func() {
		// If we didn't accept, we decrement our presumptuous count above.
		if c == nil {
			l.wg.Done()
		}
	}()

	l.closedMutex.RLock()
	if l.closed {
		l.closedMutex.RUnlock()
		return nil, ErrAlreadyClosed
	}
	l.closedMutex.RUnlock()

	c, err := l.Listener.Accept()
	if err != nil {
		if strings.HasSuffix(err.Error(), errClosed) {
			return nil, ErrAlreadyClosed
		}

		// We use SetDeadline above to trigger Accept to return when we're trying
		// to handoff to a child as part of our restart process. In this scenario
		// we want to treat the timeout the same as a Close.
		if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
			l.closedMutex.RLock()
			if l.closed {
				l.closedMutex.RUnlock()
				return nil, ErrAlreadyClosed
			}
			l.closedMutex.RUnlock()
		}
		return nil, err
	}
	return conn{Conn: c, wg: &l.wg}, nil
}

// Wait for signals to gracefully terminate or restart the process.
func Wait(listeners []Listener) (err error) {
	ch := make(chan os.Signal, 2)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGUSR2)
	for {
		sig := <-ch
		switch sig {
		case syscall.SIGTERM:
			var wg sync.WaitGroup
			wg.Add(len(listeners))
			for _, l := range listeners {
				go func(l Listener) {
					defer wg.Done()
					cErr := l.Close()
					if cErr != nil {
						err = cErr
					}
				}(l)
			}
			wg.Wait()
			return
		case syscall.SIGUSR2:
			rErr := Restart(listeners)
			if rErr != nil {
				return rErr
			}
		}
	}
}

// Try to inherit listeners from the parent process.
func Inherit() (listeners []Listener, err error) {
	countStr := os.Getenv(envCountKey)
	if countStr == "" {
		return nil, ErrNotInheriting
	}
	count, err := strconv.Atoi(countStr)
	if err != nil {
		return nil, err
	}
	// If we are inheriting, the listeners will begin at fd 3
	for i := 3; i < 3+count; i++ {
		file := os.NewFile(uintptr(i), "listener")
		tmp, err := net.FileListener(file)
		file.Close()
		if err != nil {
			return nil, err
		}
		l := tmp.(Listener)
		listeners = append(listeners, NewListener(l))
	}
	return
}

// Start the Close process in the parent. This does not wait for the
// parent to close and simply sends it the TERM signal.
func CloseParent() error {
	ppid := os.Getppid()
	if ppid == 1 { // init provided sockets, for example systemd
		return nil
	}
	return syscall.Kill(ppid, syscall.SIGTERM)
}

// Restart the process passing the given listeners to the new process.
func Restart(listeners []Listener) (err error) {
	if len(listeners) == 0 {
		return errors.New("restart must be given listeners.")
	}
	files := make([]*os.File, len(listeners))
	for i, l := range listeners {
		files[i], err = l.File()
		if err != nil {
			return err
		}
		defer files[i].Close()
		syscall.CloseOnExec(int(files[i].Fd()))
	}
	argv0, err := exec.LookPath(os.Args[0])
	if err != nil {
		return err
	}
	wd, err := os.Getwd()
	if err != nil {
		return err
	}

	var env []string
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, envCountKeyPrefix) {
			env = append(env, v)
		}
	}
	env = append(env, fmt.Sprintf("%s%d", envCountKeyPrefix, len(listeners)))

	allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...)
	_, err = os.StartProcess(argv0, os.Args, &os.ProcAttr{
		Dir:   wd,
		Env:   env,
		Files: allFiles,
	})
	return err
}
<|endoftext|>


<commit_before>package docker

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

// A Graph is a store for versioned filesystem images and the relationship between them.
type Graph struct {
	Root       string
	idIndex    *TruncIndex
	httpClient *http.Client
}

// NewGraph instantiates a new graph at the given root path in the filesystem.
// `root` will be created if it doesn't exist.
func NewGraph(root string) (*Graph, error) {
	abspath, err := filepath.Abs(root)
	if err != nil {
		return nil, err
	}
	// Create the root directory if it doesn't exists
	if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	graph := &Graph{
		Root:    abspath,
		idIndex: NewTruncIndex(),
	}
	if err := graph.restore(); err != nil {
		return nil, err
	}
	return graph, nil
}

func (graph *Graph) restore() error {
	dir, err := ioutil.ReadDir(graph.Root)
	if err != nil {
		return err
	}
	for _, v := range dir {
		id := v.Name()
		graph.idIndex.Add(id)
	}
	return nil
}

// FIXME: Implement error subclass instead of looking at the error text
// Note: This is the way golang implements os.IsNotExists on Plan9
func (graph *Graph) IsNotExist(err error) bool {
	return err != nil && strings.Contains(err.Error(), "does not exist")
}

// Exists returns true if an image is registered at the given id.
// If the image doesn't exist or if an error is encountered, false is returned.
func (graph *Graph) Exists(id string) bool {
	if _, err := graph.Get(id); err != nil {
		return false
	}
	return true
}

// Get returns the image with the given id, or an error if the image doesn't exist.
func (graph *Graph) Get(name string) (*Image, error) {
	id, err := graph.idIndex.Get(name)
	if err != nil {
		return nil, err
	}
	// FIXME: return nil when the image doesn't exist, instead of an error
	img, err := LoadImage(graph.imageRoot(id))
	if err != nil {
		return nil, err
	}
	if img.Id != id {
		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id)
	}
	img.graph = graph
	return img, nil
}

// Create creates a new image and registers it in the graph.
func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
	img := &Image{
		Id:            GenerateId(),
		Comment:       comment,
		Created:       time.Now(),
		DockerVersion: VERSION,
		Author:        author,
		Config:        config,
	}
	if container != nil {
		img.Parent = container.Image
		img.Container = container.Id
		img.ContainerConfig = *container.Config
	}
	if err := graph.Register(layerData, img); err != nil {
		return nil, err
	}
	img.Checksum()
	return img, nil
}

// Register imports a pre-existing image into the graph.
// FIXME: pass img as first argument
func (graph *Graph) Register(layerData Archive, img *Image) error {
	if err := ValidateId(img.Id); err != nil {
		return err
	}
	// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
	if graph.Exists(img.Id) {
		return fmt.Errorf("Image %s already exists", img.Id)
	}
	tmp, err := graph.Mktemp("")
	defer os.RemoveAll(tmp)
	if err != nil {
		return fmt.Errorf("Mktemp failed: %s", err)
	}
	if err := StoreImage(img, layerData, tmp); err != nil {
		return err
	}
	// Commit
	if err := os.Rename(tmp, graph.imageRoot(img.Id)); err != nil {
		return err
	}
	img.graph = graph
	graph.idIndex.Add(img.Id)
	return nil
}

// TempLayerArchive creates a temporary archive of the given image's filesystem layer.
//   The archive is stored on disk and will be automatically deleted as soon as has been read.
//   If output is not nil, a human-readable progress bar will be written to it.
//   FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
func (graph *Graph) TempLayerArchive(id string, compression Compression, output io.Writer) (*TempArchive, error) {
	image, err := graph.Get(id)
	if err != nil {
		return nil, err
	}
	tmp, err := graph.tmp()
	if err != nil {
		return nil, err
	}
	archive, err := image.TarLayer(compression)
	if err != nil {
		return nil, err
	}
	return NewTempArchive(ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)"), tmp.Root)
}

// Mktemp creates a temporary sub-directory inside the graph's filesystem.
func (graph *Graph) Mktemp(id string) (string, error) {
	if id == "" {
		id = GenerateId()
	}
	tmp, err := graph.tmp()
	if err != nil {
		return "", fmt.Errorf("Couldn't create temp: %s", err)
	}
	if tmp.Exists(id) {
		return "", fmt.Errorf("Image %d already exists", id)
	}
	return tmp.imageRoot(id), nil
}

func (graph *Graph) tmp() (*Graph, error) {
	return NewGraph(path.Join(graph.Root, ":tmp:"))
}

// Check if given error is "not empty".
// Note: this is the way golang does it internally with os.IsNotExists.
func isNotEmpty(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *os.PathError:
		err = pe.Err
	case *os.LinkError:
		err = pe.Err
	}
	return strings.Contains(err.Error(), " not empty")
}

// Delete atomically removes an image from the graph.
func (graph *Graph) Delete(name string) error {
	id, err := graph.idIndex.Get(name)
	if err != nil {
		return err
	}
	tmp, err := graph.Mktemp("")
	if err != nil {
		return err
	}
	graph.idIndex.Delete(id)
	err = os.Rename(graph.imageRoot(id), tmp)
	if err != nil {
		return err
	}
	return os.RemoveAll(tmp)
}

// Map returns a list of all images in the graph, addressable by ID.
func (graph *Graph) Map() (map[string]*Image, error) {
	// FIXME: this should replace All()
	all, err := graph.All()
	if err != nil {
		return nil, err
	}
	images := make(map[string]*Image, len(all))
	for _, image := range all {
		images[image.Id] = image
	}
	return images, nil
}

// All returns a list of all images in the graph.
func (graph *Graph) All() ([]*Image, error) {
	var images []*Image
	err := graph.WalkAll(func(image *Image) {
		images = append(images, image)
	})
	return images, err
}

// WalkAll iterates over each image in the graph, and passes it to a handler.
// The walking order is undetermined.
func (graph *Graph) WalkAll(handler func(*Image)) error {
	files, err := ioutil.ReadDir(graph.Root)
	if err != nil {
		return err
	}
	for _, st := range files {
		if img, err := graph.Get(st.Name()); err != nil {
			// Skip image
			continue
		} else if handler != nil {
			handler(img)
		}
	}
	return nil
}

// ByParent returns a lookup table of images by their parent.
// If an image of id ID has 3 children images, then the value for key ID
// will be a list of 3 images.
// If an image has no children, it will not have an entry in the table.
func (graph *Graph) ByParent() (map[string][]*Image, error) {
	byParent := make(map[string][]*Image)
	err := graph.WalkAll(func(image *Image) {
		image, err := graph.Get(image.Parent)
		if err != nil {
			return
		}
		if children, exists := byParent[image.Parent]; exists {
			byParent[image.Parent] = []*Image{image}
		} else {
			byParent[image.Parent] = append(children, image)
		}
	})
	return byParent, err
}

// Heads returns all heads in the graph, keyed by id.
// A head is an image which is not the parent of another image in the graph.
func (graph *Graph) Heads() (map[string]*Image, error) {
	heads := make(map[string]*Image)
	byParent, err := graph.ByParent()
	if err != nil {
		return nil, err
	}
	err = graph.WalkAll(func(image *Image) {
		// If it's not in the byParent lookup table, then
		// it's not a parent -> so it's a head!
		if _, exists := byParent[image.Id]; !exists {
			heads[image.Id] = image
		}
	})
	return heads, err
}

func (graph *Graph) imageRoot(id string) string {
	return path.Join(graph.Root, id)
}
<commit_msg>fix ByParent<commit_after>package docker

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

// A Graph is a store for versioned filesystem images and the relationship between them.
type Graph struct {
	Root       string
	idIndex    *TruncIndex
	httpClient *http.Client
}

// NewGraph instantiates a new graph at the given root path in the filesystem.
// `root` will be created if it doesn't exist.
func NewGraph(root string) (*Graph, error) {
	abspath, err := filepath.Abs(root)
	if err != nil {
		return nil, err
	}
	// Create the root directory if it doesn't exists
	if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	graph := &Graph{
		Root:    abspath,
		idIndex: NewTruncIndex(),
	}
	if err := graph.restore(); err != nil {
		return nil, err
	}
	return graph, nil
}

func (graph *Graph) restore() error {
	dir, err := ioutil.ReadDir(graph.Root)
	if err != nil {
		return err
	}
	for _, v := range dir {
		id := v.Name()
		graph.idIndex.Add(id)
	}
	return nil
}

// FIXME: Implement error subclass instead of looking at the error text
// Note: This is the way golang implements os.IsNotExists on Plan9
func (graph *Graph) IsNotExist(err error) bool {
	return err != nil && strings.Contains(err.Error(), "does not exist")
}

// Exists returns true if an image is registered at the given id.
// If the image doesn't exist or if an error is encountered, false is returned.
func (graph *Graph) Exists(id string) bool {
	if _, err := graph.Get(id); err != nil {
		return false
	}
	return true
}

// Get returns the image with the given id, or an error if the image doesn't exist.
func (graph *Graph) Get(name string) (*Image, error) {
	id, err := graph.idIndex.Get(name)
	if err != nil {
		return nil, err
	}
	// FIXME: return nil when the image doesn't exist, instead of an error
	img, err := LoadImage(graph.imageRoot(id))
	if err != nil {
		return nil, err
	}
	if img.Id != id {
		return nil, fmt.Errorf("Image stored at '%s' has wrong id '%s'", id, img.Id)
	}
	img.graph = graph
	return img, nil
}

// Create creates a new image and registers it in the graph.
func (graph *Graph) Create(layerData Archive, container *Container, comment, author string, config *Config) (*Image, error) {
	img := &Image{
		Id:            GenerateId(),
		Comment:       comment,
		Created:       time.Now(),
		DockerVersion: VERSION,
		Author:        author,
		Config:        config,
	}
	if container != nil {
		img.Parent = container.Image
		img.Container = container.Id
		img.ContainerConfig = *container.Config
	}
	if err := graph.Register(layerData, img); err != nil {
		return nil, err
	}
	img.Checksum()
	return img, nil
}

// Register imports a pre-existing image into the graph.
// FIXME: pass img as first argument
func (graph *Graph) Register(layerData Archive, img *Image) error {
	if err := ValidateId(img.Id); err != nil {
		return err
	}
	// (This is a convenience to save time. Race conditions are taken care of by os.Rename)
	if graph.Exists(img.Id) {
		return fmt.Errorf("Image %s already exists", img.Id)
	}
	tmp, err := graph.Mktemp("")
	defer os.RemoveAll(tmp)
	if err != nil {
		return fmt.Errorf("Mktemp failed: %s", err)
	}
	if err := StoreImage(img, layerData, tmp); err != nil {
		return err
	}
	// Commit
	if err := os.Rename(tmp, graph.imageRoot(img.Id)); err != nil {
		return err
	}
	img.graph = graph
	graph.idIndex.Add(img.Id)
	return nil
}

// TempLayerArchive creates a temporary archive of the given image's filesystem layer.
//   The archive is stored on disk and will be automatically deleted as soon as has been read.
//   If output is not nil, a human-readable progress bar will be written to it.
//   FIXME: does this belong in Graph? How about MktempFile, let the caller use it for archives?
func (graph *Graph) TempLayerArchive(id string, compression Compression, output io.Writer) (*TempArchive, error) {
	image, err := graph.Get(id)
	if err != nil {
		return nil, err
	}
	tmp, err := graph.tmp()
	if err != nil {
		return nil, err
	}
	archive, err := image.TarLayer(compression)
	if err != nil {
		return nil, err
	}
	return NewTempArchive(ProgressReader(ioutil.NopCloser(archive), 0, output, "Buffering to disk %v/%v (%v)"), tmp.Root)
}

// Mktemp creates a temporary sub-directory inside the graph's filesystem.
func (graph *Graph) Mktemp(id string) (string, error) {
	if id == "" {
		id = GenerateId()
	}
	tmp, err := graph.tmp()
	if err != nil {
		return "", fmt.Errorf("Couldn't create temp: %s", err)
	}
	if tmp.Exists(id) {
		return "", fmt.Errorf("Image %d already exists", id)
	}
	return tmp.imageRoot(id), nil
}

func (graph *Graph) tmp() (*Graph, error) {
	return NewGraph(path.Join(graph.Root, ":tmp:"))
}

// Check if given error is "not empty".
// Note: this is the way golang does it internally with os.IsNotExists.
func isNotEmpty(err error) bool {
	switch pe := err.(type) {
	case nil:
		return false
	case *os.PathError:
		err = pe.Err
	case *os.LinkError:
		err = pe.Err
	}
	return strings.Contains(err.Error(), " not empty")
}

// Delete atomically removes an image from the graph.
func (graph *Graph) Delete(name string) error {
	id, err := graph.idIndex.Get(name)
	if err != nil {
		return err
	}
	tmp, err := graph.Mktemp("")
	if err != nil {
		return err
	}
	graph.idIndex.Delete(id)
	err = os.Rename(graph.imageRoot(id), tmp)
	if err != nil {
		return err
	}
	return os.RemoveAll(tmp)
}

// Map returns a list of all images in the graph, addressable by ID.
func (graph *Graph) Map() (map[string]*Image, error) {
	// FIXME: this should replace All()
	all, err := graph.All()
	if err != nil {
		return nil, err
	}
	images := make(map[string]*Image, len(all))
	for _, image := range all {
		images[image.Id] = image
	}
	return images, nil
}

// All returns a list of all images in the graph.
func (graph *Graph) All() ([]*Image, error) {
	var images []*Image
	err := graph.WalkAll(func(image *Image) {
		images = append(images, image)
	})
	return images, err
}

// WalkAll iterates over each image in the graph, and passes it to a handler.
// The walking order is undetermined.
func (graph *Graph) WalkAll(handler func(*Image)) error {
	files, err := ioutil.ReadDir(graph.Root)
	if err != nil {
		return err
	}
	for _, st := range files {
		if img, err := graph.Get(st.Name()); err != nil {
			// Skip image
			continue
		} else if handler != nil {
			handler(img)
		}
	}
	return nil
}

// ByParent returns a lookup table of images by their parent.
// If an image of id ID has 3 children images, then the value for key ID
// will be a list of 3 images.
// If an image has no children, it will not have an entry in the table.
func (graph *Graph) ByParent() (map[string][]*Image, error) {
	byParent := make(map[string][]*Image)
	err := graph.WalkAll(func(image *Image) {
		parent, err := graph.Get(image.Parent)
		if err != nil {
			return
		}
		if children, exists := byParent[parent.Id]; exists {
			byParent[parent.Id] = []*Image{image}
		} else {
			byParent[parent.Id] = append(children, image)
		}
	})
	return byParent, err
}

// Heads returns all heads in the graph, keyed by id.
// A head is an image which is not the parent of another image in the graph.
func (graph *Graph) Heads() (map[string]*Image, error) {
	heads := make(map[string]*Image)
	byParent, err := graph.ByParent()
	if err != nil {
		return nil, err
	}
	err = graph.WalkAll(func(image *Image) {
		// If it's not in the byParent lookup table, then
		// it's not a parent -> so it's a head!
		if _, exists := byParent[image.Id]; !exists {
			heads[image.Id] = image
		}
	})
	return heads, err
}

func (graph *Graph) imageRoot(id string) string {
	return path.Join(graph.Root, id)
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package quota

import "sync"

type multiLocker struct {
	m   map[string]*sync.Mutex
	mut sync.Mutex
}

func (l *multiLocker) Lock(name string) {
	l.mut.Lock()
	mutex, ok := l.m[name]
	if !ok {
		mutex = new(sync.Mutex)
		l.m[name] = mutex
	}
	l.mut.Unlock()
	mutex.Lock()
}

func (l *multiLocker) Unlock(name string) {
	l.mut.Lock()
	defer l.mut.Unlock()
	l.m[name].Unlock()
}
<commit_msg>quota/lock: don't use defer on Unlock<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package quota

import "sync"

type multiLocker struct {
	m   map[string]*sync.Mutex
	mut sync.Mutex
}

func (l *multiLocker) Lock(name string) {
	l.mut.Lock()
	mutex, ok := l.m[name]
	if !ok {
		mutex = new(sync.Mutex)
		l.m[name] = mutex
	}
	l.mut.Unlock()
	mutex.Lock()
}

func (l *multiLocker) Unlock(name string) {
	l.mut.Lock()
	mutex := l.m[name]
	l.mut.Unlock()
	mutex.Unlock()
}
<|endoftext|>


<commit_before>// Copyright 2014 Dynamic Design. All rights reserved.

package s3

import (
	// "os"
	// "path"
	"strings"

	"github.com/dynamic-design/storage"
	"github.com/dynamic-design/storage/driver"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
)

type Driver struct{}

func (d *Driver) Open(source string) (driver.Bucket, error) {
	flds := map[string]string{}
	for _, fld := range strings.Fields(source) {
		toks := strings.SplitN(fld, "=", 2)
		flds[toks[0]] = toks[1]
	}
	c := s3.New(aws.Auth{
		AccessKey: flds["key"],
		SecretKey: flds["secret"],
	}, aws.Region{
		S3Endpoint: flds["endpoint"],
	})

	return &Bucket{
		Bucket: c.Bucket(flds["bucket"]),
	}, nil
}

type Bucket struct {
	*s3.Bucket
}

func (b *Bucket) Create(name string) (driver.File, error) {
	return &File{
		b:    b,
		name: name,
		mode: 1,
	}, nil
}

func (b *Bucket) Open(name string) (driver.File, error) {
	return &File{
		b:    b,
		name: name,
		mode: 0,
	}, nil
}

func init() {
	storage.Register("s3", &Driver{})
}
<commit_msg>Allow region selection<commit_after>// Copyright 2014 Dynamic Design. All rights reserved.

package s3

import (
	// "os"
	// "path"
	"strings"

	"github.com/dynamic-design/storage"
	"github.com/dynamic-design/storage/driver"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
)

type Driver struct{}

func (d *Driver) Open(source string) (driver.Bucket, error) {
	flds := map[string]string{}
	for _, fld := range strings.Fields(source) {
		toks := strings.SplitN(fld, "=", 2)
		flds[toks[0]] = toks[1]
	}
	c := s3.New(aws.Auth{
		AccessKey: flds["key"],
		SecretKey: flds["secret"],
	}, aws.Regions[flds["region"]])

	return &Bucket{
		Bucket: c.Bucket(flds["bucket"]),
	}, nil
}

type Bucket struct {
	*s3.Bucket
}

func (b *Bucket) Create(name string) (driver.File, error) {
	return &File{
		b:    b,
		name: name,
		mode: 1,
	}, nil
}

func (b *Bucket) Open(name string) (driver.File, error) {
	return &File{
		b:    b,
		name: name,
		mode: 0,
	}, nil
}

func init() {
	storage.Register("s3", &Driver{})
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"os"
	"os/signal"

	"github.com/anaminus/cobra"
	"github.com/anaminus/rbxmk/rbxmk/render/term"
	terminal "golang.org/x/term"
)

var Frag = NewFragments(initFragRoot())

// FragContent renders in HTML without the outer section or body.
func FragContent(fragref string) string {
	return Frag.ResolveWith(fragref, FragOptions{Inner: true})
}

var docState = NewDocState(Frag)

func Doc(fragref string) string     { return docState.Doc(fragref) }
func DocFlag(fragref string) string { return docState.DocFlag(fragref) }
func DocFragments() []string        { return docState.DocFragments() }
func UnresolvedFragments()          { docState.UnresolvedFragments() }

var Program = &cobra.Command{
	Use:           "rbxmk",
	Short:         Doc("Commands:Summary"),
	Long:          Doc("Commands:Summary"),
	SilenceUsage:  true,
	SilenceErrors: true,
}

// Template function that expands environment variables. Each argument is an
// alternating key and value. The last value is the string to expand.
func expand(p ...string) string {
	if len(p) == 0 {
		return ""
	}
	s, p := p[len(p)-1], p[:len(p)-1]
	m := make(map[string]string, len(p)/2)
	for i := 1; i < len(p); i += 2 {
		m[p[i-1]] = p[i]
	}
	return os.Expand(s, func(s string) string { return m[s] })
}

func init() {
	fragTmplFuncs["frag"] = FragContent
	fragTmplFuncs["fraglist"] = Frag.List
	fragTmplFuncs["expand"] = os.Expand

	cobra.AddTemplateFunc("frag", func(fragref string) string {
		return Frag.ResolveWith(fragref, FragOptions{
			Renderer: term.NewRenderer(-1).Render,
			Inner:    true,
		})
	})
	cobra.AddTemplateFunc("expand", expand)
	cobra.AddTemplateFunc("width", func() int {
		width, _, _ := terminal.GetSize(int(os.Stdout.Fd()))
		return width
	})
	Program.SetUsageTemplate(usageTemplate)
}

var ProgramContext, ProgramExit = context.WithCancel(context.Background())

func main() {
	ctx, stop := signal.NotifyContext(ProgramContext, os.Kill)
	defer stop()

	Program.SetIn(os.Stdin)
	Program.SetOut(os.Stdout)
	Program.SetErr(os.Stderr)

	DocumentCommands()
	UnresolvedFragments()

	if err := Starter()(ctx); err != nil {
		Program.PrintErrln(err)
	}
}
<commit_msg>Include build information when the program panics.<commit_after>package main

import (
	"context"
	"os"
	"os/signal"

	"github.com/anaminus/cobra"
	"github.com/anaminus/rbxmk/rbxmk/render/term"
	terminal "golang.org/x/term"
)

var Frag = NewFragments(initFragRoot())

// FragContent renders in HTML without the outer section or body.
func FragContent(fragref string) string {
	return Frag.ResolveWith(fragref, FragOptions{Inner: true})
}

var docState = NewDocState(Frag)

func Doc(fragref string) string     { return docState.Doc(fragref) }
func DocFlag(fragref string) string { return docState.DocFlag(fragref) }
func DocFragments() []string        { return docState.DocFragments() }
func UnresolvedFragments()          { docState.UnresolvedFragments() }

var Program = &cobra.Command{
	Use:           "rbxmk",
	Short:         Doc("Commands:Summary"),
	Long:          Doc("Commands:Summary"),
	SilenceUsage:  true,
	SilenceErrors: true,
}

// Template function that expands environment variables. Each argument is an
// alternating key and value. The last value is the string to expand.
func expand(p ...string) string {
	if len(p) == 0 {
		return ""
	}
	s, p := p[len(p)-1], p[:len(p)-1]
	m := make(map[string]string, len(p)/2)
	for i := 1; i < len(p); i += 2 {
		m[p[i-1]] = p[i]
	}
	return os.Expand(s, func(s string) string { return m[s] })
}

func init() {
	fragTmplFuncs["frag"] = FragContent
	fragTmplFuncs["fraglist"] = Frag.List
	fragTmplFuncs["expand"] = os.Expand

	cobra.AddTemplateFunc("frag", func(fragref string) string {
		return Frag.ResolveWith(fragref, FragOptions{
			Renderer: term.NewRenderer(-1).Render,
			Inner:    true,
		})
	})
	cobra.AddTemplateFunc("expand", expand)
	cobra.AddTemplateFunc("width", func() int {
		width, _, _ := terminal.GetSize(int(os.Stdout.Fd()))
		return width
	})
	Program.SetUsageTemplate(usageTemplate)
}

var ProgramContext, ProgramExit = context.WithCancel(context.Background())

// Include build information when the program panics.
func PanicWithBuildInfo() {
	if v := recover(); v != nil {
		(&VersionCommand{
			Format:  "text",
			Verbose: 2,
			Error:   true,
		}).WriteInfo(os.Stderr)
		panic(v)
	}
}

func main() {
	defer PanicWithBuildInfo()
	ctx, stop := signal.NotifyContext(ProgramContext, os.Kill)
	defer stop()

	Program.SetIn(os.Stdin)
	Program.SetOut(os.Stdout)
	Program.SetErr(os.Stderr)

	DocumentCommands()
	UnresolvedFragments()

	if err := Starter()(ctx); err != nil {
		Program.PrintErrln(err)
	}
}
<|endoftext|>


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

// ----------------

// Package rac provides access to RAC (Random Access Compression) files.
//
// RAC is just a container format, and this package ("rac") is a relatively
// low-level. Users will typically want to process a particular compression
// format wrapped in RAC, such as (RAC + Zlib). For that, look at e.g. the
// sibling "raczlib" package (TODO).
//
// The RAC specification is at
// https://github.com/google/wuffs/blob/master/doc/spec/rac-spec.md
package rac

const (
	// MaxSize is the maximum RAC file size (in both CSpace and DSpace).
	MaxSize = (1 << 48) - 1

	// invalidCOffsetCLength is ((1 << 64) - 1).
	invalidCOffsetCLength = 0xFFFFFFFFFFFFFFFF
)

// Codec is the compression codec for the RAC file.
//
// See the RAC specification for further discussion.
type Codec uint8

const (
	CodecZlib      = Codec(0x01)
	CodecBrotli    = Codec(0x02)
	CodecZstandard = Codec(0x04)
)

// IndexLocation is whether the index is at the start or end of the RAC file.
//
// See the RAC specification for further discussion.
type IndexLocation uint8

const magic = "\x72\xC3\x63"

const (
	IndexLocationAtEnd   = IndexLocation(0)
	IndexLocationAtStart = IndexLocation(1)
)

var indexLocationAtEndMagic = []byte("\x72\xC3\x63\x00")

// OptResource is an option type, optionally holding a Writer-specific
// identifier for a shared resource.
//
// Zero means that the option is not taken: no shared resource is used.
type OptResource uint32
<commit_msg>Remove TODO comment about implementing raczlib<commit_after>// Copyright 2019 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// Package rac provides access to RAC (Random Access Compression) files.
//
// RAC is just a container format, and this package ("rac") is a relatively
// low-level. Users will typically want to process a particular compression
// format wrapped in RAC, such as (RAC + Zlib). For that, look at e.g. the
// sibling "raczlib" package.
//
// The RAC specification is at
// https://github.com/google/wuffs/blob/master/doc/spec/rac-spec.md
package rac

const (
	// MaxSize is the maximum RAC file size (in both CSpace and DSpace).
	MaxSize = (1 << 48) - 1

	// invalidCOffsetCLength is ((1 << 64) - 1).
	invalidCOffsetCLength = 0xFFFFFFFFFFFFFFFF
)

// Codec is the compression codec for the RAC file.
//
// See the RAC specification for further discussion.
type Codec uint8

const (
	CodecZlib      = Codec(0x01)
	CodecBrotli    = Codec(0x02)
	CodecZstandard = Codec(0x04)
)

// IndexLocation is whether the index is at the start or end of the RAC file.
//
// See the RAC specification for further discussion.
type IndexLocation uint8

const magic = "\x72\xC3\x63"

const (
	IndexLocationAtEnd   = IndexLocation(0)
	IndexLocationAtStart = IndexLocation(1)
)

var indexLocationAtEndMagic = []byte("\x72\xC3\x63\x00")

// OptResource is an option type, optionally holding a Writer-specific
// identifier for a shared resource.
//
// Zero means that the option is not taken: no shared resource is used.
type OptResource uint32
<|endoftext|>


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

package tag

import (
	"fmt"
	"io"
	"os"
	"strings"
)

// ID3v2Header is a type which represents an ID3v2 tag header.
type ID3v2Header struct {
	Version           Format
	Unsynchronisation bool
	ExtendedHeader    bool
	Experimental      bool
	Size              int
}

// readID3v2Header reads the ID3v2 header from the given io.Reader.
func readID3v2Header(r io.Reader) (*ID3v2Header, error) {
	b, err := readBytes(r, 10)
	if err != nil {
		return nil, fmt.Errorf("expected to read 10 bytes (ID3v2Header): %v", err)
	}

	if string(b[0:3]) != "ID3" {
		return nil, fmt.Errorf("expected to read \"ID3\"")
	}

	b = b[3:]
	var vers Format
	switch uint(b[0]) {
	case 2:
		vers = ID3v2_2
	case 3:
		vers = ID3v2_3
	case 4:
		vers = ID3v2_4
	case 0, 1:
		fallthrough
	default:
		return nil, fmt.Errorf("ID3 version: %v, expected: 2, 3 or 4", uint(b[0]))
	}

	// NB: We ignore b[1] (the revision) as we don't currently rely on it.
	return &ID3v2Header{
		Version:           vers,
		Unsynchronisation: getBit(b[2], 7),
		ExtendedHeader:    getBit(b[2], 6),
		Experimental:      getBit(b[2], 5),
		Size:              get7BitChunkedInt(b[3:7]),
	}, nil
}

// ID3v2FrameFlags is a type which represents the flags which can be set on an ID3v2 frame.
type ID3v2FrameFlags struct {
	// Message
	TagAlterPreservation  bool
	FileAlterPreservation bool
	ReadOnly              bool

	// Format
	GroupIdentity       bool
	Compression         bool
	Encryption          bool
	Unsynchronisation   bool
	DataLengthIndicator bool
}

func readID3v2FrameFlags(r io.Reader) (*ID3v2FrameFlags, error) {
	b, err := readBytes(r, 2)
	if err != nil {
		return nil, err
	}

	msg := b[0]
	fmt := b[1]

	return &ID3v2FrameFlags{
		TagAlterPreservation:  getBit(msg, 6),
		FileAlterPreservation: getBit(msg, 5),
		ReadOnly:              getBit(msg, 4),
		GroupIdentity:         getBit(fmt, 7),
		Compression:           getBit(fmt, 3),
		Encryption:            getBit(fmt, 2),
		Unsynchronisation:     getBit(fmt, 1),
		DataLengthIndicator:   getBit(fmt, 0),
	}, nil
}

func readID3v2_2FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
	name, err = readString(r, 3)
	if err != nil {
		return
	}
	size, err = readInt(r, 3)
	if err != nil {
		return
	}
	headerSize = 6
	return
}

func readID3v2_3FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
	name, err = readString(r, 4)
	if err != nil {
		return
	}
	size, err = readInt(r, 4)
	if err != nil {
		return
	}
	headerSize = 8
	return
}

func readID3v2_4FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
	name, err = readString(r, 4)
	if err != nil {
		return
	}
	size, err = read7BitChunkedInt(r, 4)
	if err != nil {
		return
	}
	headerSize = 8
	return
}

// readID3v2Frames reads ID3v2 frames from the given reader using the ID3v2Header.
func readID3v2Frames(r io.Reader, h *ID3v2Header) (map[string]interface{}, error) {
	offset := 10 // the size of the header
	result := make(map[string]interface{})

	for offset < h.Size {
		var err error
		var name string
		var size, headerSize int
		var flags *ID3v2FrameFlags

		switch h.Version {
		case ID3v2_2:
			name, size, headerSize, err = readID3v2_2FrameHeader(r)

		case ID3v2_3:
			name, size, headerSize, err = readID3v2_3FrameHeader(r)
			if err != nil {
				return nil, err
			}
			flags, err = readID3v2FrameFlags(r)
			headerSize += 2

		case ID3v2_4:
			name, size, headerSize, err = readID3v2_4FrameHeader(r)
			if err != nil {
				return nil, err
			}
			flags, err = readID3v2FrameFlags(r)
			headerSize += 2
		}

		if err != nil {
			return nil, err
		}
		// if size=0, we certainly are in a padding zone. ignore the rest of
		// the tags. and if size > h.Size, we have a problem
		if size == 0 || size > h.Size {
			break
		}

		offset += headerSize + size

		// Check this stuff out...
		if flags != nil && flags.DataLengthIndicator {
			_, err = read7BitChunkedInt(r, 4) // read 4
			if err != nil {
				return nil, err
			}
			size -= 4
		}

		if flags != nil && flags.Unsynchronisation {
			// FIXME: Implement this.
			continue
		}

		name = strings.TrimSpace(name)
		if name == "" {
			break
		}

		b, err := readBytes(r, size)
		if err != nil {
			return nil, err
		}

		switch {
		case name[0] == 'T':
			txt, err := readTFrame(b)
			if err != nil {
				return nil, err
			}
			result[name] = txt

		case name == "APIC":
			p, err := readAPICFrame(b)
			if err != nil {
				return nil, err
			}
			result[name] = p

		case name == "PIC":
			p, err := readPICFrame(b)
			if err != nil {
				return nil, err
			}
			result[name] = p
		}

		continue
	}
	return result, nil
}

type Unsynchroniser struct {
	orig io.Reader
}

// filter io.Reader which skip the Unsynchronisation bytes
func (r *Unsynchroniser) Read(p []byte) (int, error) {
	nextOk := false
	for i := 0; i < len(p); i++ {
		if n, err := r.orig.Read(p[i : i+1]); n == 0 || err != nil {
			return i, err
		}
		if i >= 1 && p[i-1] == 255 && p[i] == 0 && !nextOk {
			// we must skip this 00
			i--
			// but not the next one
			nextOk = true
		} else {
			nextOk = false
		}
	}
	return len(p), nil
}

// ReadID3v2Tags parses ID3v2.{2,3,4} tags from the io.ReadSeeker into a Metadata, returning
// non-nil error on failure.
func ReadID3v2Tags(r io.ReadSeeker) (Metadata, error) {
	_, err := r.Seek(0, os.SEEK_SET)
	if err != nil {
		return nil, err
	}

	h, err := readID3v2Header(r)
	if err != nil {
		return nil, err
	}

	var ur io.Reader

	if h.Unsynchronisation {
		ur = &Unsynchroniser{orig: r}
	} else {
		ur = r
	}

	f, err := readID3v2Frames(ur, h)
	if err != nil {
		return nil, err
	}
	return metadataID3v2{header: h, frames: f}, nil
}
<commit_msg>Need to skip Unsynchronisation byte at the boundary between 2 Read<commit_after>// Copyright 2015, David Howden
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tag

import (
	"fmt"
	"io"
	"os"
	"strings"
)

// ID3v2Header is a type which represents an ID3v2 tag header.
type ID3v2Header struct {
	Version           Format
	Unsynchronisation bool
	ExtendedHeader    bool
	Experimental      bool
	Size              int
}

// readID3v2Header reads the ID3v2 header from the given io.Reader.
func readID3v2Header(r io.Reader) (*ID3v2Header, error) {
	b, err := readBytes(r, 10)
	if err != nil {
		return nil, fmt.Errorf("expected to read 10 bytes (ID3v2Header): %v", err)
	}

	if string(b[0:3]) != "ID3" {
		return nil, fmt.Errorf("expected to read \"ID3\"")
	}

	b = b[3:]
	var vers Format
	switch uint(b[0]) {
	case 2:
		vers = ID3v2_2
	case 3:
		vers = ID3v2_3
	case 4:
		vers = ID3v2_4
	case 0, 1:
		fallthrough
	default:
		return nil, fmt.Errorf("ID3 version: %v, expected: 2, 3 or 4", uint(b[0]))
	}

	// NB: We ignore b[1] (the revision) as we don't currently rely on it.
	return &ID3v2Header{
		Version:           vers,
		Unsynchronisation: getBit(b[2], 7),
		ExtendedHeader:    getBit(b[2], 6),
		Experimental:      getBit(b[2], 5),
		Size:              get7BitChunkedInt(b[3:7]),
	}, nil
}

// ID3v2FrameFlags is a type which represents the flags which can be set on an ID3v2 frame.
type ID3v2FrameFlags struct {
	// Message
	TagAlterPreservation  bool
	FileAlterPreservation bool
	ReadOnly              bool

	// Format
	GroupIdentity       bool
	Compression         bool
	Encryption          bool
	Unsynchronisation   bool
	DataLengthIndicator bool
}

func readID3v2FrameFlags(r io.Reader) (*ID3v2FrameFlags, error) {
	b, err := readBytes(r, 2)
	if err != nil {
		return nil, err
	}

	msg := b[0]
	fmt := b[1]

	return &ID3v2FrameFlags{
		TagAlterPreservation:  getBit(msg, 6),
		FileAlterPreservation: getBit(msg, 5),
		ReadOnly:              getBit(msg, 4),
		GroupIdentity:         getBit(fmt, 7),
		Compression:           getBit(fmt, 3),
		Encryption:            getBit(fmt, 2),
		Unsynchronisation:     getBit(fmt, 1),
		DataLengthIndicator:   getBit(fmt, 0),
	}, nil
}

func readID3v2_2FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
	name, err = readString(r, 3)
	if err != nil {
		return
	}
	size, err = readInt(r, 3)
	if err != nil {
		return
	}
	headerSize = 6
	return
}

func readID3v2_3FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
	name, err = readString(r, 4)
	if err != nil {
		return
	}
	size, err = readInt(r, 4)
	if err != nil {
		return
	}
	headerSize = 8
	return
}

func readID3v2_4FrameHeader(r io.Reader) (name string, size int, headerSize int, err error) {
	name, err = readString(r, 4)
	if err != nil {
		return
	}
	size, err = read7BitChunkedInt(r, 4)
	if err != nil {
		return
	}
	headerSize = 8
	return
}

// readID3v2Frames reads ID3v2 frames from the given reader using the ID3v2Header.
func readID3v2Frames(r io.Reader, h *ID3v2Header) (map[string]interface{}, error) {
	offset := 10 // the size of the header
	result := make(map[string]interface{})

	for offset < h.Size {
		var err error
		var name string
		var size, headerSize int
		var flags *ID3v2FrameFlags

		switch h.Version {
		case ID3v2_2:
			name, size, headerSize, err = readID3v2_2FrameHeader(r)

		case ID3v2_3:
			name, size, headerSize, err = readID3v2_3FrameHeader(r)
			if err != nil {
				return nil, err
			}
			flags, err = readID3v2FrameFlags(r)
			headerSize += 2

		case ID3v2_4:
			name, size, headerSize, err = readID3v2_4FrameHeader(r)
			if err != nil {
				return nil, err
			}
			flags, err = readID3v2FrameFlags(r)
			headerSize += 2
		}

		if err != nil {
			return nil, err
		}
		// if size=0, we certainly are in a padding zone. ignore the rest of
		// the tags
		if size == 0 {
			break
		}

		offset += headerSize + size

		// Check this stuff out...
		if flags != nil && flags.DataLengthIndicator {
			_, err = read7BitChunkedInt(r, 4) // read 4
			if err != nil {
				return nil, err
			}
			size -= 4
		}

		if flags != nil && flags.Unsynchronisation {
			// FIXME: Implement this.
			continue
		}

		name = strings.TrimSpace(name)
		if name == "" {
			break
		}

		b, err := readBytes(r, size)
		if err != nil {
			return nil, err
		}

		switch {
		case name[0] == 'T':
			txt, err := readTFrame(b)
			if err != nil {
				return nil, err
			}
			result[name] = txt

		case name == "APIC":
			p, err := readAPICFrame(b)
			if err != nil {
				return nil, err
			}
			result[name] = p

		case name == "PIC":
			p, err := readPICFrame(b)
			if err != nil {
				return nil, err
			}
			result[name] = p
		}

		continue
	}
	return result, nil
}

type Unsynchroniser struct {
	orig      io.Reader
	prevWasFF bool
}

// filter io.Reader which skip the Unsynchronisation bytes
func (r *Unsynchroniser) Read(p []byte) (int, error) {
	for i := 0; i < len(p); i++ {
		// there is only one byte to read.
		if i == len(p)-1 {
			if n, err := r.orig.Read(p[i : i+1]); n == 0 || err != nil {
				return i, err
			}
			// we need to read this last byte once more
			if r.prevWasFF && p[i] == 0 {
				i--
				r.prevWasFF = false
			}
			r.prevWasFF = (p[i] == 255)
			continue
		}
		if n, err := r.orig.Read(p[i : i+2]); n == 0 || err != nil {
			return i, err
		}
		if r.prevWasFF && p[i] == 0 {
			p[i] = p[i+1]
			r.prevWasFF = false
			continue
		}
		if p[i] == 255 && p[i+1] == 0 {
			r.prevWasFF = false
			continue
		}
		r.prevWasFF = (p[i+1] == 255)
		// these 2 bytes are fine, we skip none
		i++
	}
	return len(p), nil
}

// ReadID3v2Tags parses ID3v2.{2,3,4} tags from the io.ReadSeeker into a Metadata, returning
// non-nil error on failure.
func ReadID3v2Tags(r io.ReadSeeker) (Metadata, error) {
	_, err := r.Seek(0, os.SEEK_SET)
	if err != nil {
		return nil, err
	}

	h, err := readID3v2Header(r)
	if err != nil {
		return nil, err
	}

	var ur io.Reader

	if h.Unsynchronisation {
		ur = &Unsynchroniser{orig: r}
	} else {
		ur = r
	}

	f, err := readID3v2Frames(ur, h)
	if err != nil {
		return nil, err
	}
	return metadataID3v2{header: h, frames: f}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"github.com/codegangsta/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "ghoto"
	app.Usage = "Transfer photo(video)"
	app.Action = func(c *cli.Context) {
		println("Hello ghoto")
	}
	app.Run(os.Args)
}
<commit_msg>add arguments<commit_after>package main

import (
	"os"
	"fmt"
	"github.com/codegangsta/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "ghoto"
	app.Usage = "Transfer photo(video)"
	app.Flags = []cli.Flag {
		cli.StringFlag {
			Name: "src, s",
			Value: "/path/to/src",
			Usage: "Source directory",
		},
		cli.StringFlag {
			Name: "dst, d",
			Value: "/path/to/dst",
			Usage: "Destination directory",
		},
		cli.StringFlag {
			Name: "photo-dir, P",
			Value: "photo",
			Usage: "Destination photo directory",
		},
		cli.StringFlag {
			Name: "video-dir, V",
			Value: "video",
			Usage: "Destination video directory",
		},

	}
	app.Action = func(c *cli.Context) {
		fmt.Printf("Hello ghoto src=%s, dst=%s, photo-dir=%s, video-dir=%s \n", c.String("src"), c.String("dst"), c.String("photo-dir"), c.String("video-dir"))
	}
	app.Run(os.Args)
}
<|endoftext|>