<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"hash/crc64"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/mssola/user_agent"

	"github.com/ernado/ice"
	"github.com/gortc/sdp"
	"github.com/gortc/stun"
)

var (
	portHTTP = flag.Int("port", 3000, "http server port")
	hostHTTP = flag.String("host", "localhost", "http server host")
	portSTUN = flag.Int("port-stun", stun.DefaultPort, "UDP port")
	messages = &storage{
		data: make(map[string]*storageEntry),
	}
)

var (
	bindingRequest = stun.MessageType{
		Method: stun.MethodBinding,
		Class:  stun.ClassRequest,
	}
	bindingSuccessResponse = stun.MessageType{
		Method: stun.MethodBinding,
		Class:  stun.ClassSuccessResponse,
	}
)

func processUDPPacket(addr net.Addr, b []byte, req, res *stun.Message) error {
	if !stun.IsMessage(b) {
		log.Println("packet from", addr, "is not STUN message")
		return nil
	}
	req.Raw = b
	if err := req.Decode(); err != nil {
		return err
	}
	if req.Type != bindingRequest {
		log.Println("stun: skipping", req.Type, "from", addr)
		return nil
	}
	log.Println("stun: got", req.Type)
	res.TransactionID = req.TransactionID
	res.Type = bindingSuccessResponse
	var (
		ip   net.IP
		port int
	)
	switch a := addr.(type) {
	case *net.UDPAddr:
		ip = a.IP
		port = a.Port
	default:
		panic(fmt.Sprintf("unknown addr: %v", addr))
	}
	stun.XORMappedAddress{
		IP: ip,
		Port: port,
	}.AddTo(res)
	stun.NewSoftware("cydev.ru/sdp example").AddTo(res)
	res.WriteHeader()
	messages.add(fmt.Sprintf("%s:%d", ip, port), req)
	return nil
}

type iceServerConfiguration struct {
	URLs []string `json:"urls"`
}

type iceConfiguration struct {
	Servers []iceServerConfiguration `json:"iceServers"`
}

type storageEntry struct {
	*stun.Message
	createdAt time.Time
}

func (s storageEntry) timedOut(timeout time.Time) bool {
	return s.createdAt.Before(timeout)
}

type storage struct {
	data map[string]*storageEntry
	sync.Mutex
}

func (storage) timeout() time.Time {
	return time.Now().Add(time.Second * -60)
}

func mustClone(m *stun.Message) *stun.Message {
	b := new(stun.Message)
	if err := m.CloneTo(b); err != nil {
		panic(err)
	}
	return b
}

func (s *storage) pop(addr string) *stun.Message {
	s.Lock()
	defer s.Unlock()
	if s.data[addr] == nil {
		return nil
	}
	m := mustClone(s.data[addr].Message)
	delete(s.data, addr)
	return m
}

func (s *storage) add(addr string, m *stun.Message) {
	c := new(stun.Message)
	m.CloneTo(c)
	entry := &storageEntry{
		Message:   c,
		createdAt: time.Now(),
	}
	s.Lock()
	s.data[addr] = entry
	s.Unlock()
	log.Println("storage: added", addr)
}

func (s *storage) collect() {
	s.Lock()
	var (
		toRemove = make([]string, 0, 10)
		timeout  = s.timeout()
	)
	for addr, m := range s.data {
		if m.timedOut(timeout) {
			toRemove = append(toRemove, addr)
		}
	}
	for _, addr := range toRemove {
		delete(s.data, addr)
	}
	s.Unlock()
	if len(toRemove) > 0 {
		log.Println("storage: collected", len(toRemove))
	}
}

func (s *storage) gc() {
	ticker := time.NewTicker(time.Second * 2)
	for range ticker.C {
		s.collect()
	}
}

func main() {
	flag.Parse()
	log.SetFlags(log.Lshortfile)
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/", fs)
	http.HandleFunc("/ice-configuration", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Content-type", "application/json")
		encoder := json.NewEncoder(w)
		origin := r.Header.Get("Origin")
		server := "stun:rs.cydev.ru"
		if len(origin) > 0 {
			u, err := url.Parse(origin)
			if err != nil {
				log.Printf("http: failed to parse origin %q: %s", origin, err)
			} else {
				if idx := strings.LastIndex(u.Host, ":"); idx > 0 {
					u.Host = u.Host[:idx]
				}
				server = fmt.Sprintf("stun:%s:%d", u.Host, *portSTUN)
				log.Printf("http: sending ice-server %q for origin %q", server, origin)
			}
		}
		if err := encoder.Encode(iceConfiguration{
			Servers: []iceServerConfiguration{
				{URLs: []string{server}},
			},
		}); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			fmt.Fprintln(w, "json encode:", err)
		}
	})

	mLog, err := os.OpenFile("packets.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		log.Fatalln("Failed to open log:", err)
	}
	defer mLog.Close()
	csvLog := csv.NewWriter(mLog)

	// Custom domain support.
	for _, name := range []string{
		"stun", "turn", "sdp", "web", "ice",
	} {
		body := strings.Replace(`<!DOCTYPE html>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="go-import" content="gortc.io/pkg git https://github.com/gortc/sdp.git">
    <meta name="go-source"
          content="gortc.io/pkg https://github.com/gortc/pkg/ https://github.com/gortc/pkg/tree/master{/dir} https://github.com/gortc/pkg/blob/master{/dir}/{file}#L{line}">
    <meta http-equiv="refresh" content="0; url=https://godoc.org/gortc.io/pkg">

Nothing to see here; move along.
`, "pkg", name, -1)
		http.HandleFunc("/" + name, func(w http.ResponseWriter, r *http.Request) {
			defer r.Body.Close()
			fmt.Fprint(w, body)
		})
	}

	http.HandleFunc("/x/sdp", func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		log.Println("http:", r.Method, "request from", r.RemoteAddr)
		if r.Method == http.MethodGet {
			http.Redirect(w, r, "/x/sdp/", http.StatusPermanentRedirect)
			return
		}
		s := sdp.Session{}
		data, err := ioutil.ReadAll(r.Body)
		if err != nil {
			log.Println("http: ReadAll body failed:", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		if s, err = sdp.DecodeSession(data, s); err != nil {
			log.Println("http: failed to decode sdp session:", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		for k, v := range s {
			fmt.Fprintf(w, `<p class="attribute">%02d %s</p>`+"\n", k, v)
			if v.Type != sdp.TypeAttribute {
				continue
			}
			if !bytes.HasPrefix(v.Value, []byte("candidate")) {
				continue
			}
			c := new(ice.Candidate)
			fmt.Fprintln(w, `<div class="stun-message">`)
			if err = ice.ParseAttribute(v.Value, c); err != nil {
				fmt.Fprintln(w, `<p class="error">failed to parse as candidate:`, err, "
")
				fmt.Fprintln(w, `</div>`)
				continue
			}
			fmt.Fprintln(w, "
parsed as candidate:", fmt.Sprintf("%+v", c), "
")
			if c.Type != ice.CandidateServerReflexive {
				fmt.Fprintln(w, `</div>`)
				continue
			}
			addr := fmt.Sprintf("%s:%d", c.ConnectionAddress, c.Port)
			m := messages.pop(addr)
			if m == nil {
				log.Println("http: no message for", addr, "in log")
				fmt.Fprintln(w, `<p class="warning">message from candidate not found in STUN log</p>`)
				fmt.Fprintln(w, `</div>`)
				continue
			}
			fmt.Fprintln(w, `<p class="success">message found in STUN log:`, m, `</p>`)
			for _, a := range m.Attributes {
				switch a.Type {
				case stun.AttrOrigin:
					fmt.Fprintf(w, "
STUN attribute %s: %q (len=%d)
", a.Type, a.Value, a.Length)
				default:
					fmt.Fprintf(w, "
STUN attribute %s: %v (len=%d)
", a.Type, a.Value, a.Length)
				}
			}
			var (
				b64             = base64.StdEncoding.EncodeToString(m.Raw)
				messageCRC64    = crc64.Checksum(m.Raw, crc64.MakeTable(crc64.ISO))
				clipID          = fmt.Sprintf("crc64-%d", messageCRC64)
				ua              = user_agent.New(r.Header.Get("User-agent"))
				bName, bVersion = ua.Browser()
			)
			if err = csvLog.Write([]string{
				addr,
				b64,
				fmt.Sprintf("%d", messageCRC64),
				bName,
				bVersion,
				ua.OS(),
			}); err != nil {
				log.Fatalln("log: failed to write:", err)
			}
			csvLog.Flush()
			fmt.Fprintln(w, `<p>dumped: <code id="`+clipID+`">stun-decode`, b64, `
				<button class="btn" data-clipboard-target="#`+clipID+`">copy</button>

`)
			fmt.Fprintln(w, `<p>crc64: <code>`, messageCRC64, `</code></p>`)
			fmt.Fprintln(w, `</div>`)
		}
	})

	var (
		addrSTUN = fmt.Sprintf(":%d", *portSTUN)
		addrHTTP = fmt.Sprintf("%s:%d", *hostHTTP, *portHTTP)
	)
	log.Println("Listening udp", addrSTUN)
	c, err := net.ListenPacket("udp", addrSTUN)
	if err != nil {
		log.Fatalf("Failed to bind udp on %s: %s", addrSTUN, err)
	}
	defer c.Close()

	// spawning storage garbage collector
	go messages.gc()

	// spawning STUN server
	go func(conn net.PacketConn) {
		log.Println("Started STUN server on", conn.LocalAddr())
		var (
			res = new(stun.Message)
			req = new(stun.Message)
			buf = make([]byte, 1024)
		)
		for {
			// ReadFrom c to buf
			n, addr, err := c.ReadFrom(buf)
			if err != nil {
				log.Fatalln("c.ReadFrom:", err)
			}
			log.Printf("udp: got packet len(%d) from %s", n, addr)
			// processing binding request
			if err = processUDPPacket(addr, buf[:n], req, res); err != nil {
				log.Println("failed to process UDP packet:", err, "from addr", addr)
			} else {
				log.Printf("stun: parsed message %q from %s", req, addr)
				if _, err = c.WriteTo(res.Raw, addr); err != nil {
					log.Println("failed to send packet:", err)
				}
			}
			res.Reset()
			req.Reset()
		}

	}(c)
	log.Println("Listening http", addrHTTP)
	log.Fatal(http.ListenAndServe(addrHTTP, nil))
}
<commit_msg>server: fix import path handling<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"hash/crc64"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/mssola/user_agent"

	"github.com/ernado/ice"
	"github.com/gortc/sdp"
	"github.com/gortc/stun"
)

var (
	portHTTP = flag.Int("port", 3000, "http server port")
	hostHTTP = flag.String("host", "localhost", "http server host")
	portSTUN = flag.Int("port-stun", stun.DefaultPort, "UDP port")
	messages = &storage{
		data: make(map[string]*storageEntry),
	}
)

var (
	bindingRequest = stun.MessageType{
		Method: stun.MethodBinding,
		Class:  stun.ClassRequest,
	}
	bindingSuccessResponse = stun.MessageType{
		Method: stun.MethodBinding,
		Class:  stun.ClassSuccessResponse,
	}
)

func processUDPPacket(addr net.Addr, b []byte, req, res *stun.Message) error {
	if !stun.IsMessage(b) {
		log.Println("packet from", addr, "is not STUN message")
		return nil
	}
	req.Raw = b
	if err := req.Decode(); err != nil {
		return err
	}
	if req.Type != bindingRequest {
		log.Println("stun: skipping", req.Type, "from", addr)
		return nil
	}
	log.Println("stun: got", req.Type)
	res.TransactionID = req.TransactionID
	res.Type = bindingSuccessResponse
	var (
		ip   net.IP
		port int
	)
	switch a := addr.(type) {
	case *net.UDPAddr:
		ip = a.IP
		port = a.Port
	default:
		panic(fmt.Sprintf("unknown addr: %v", addr))
	}
	stun.XORMappedAddress{
		IP: ip,
		Port: port,
	}.AddTo(res)
	stun.NewSoftware("cydev.ru/sdp example").AddTo(res)
	res.WriteHeader()
	messages.add(fmt.Sprintf("%s:%d", ip, port), req)
	return nil
}

type iceServerConfiguration struct {
	URLs []string `json:"urls"`
}

type iceConfiguration struct {
	Servers []iceServerConfiguration `json:"iceServers"`
}

type storageEntry struct {
	*stun.Message
	createdAt time.Time
}

func (s storageEntry) timedOut(timeout time.Time) bool {
	return s.createdAt.Before(timeout)
}

type storage struct {
	data map[string]*storageEntry
	sync.Mutex
}

func (storage) timeout() time.Time {
	return time.Now().Add(time.Second * -60)
}

func mustClone(m *stun.Message) *stun.Message {
	b := new(stun.Message)
	if err := m.CloneTo(b); err != nil {
		panic(err)
	}
	return b
}

func (s *storage) pop(addr string) *stun.Message {
	s.Lock()
	defer s.Unlock()
	if s.data[addr] == nil {
		return nil
	}
	m := mustClone(s.data[addr].Message)
	delete(s.data, addr)
	return m
}

func (s *storage) add(addr string, m *stun.Message) {
	c := new(stun.Message)
	m.CloneTo(c)
	entry := &storageEntry{
		Message:   c,
		createdAt: time.Now(),
	}
	s.Lock()
	s.data[addr] = entry
	s.Unlock()
	log.Println("storage: added", addr)
}

func (s *storage) collect() {
	s.Lock()
	var (
		toRemove = make([]string, 0, 10)
		timeout  = s.timeout()
	)
	for addr, m := range s.data {
		if m.timedOut(timeout) {
			toRemove = append(toRemove, addr)
		}
	}
	for _, addr := range toRemove {
		delete(s.data, addr)
	}
	s.Unlock()
	if len(toRemove) > 0 {
		log.Println("storage: collected", len(toRemove))
	}
}

func (s *storage) gc() {
	ticker := time.NewTicker(time.Second * 2)
	for range ticker.C {
		s.collect()
	}
}

func main() {
	flag.Parse()
	log.SetFlags(log.Lshortfile)
	fs := http.FileServer(http.Dir("static"))
	http.Handle("/", fs)
	http.HandleFunc("/ice-configuration", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Content-type", "application/json")
		encoder := json.NewEncoder(w)
		origin := r.Header.Get("Origin")
		server := "stun:rs.cydev.ru"
		if len(origin) > 0 {
			u, err := url.Parse(origin)
			if err != nil {
				log.Printf("http: failed to parse origin %q: %s", origin, err)
			} else {
				if idx := strings.LastIndex(u.Host, ":"); idx > 0 {
					u.Host = u.Host[:idx]
				}
				server = fmt.Sprintf("stun:%s:%d", u.Host, *portSTUN)
				log.Printf("http: sending ice-server %q for origin %q", server, origin)
			}
		}
		if err := encoder.Encode(iceConfiguration{
			Servers: []iceServerConfiguration{
				{URLs: []string{server}},
			},
		}); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			fmt.Fprintln(w, "json encode:", err)
		}
	})

	mLog, err := os.OpenFile("packets.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		log.Fatalln("Failed to open log:", err)
	}
	defer mLog.Close()
	csvLog := csv.NewWriter(mLog)

	// Custom domain support.
	for _, name := range []string{
		"stun", "turn", "sdp", "web", "ice",
	} {
		body := strings.Replace(`<!DOCTYPE html>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="go-import" content="gortc.io/pkg git https://github.com/gortc/sdp.git">
    <meta name="go-source"
          content="gortc.io/pkg https://github.com/gortc/pkg/ https://github.com/gortc/pkg/tree/master{/dir} https://github.com/gortc/pkg/blob/master{/dir}/{file}#L{line}">
    <meta http-equiv="refresh" content="0; url=https://godoc.org/gortc.io/pkg">

Nothing to see here; move along.
`, "pkg", name, -1)
		http.HandleFunc("/" + name + "/", func(w http.ResponseWriter, r *http.Request) {
			defer r.Body.Close()
			fmt.Fprint(w, body)
		})
	}

	http.HandleFunc("/x/sdp", func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		log.Println("http:", r.Method, "request from", r.RemoteAddr)
		if r.Method == http.MethodGet {
			http.Redirect(w, r, "/x/sdp/", http.StatusPermanentRedirect)
			return
		}
		s := sdp.Session{}
		data, err := ioutil.ReadAll(r.Body)
		if err != nil {
			log.Println("http: ReadAll body failed:", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		if s, err = sdp.DecodeSession(data, s); err != nil {
			log.Println("http: failed to decode sdp session:", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		for k, v := range s {
			fmt.Fprintf(w, `<p class="attribute">%02d %s</p>`+"\n", k, v)
			if v.Type != sdp.TypeAttribute {
				continue
			}
			if !bytes.HasPrefix(v.Value, []byte("candidate")) {
				continue
			}
			c := new(ice.Candidate)
			fmt.Fprintln(w, `<div class="stun-message">`)
			if err = ice.ParseAttribute(v.Value, c); err != nil {
				fmt.Fprintln(w, `<p class="error">failed to parse as candidate:`, err, "
")
				fmt.Fprintln(w, `</div>`)
				continue
			}
			fmt.Fprintln(w, "
parsed as candidate:", fmt.Sprintf("%+v", c), "
")
			if c.Type != ice.CandidateServerReflexive {
				fmt.Fprintln(w, `</div>`)
				continue
			}
			addr := fmt.Sprintf("%s:%d", c.ConnectionAddress, c.Port)
			m := messages.pop(addr)
			if m == nil {
				log.Println("http: no message for", addr, "in log")
				fmt.Fprintln(w, `<p class="warning">message from candidate not found in STUN log</p>`)
				fmt.Fprintln(w, `</div>`)
				continue
			}
			fmt.Fprintln(w, `<p class="success">message found in STUN log:`, m, `</p>`)
			for _, a := range m.Attributes {
				switch a.Type {
				case stun.AttrOrigin:
					fmt.Fprintf(w, "
STUN attribute %s: %q (len=%d)
", a.Type, a.Value, a.Length)
				default:
					fmt.Fprintf(w, "
STUN attribute %s: %v (len=%d)
", a.Type, a.Value, a.Length)
				}
			}
			var (
				b64             = base64.StdEncoding.EncodeToString(m.Raw)
				messageCRC64    = crc64.Checksum(m.Raw, crc64.MakeTable(crc64.ISO))
				clipID          = fmt.Sprintf("crc64-%d", messageCRC64)
				ua              = user_agent.New(r.Header.Get("User-agent"))
				bName, bVersion = ua.Browser()
			)
			if err = csvLog.Write([]string{
				addr,
				b64,
				fmt.Sprintf("%d", messageCRC64),
				bName,
				bVersion,
				ua.OS(),
			}); err != nil {
				log.Fatalln("log: failed to write:", err)
			}
			csvLog.Flush()
			fmt.Fprintln(w, `<p>dumped: <code id="`+clipID+`">stun-decode`, b64, `
				<button class="btn" data-clipboard-target="#`+clipID+`">copy</button>

`)
			fmt.Fprintln(w, `<p>crc64: <code>`, messageCRC64, `</code></p>`)
			fmt.Fprintln(w, `</div>`)
		}
	})

	var (
		addrSTUN = fmt.Sprintf(":%d", *portSTUN)
		addrHTTP = fmt.Sprintf("%s:%d", *hostHTTP, *portHTTP)
	)
	log.Println("Listening udp", addrSTUN)
	c, err := net.ListenPacket("udp", addrSTUN)
	if err != nil {
		log.Fatalf("Failed to bind udp on %s: %s", addrSTUN, err)
	}
	defer c.Close()

	// spawning storage garbage collector
	go messages.gc()

	// spawning STUN server
	go func(conn net.PacketConn) {
		log.Println("Started STUN server on", conn.LocalAddr())
		var (
			res = new(stun.Message)
			req = new(stun.Message)
			buf = make([]byte, 1024)
		)
		for {
			// ReadFrom c to buf
			n, addr, err := c.ReadFrom(buf)
			if err != nil {
				log.Fatalln("c.ReadFrom:", err)
			}
			log.Printf("udp: got packet len(%d) from %s", n, addr)
			// processing binding request
			if err = processUDPPacket(addr, buf[:n], req, res); err != nil {
				log.Println("failed to process UDP packet:", err, "from addr", addr)
			} else {
				log.Printf("stun: parsed message %q from %s", req, addr)
				if _, err = c.WriteTo(res.Raw, addr); err != nil {
					log.Println("failed to send packet:", err)
				}
			}
			res.Reset()
			req.Reset()
		}

	}(c)
	log.Println("Listening http", addrHTTP)
	log.Fatal(http.ListenAndServe(addrHTTP, nil))
}
<|endoftext|>


<commit_before>// Copyright 2014 The Hanoverd 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 main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"

	"golang.org/x/sys/unix"

	"github.com/codegangsta/cli"
	"github.com/docker/docker/pkg/nat"
	"github.com/fsouza/go-dockerclient"
	"github.com/pwaller/barrier"
	"github.com/scraperwiki/hookbot/pkg/listen"

	"github.com/scraperwiki/hanoverd/pkg/builder"
	"github.com/scraperwiki/hanoverd/pkg/iptables"
	"github.com/scraperwiki/hanoverd/pkg/source"
	"github.com/scraperwiki/hanoverd/pkg/util"
)

// DockerErrorStatus returns the HTTP status code represented by `err` or Status
// OK if no error or 0 if err != nil and is not a docker error.
func DockerErrorStatus(err error) int {
	if err, ok := err.(*docker.Error); ok {
		return err.Status
	}
	if err == nil {
		return http.StatusOK
	}
	return 0
}

type Options struct {
	env, publish, volumes []string

	containerArgs  []string
	ports          nat.PortSet
	portBindings   nat.PortMap
	statusURI      string
	disableOverlap bool
}

type UpdateEvent struct {
	Payload       []byte // input
	OutputStream  io.Writer
	Obtained      barrier.Barrier
	BuildComplete chan<- struct{}
}

// Determine if stdin is connected without blocking
func IsStdinReadable() bool {
	unix.SetNonblock(int(os.Stdin.Fd()), true)
	_, err := os.Stdin.Read([]byte{0})
	unix.SetNonblock(int(os.Stdin.Fd()), false)
	return err != io.EOF
}

func main() {
	app := cli.NewApp()

	app.Name = "hanoverd"
	app.Usage = "handover docker containers"

	// Use `hanoverd version` rather than `hanoverd -v`
	app.HideVersion = true

	// Made by `go generate` populating version.go via `git describe`.
	app.Version = Version

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "disable-overlap",
			Usage: "shut down old container before starting new one",
		},
		cli.StringSliceFlag{
			Name:  "env, e",
			Usage: "environment variables to pass (reads from env if = omitted)",
			Value: &cli.StringSlice{},
		},
		cli.StringSliceFlag{
			Name:  "publish, p",
			Usage: "ports to publish (same syntax as docker)",
			Value: &cli.StringSlice{},
		},
		cli.StringSliceFlag{
			Name:  "volume, v",
			Usage: "Bind mount a volume",
			Value: &cli.StringSlice{},
		},
		cli.StringFlag{
			Name:  "status-uri",
			Usage: "specify URI which returns 200 OK when functioning correctly",
			Value: "/",
		},
		cli.StringFlag{
			Name:   "hookbot",
			Usage:  "url of hookbot websocket endpoint to monitor for updates",
			EnvVar: "HOOKBOT_URL",
		},
	}

	app.Action = ActionRun

	app.Commands = []cli.Command{
		{
			Name:   "builder",
			Action: builder.Action,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "listen",
					Usage:  "url of hookbot websocket endpoint to monitor for updates",
					EnvVar: "HOOKBOT_MONITOR_URL",
				},
				cli.StringFlag{
					Name:   "docker-notify",
					Usage:  "url of hookbot pub endpoint to notify on complete build",
					EnvVar: "HOOKBOT_DOCKER_NOTIFY_URL",
				},
			},
		},
		{
			Name:   "version",
			Action: cli.ShowVersion,
		},
	}

	app.RunAndExitOnError()
}

func ActionRun(c *cli.Context) {
	var err error

	options := Options{}
	options.volumes = c.StringSlice("volume")
	options.env = makeEnv(c.StringSlice("env"))
	options.statusURI = c.String("status-uri")
	options.disableOverlap = c.Bool("disable-overlap")

	containerName := "hanoverd"
	var imageSource source.ImageSource

	if c.GlobalString("hookbot") != "" {

		hookbotURL := c.GlobalString("hookbot")
		containerName, imageSource, err = source.GetSourceFromHookbot(hookbotURL)
		if err != nil {
			log.Fatalf("Failed to parse hookbot source: %v", err)
		}

		options.containerArgs = c.Args()

	} else if len(c.Args()) == 0 {
		imageSource = &source.CwdSource{}

	} else {
		first := c.Args().First()
		args := c.Args()[1:]

		if first == "@" {
			// If the first arg is "@", then use the Cwd
			imageSource = &source.CwdSource{}
		} else {
			// The argument is a repository[:tag] to pull and run.
			imageSource = source.DockerPullSourceFromImage(first)
		}
		options.containerArgs = args
	}

	if imageSource == nil {
		log.Fatalf("No image source specified")
	}

	if err := iptables.CheckIPTables(); err != nil {
		log.Fatal("Unable to run `iptables -L`, see README (", err, ")")
	}

	options.ports, options.portBindings, err = nat.ParsePortSpecs(c.StringSlice("publish"))
	if err != nil {
		log.Fatalln("--publish:", err)
	}

	log.Println("Hanoverd")

	var wg sync.WaitGroup
	defer wg.Wait()

	// Fired when we're signalled to exit
	var dying barrier.Barrier
	defer dying.Fall()

	if IsStdinReadable() {
		log.Println("Press CTRL-D to exit")
		go func() {
			defer dying.Fall()
			defer log.Println("Stdin closed, exiting...")

			// Await Stdin closure, don't care about errors
			_, _ = io.Copy(ioutil.Discard, os.Stdin)
		}()
	}

	events := make(chan *UpdateEvent, 1)
	originalEvent := &UpdateEvent{}
	events <- originalEvent

	// SIGHUP handler
	go func() {
		sig := make(chan os.Signal)
		signal.Notify(sig, unix.SIGHUP)
		for value := range sig {
			log.Printf("Received signal %s", value)
			// Resend the original event
			events <- originalEvent
		}
	}()

	// SIGTERM, SIGINT handler
	go func() {
		defer dying.Fall()

		var value os.Signal

		defer log.Printf("Received signal %v", value)

		sig := make(chan os.Signal)
		signal.Notify(sig, unix.SIGTERM, unix.SIGINT)
		value = <-sig
	}()

	if c.GlobalString("hookbot") != "" {
		go MonitorHookbot(c.GlobalString("hookbot"), events)
	}

	go loop(containerName, imageSource, &wg, &dying, options, events)

	<-dying.Barrier()
}

func MonitorHookbot(target string, notify chan<- *UpdateEvent) {
	finish := make(chan struct{})
	header := http.Header{}
	events, errs := listen.RetryingWatch(target, header, finish)

	log.Println("Monitoring hookbot")

	go func() {
		for err := range errs {
			log.Printf("Error in MonitorHookbot: %v", err)
		}
	}()

	for payload := range events {

		log.Printf("Signalled via hookbot")
		// data := map[string]string{}
		// err := json.Unmarshal(ev, &data)
		// if err != nil {
		// 	log.Printf("Failed to parse message: %v", err)
		// 	continue
		// }

		done := make(chan struct{})

		outBound := &UpdateEvent{}
		outBound.BuildComplete = done
		outBound.Payload = payload
		// outBound.Source.Type = GithubRepository
		// outBound.Source.githubURL = "github.com/scraperwiki/hookbot"
		// outBound.Source.githubRef = data["SHA"]

		notify <- outBound

		<-outBound.Obtained.Barrier()

		// <-done
		log.Printf("--- Build completed %v ---", "TODO(pwaller): Determine name from payload")
	}
}

// Make an env []string from a list of options specified on the cmdline.
func makeEnv(opts []string) []string {
	var env []string
	for _, envVar := range opts {
		if strings.Contains(envVar, "=") {
			env = append(env, envVar)
		} else {
			env = append(env, fmt.Sprint(envVar, "=", os.Getenv(envVar)))
		}
	}
	return env
}

// Main loop managing the lifecycle of all containers.
func loop(
	containerName string,
	imageSource source.ImageSource,
	wg *sync.WaitGroup,
	dying *barrier.Barrier,
	options Options,
	events <-chan *UpdateEvent,
) {
	client, err := util.DockerConnect()
	if err != nil {
		dying.Fall()
		log.Println("Connecting to Docker failed:", err)
		return
	}

	flips := make(chan *Container)
	go flipper(wg, options, flips)

	var i int

	for event := range events {

		name := fmt.Sprint(containerName, "_", i)
		i++

		log.Printf("New container starting: %q", name)
		if options.disableOverlap {
			log.Printf("Overlap switched off, killing old")
			flips <- nil
		}

		c := NewContainer(client, name, wg)
		c.Args = options.containerArgs
		c.Env = options.env
		c.Volumes = options.volumes
		c.StatusURI = options.statusURI

		c.Obtained.Forward(&event.Obtained)

		// Global exit should cause container exit
		dying.Forward(&c.Closing)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			if imageSource == nil {
				log.Printf("No image source specified")
				c.Failed.Fall()
				return
			}

			status, err := c.Run(imageSource, event.Payload)
			if err != nil {
				log.Println("Container run failed:", strings.TrimSpace(err.Error()))
				return
			}
			log.Println("container", c.Name, "quit, exit status:", status)
		}(c)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			log.Printf("Awaiting container fate: %q %q", c.Name, c.StatusURI)
			select {
			case <-c.Failed.Barrier():
				log.Println("Container failed before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Superceded.Barrier():
				log.Println("Container superceded before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Closing.Barrier():
				log.Println("Container closed before going live:", c.Name)
				return

			case <-c.Ready.Barrier():
			}

			log.Println("Container going live:", c.Name)

			flips <- c
		}(c)
	}
}

// Manage firewall flips
func flipper(
	wg *sync.WaitGroup,
	options Options,
	newContainers <-chan *Container,
) {
	var live *Container

	for container := range newContainers {
		if container == nil {
			// A nil container is an instruction to just kill the
			// running container. (e.g, for --disable-overlap)
			if live != nil {
				live.Closing.Fall()
			}
			live = nil
			continue
		}

		err := flip(wg, options, container)
		if err != nil {
			container.Failed.Fall()
			// Don't flip the firewall rules if there was a problem.
			continue
		}

		if live != nil {
			live.Closing.Fall()
		}

		live = container
	}
}

// Make container receive live traffic
func flip(wg *sync.WaitGroup, options Options, container *Container) error {

	removal := []func(){}

	defer func() {
		// Block main exit until firewall rule has been removed
		wg.Add(1)
		go func() {
			defer wg.Done()

			<-container.Closing.Barrier()

			for _, remove := range removal {
				remove()
			}
		}()
	}()

	for internalPort, bindings := range options.portBindings {
		if mappedPort, ok := container.MappedPort(internalPort.Int()); ok {
			for _, binding := range bindings {
				var public int
				_, err := fmt.Sscan(binding.HostPort, &public)
				if err != nil {
					// If no public port specified, use same port as internal port
					public = internalPort.Int()
				}

				ipAddress := container.container.NetworkSettings.IPAddress
				remove, err := iptables.ConfigureRedirect(public, mappedPort, ipAddress)
				if err != nil {
					// Firewall rule didn't get applied.
					err := fmt.Errorf(
						"Firewall rule application failed: %q (public: %v, private: %v)",
						err, public, internalPort)
					container.err(err)
					return err
				}

				removal = append(removal, remove)
			}
		} else {
			err := fmt.Errorf("Docker image not exposing port %v!", internalPort)
			container.err(err)
			return err
		}
	}

	return nil
}
<commit_msg>Fix container superceding<commit_after>// Copyright 2014 The Hanoverd 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 main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"

	"golang.org/x/sys/unix"

	"github.com/codegangsta/cli"
	"github.com/docker/docker/pkg/nat"
	"github.com/fsouza/go-dockerclient"
	"github.com/pwaller/barrier"
	"github.com/scraperwiki/hookbot/pkg/listen"

	"github.com/scraperwiki/hanoverd/pkg/builder"
	"github.com/scraperwiki/hanoverd/pkg/iptables"
	"github.com/scraperwiki/hanoverd/pkg/source"
	"github.com/scraperwiki/hanoverd/pkg/util"
)

// DockerErrorStatus returns the HTTP status code represented by `err` or Status
// OK if no error or 0 if err != nil and is not a docker error.
func DockerErrorStatus(err error) int {
	if err, ok := err.(*docker.Error); ok {
		return err.Status
	}
	if err == nil {
		return http.StatusOK
	}
	return 0
}

type Options struct {
	env, publish, volumes []string

	containerArgs  []string
	ports          nat.PortSet
	portBindings   nat.PortMap
	statusURI      string
	disableOverlap bool
}

type UpdateEvent struct {
	Payload       []byte // input
	OutputStream  io.Writer
	Obtained      barrier.Barrier
	BuildComplete chan<- struct{}
}

// Determine if stdin is connected without blocking
func IsStdinReadable() bool {
	unix.SetNonblock(int(os.Stdin.Fd()), true)
	_, err := os.Stdin.Read([]byte{0})
	unix.SetNonblock(int(os.Stdin.Fd()), false)
	return err != io.EOF
}

func main() {
	app := cli.NewApp()

	app.Name = "hanoverd"
	app.Usage = "handover docker containers"

	// Use `hanoverd version` rather than `hanoverd -v`
	app.HideVersion = true

	// Made by `go generate` populating version.go via `git describe`.
	app.Version = Version

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "disable-overlap",
			Usage: "shut down old container before starting new one",
		},
		cli.StringSliceFlag{
			Name:  "env, e",
			Usage: "environment variables to pass (reads from env if = omitted)",
			Value: &cli.StringSlice{},
		},
		cli.StringSliceFlag{
			Name:  "publish, p",
			Usage: "ports to publish (same syntax as docker)",
			Value: &cli.StringSlice{},
		},
		cli.StringSliceFlag{
			Name:  "volume, v",
			Usage: "Bind mount a volume",
			Value: &cli.StringSlice{},
		},
		cli.StringFlag{
			Name:  "status-uri",
			Usage: "specify URI which returns 200 OK when functioning correctly",
			Value: "/",
		},
		cli.StringFlag{
			Name:   "hookbot",
			Usage:  "url of hookbot websocket endpoint to monitor for updates",
			EnvVar: "HOOKBOT_URL",
		},
	}

	app.Action = ActionRun

	app.Commands = []cli.Command{
		{
			Name:   "builder",
			Action: builder.Action,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:   "listen",
					Usage:  "url of hookbot websocket endpoint to monitor for updates",
					EnvVar: "HOOKBOT_MONITOR_URL",
				},
				cli.StringFlag{
					Name:   "docker-notify",
					Usage:  "url of hookbot pub endpoint to notify on complete build",
					EnvVar: "HOOKBOT_DOCKER_NOTIFY_URL",
				},
			},
		},
		{
			Name:   "version",
			Action: cli.ShowVersion,
		},
	}

	app.RunAndExitOnError()
}

func ActionRun(c *cli.Context) {
	var err error

	options := Options{}
	options.volumes = c.StringSlice("volume")
	options.env = makeEnv(c.StringSlice("env"))
	options.statusURI = c.String("status-uri")
	options.disableOverlap = c.Bool("disable-overlap")

	containerName := "hanoverd"
	var imageSource source.ImageSource

	if c.GlobalString("hookbot") != "" {

		hookbotURL := c.GlobalString("hookbot")
		containerName, imageSource, err = source.GetSourceFromHookbot(hookbotURL)
		if err != nil {
			log.Fatalf("Failed to parse hookbot source: %v", err)
		}

		options.containerArgs = c.Args()

	} else if len(c.Args()) == 0 {
		imageSource = &source.CwdSource{}

	} else {
		first := c.Args().First()
		args := c.Args()[1:]

		if first == "@" {
			// If the first arg is "@", then use the Cwd
			imageSource = &source.CwdSource{}
		} else {
			// The argument is a repository[:tag] to pull and run.
			imageSource = source.DockerPullSourceFromImage(first)
		}
		options.containerArgs = args
	}

	if imageSource == nil {
		log.Fatalf("No image source specified")
	}

	if err := iptables.CheckIPTables(); err != nil {
		log.Fatal("Unable to run `iptables -L`, see README (", err, ")")
	}

	options.ports, options.portBindings, err = nat.ParsePortSpecs(c.StringSlice("publish"))
	if err != nil {
		log.Fatalln("--publish:", err)
	}

	log.Println("Hanoverd")

	var wg sync.WaitGroup
	defer wg.Wait()

	// Fired when we're signalled to exit
	var dying barrier.Barrier
	defer dying.Fall()

	if IsStdinReadable() {
		log.Println("Press CTRL-D to exit")
		go func() {
			defer dying.Fall()
			defer log.Println("Stdin closed, exiting...")

			// Await Stdin closure, don't care about errors
			_, _ = io.Copy(ioutil.Discard, os.Stdin)
		}()
	}

	events := make(chan *UpdateEvent, 1)
	originalEvent := &UpdateEvent{}
	events <- originalEvent

	// SIGHUP handler
	go func() {
		sig := make(chan os.Signal)
		signal.Notify(sig, unix.SIGHUP)
		for value := range sig {
			log.Printf("Received signal %s", value)
			// Resend the original event
			events <- originalEvent
		}
	}()

	// SIGTERM, SIGINT handler
	go func() {
		defer dying.Fall()

		var value os.Signal

		defer log.Printf("Received signal %v", value)

		sig := make(chan os.Signal)
		signal.Notify(sig, unix.SIGTERM, unix.SIGINT)
		value = <-sig
	}()

	if c.GlobalString("hookbot") != "" {
		go MonitorHookbot(c.GlobalString("hookbot"), events)
	}

	go loop(containerName, imageSource, &wg, &dying, options, events)

	<-dying.Barrier()
}

func MonitorHookbot(target string, notify chan<- *UpdateEvent) {
	finish := make(chan struct{})
	header := http.Header{}
	events, errs := listen.RetryingWatch(target, header, finish)

	log.Println("Monitoring hookbot")

	go func() {
		for err := range errs {
			log.Printf("Error in MonitorHookbot: %v", err)
		}
	}()

	for payload := range events {

		log.Printf("Signalled via hookbot")
		// data := map[string]string{}
		// err := json.Unmarshal(ev, &data)
		// if err != nil {
		// 	log.Printf("Failed to parse message: %v", err)
		// 	continue
		// }

		done := make(chan struct{})

		outBound := &UpdateEvent{}
		outBound.BuildComplete = done
		outBound.Payload = payload
		// outBound.Source.Type = GithubRepository
		// outBound.Source.githubURL = "github.com/scraperwiki/hookbot"
		// outBound.Source.githubRef = data["SHA"]

		notify <- outBound

		<-outBound.Obtained.Barrier()

		// <-done
		log.Printf("--- Build completed %v ---", "TODO(pwaller): Determine name from payload")
	}
}

// Make an env []string from a list of options specified on the cmdline.
func makeEnv(opts []string) []string {
	var env []string
	for _, envVar := range opts {
		if strings.Contains(envVar, "=") {
			env = append(env, envVar)
		} else {
			env = append(env, fmt.Sprint(envVar, "=", os.Getenv(envVar)))
		}
	}
	return env
}

// Main loop managing the lifecycle of all containers.
func loop(
	containerName string,
	imageSource source.ImageSource,
	wg *sync.WaitGroup,
	dying *barrier.Barrier,
	options Options,
	events <-chan *UpdateEvent,
) {
	client, err := util.DockerConnect()
	if err != nil {
		dying.Fall()
		log.Println("Connecting to Docker failed:", err)
		return
	}

	flips := make(chan *Container)
	go flipper(wg, options, flips)

	var i int
	supercede := func() {}

	for event := range events {

		name := fmt.Sprint(containerName, "_", i)
		i++

		log.Printf("New container starting: %q", name)
		if options.disableOverlap {
			log.Printf("Overlap switched off, killing old")
			flips <- nil
		}

		c := NewContainer(client, name, wg)
		c.Args = options.containerArgs
		c.Env = options.env
		c.Volumes = options.volumes
		c.StatusURI = options.statusURI

		c.Obtained.Forward(&event.Obtained)

		// Global exit should cause container exit
		dying.Forward(&c.Closing)

		// Cancel an existing startup, if there is one.
		supercede()
		supercede = c.Superceded.Fall

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			if imageSource == nil {
				log.Printf("No image source specified")
				c.Failed.Fall()
				return
			}

			status, err := c.Run(imageSource, event.Payload)
			if err != nil {
				log.Println("Container run failed:", strings.TrimSpace(err.Error()))
				return
			}
			log.Println("container", c.Name, "quit, exit status:", status)
		}(c)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			log.Printf("Awaiting container fate: %q %q", c.Name, c.StatusURI)
			select {
			case <-c.Failed.Barrier():
				log.Println("Container failed before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Superceded.Barrier():
				log.Println("Container superceded before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Closing.Barrier():
				log.Println("Container closed before going live:", c.Name)
				return

			case <-c.Ready.Barrier():
			}

			log.Println("Container going live:", c.Name)

			flips <- c
		}(c)
	}
}

// Manage firewall flips
func flipper(
	wg *sync.WaitGroup,
	options Options,
	newContainers <-chan *Container,
) {
	var live *Container

	for container := range newContainers {
		if container == nil {
			// A nil container is an instruction to just kill the
			// running container. (e.g, for --disable-overlap)
			if live != nil {
				live.Closing.Fall()
			}
			live = nil
			continue
		}

		err := flip(wg, options, container)
		if err != nil {
			container.Failed.Fall()
			// Don't flip the firewall rules if there was a problem.
			continue
		}

		if live != nil {
			live.Closing.Fall()
		}

		live = container
	}
}

// Make container receive live traffic
func flip(wg *sync.WaitGroup, options Options, container *Container) error {

	removal := []func(){}

	defer func() {
		// Block main exit until firewall rule has been removed
		wg.Add(1)
		go func() {
			defer wg.Done()

			<-container.Closing.Barrier()

			for _, remove := range removal {
				remove()
			}
		}()
	}()

	for internalPort, bindings := range options.portBindings {
		if mappedPort, ok := container.MappedPort(internalPort.Int()); ok {
			for _, binding := range bindings {
				var public int
				_, err := fmt.Sscan(binding.HostPort, &public)
				if err != nil {
					// If no public port specified, use same port as internal port
					public = internalPort.Int()
				}

				ipAddress := container.container.NetworkSettings.IPAddress
				remove, err := iptables.ConfigureRedirect(public, mappedPort, ipAddress)
				if err != nil {
					// Firewall rule didn't get applied.
					err := fmt.Errorf(
						"Firewall rule application failed: %q (public: %v, private: %v)",
						err, public, internalPort)
					container.err(err)
					return err
				}

				removal = append(removal, remove)
			}
		} else {
			err := fmt.Errorf("Docker image not exposing port %v!", internalPort)
			container.err(err)
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"os"
	"strings"
	"time"
	"unicode/utf8"
)

var versionName = "2.0.0"

var message = `
Hozumi Command

USAGE:
  hozumi [option] param1 param2 param3...

VERSION:
  %s

OPTIONS:
  -h, --help                            He displays help message.
  -v, --version                         He displays his version.
  -s, --speed {low|middle|high}         He displays by specified speed.
  -c. --cool                            He sometimes shouts, "Cool".
  -p  --parallel                        He displays in parallel.
`

var opts struct {
	Help bool `short:"h" long:"help" description:"He displays help message."`
	Version bool `short:"v" long:"version" description:"He displays his version."`
	Speed string `short:"s" long:"speed" description:"He displays by specified speed." default:"middle"`
	Cool bool `short:"c" long:"cool" description:"He sometimes shouts, \"Cool\"."`
	Parallel bool `short:"p" long:"parallel" description:"He displeys in parallel."`
}

func main() {
  hozumiWriter := setup()
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

  go hozumiWriter.write()
loop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			break loop
		case termbox.EventResize:
			break loop
		}
	}
}

type HozumiWriter struct {
	contents                 []string
	intervalDisplayRow       time.Duration
	intervalDisplayOneLetter time.Duration
	intervalDisplayCool      time.Duration
	cool                     bool
	dashboard                []string
}

func setup() *HozumiWriter {
	p := flags.NewParser(&opts, flags.PrintErrors)
	args, err := p.Parse()

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

	if opts.Help {
		displayHelpMessage()
		os.Exit(0)
	}

	if opts.Version {
		fmt.Printf("Hozumi Command version (%s)\n", versionName)
		os.Exit(0)
	}

	writer := new(HozumiWriter)

	if len(args) > 0 {
		writer.contents = args
	} else {
		writer.contents = []string{"ほずみ"}
	}
	var intervalDisplayRow time.Duration
	var intervalDisplayOneLetter time.Duration

	if opts.Speed == "low" {
		intervalDisplayRow = 600 * time.Millisecond
		intervalDisplayOneLetter = 270 * time.Millisecond
	} else if opts.Speed == "middle" {
		intervalDisplayRow = 300 * time.Millisecond
		intervalDisplayOneLetter = 180 * time.Millisecond
	} else if opts.Speed == "high" {
		intervalDisplayRow = 150 * time.Millisecond
		intervalDisplayOneLetter = 90 * time.Millisecond
	} else if opts.Speed != "" {
		displayHelpMessage()
		os.Exit(1)
	}
	writer.intervalDisplayRow = intervalDisplayRow
	writer.intervalDisplayOneLetter = intervalDisplayOneLetter
	writer.cool = opts.Cool
	writer.intervalDisplayCool = 10 * time.Millisecond
	return writer
}

func displayHelpMessage() {
	fmt.Printf(message, versionName)
}

func (writer *HozumiWriter) write() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	_, ymax := termbox.Size()
	for {
		y := 0
		for ; y < ymax; {
			if opts.Parallel {
				writer.writer_contents_pararrel(y)
			} else {
				writer.write_contents(y)
			}
			y = y + len(writer.contents)
			if writer.cool {
				y++
			}
		}
		termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	}
}

func (writer *HozumiWriter) write_contents(row int) {
	for i, content := range writer.contents {
		writer.draw_row(content, row + i)
		time.Sleep(50 * time.Millisecond)
	}
	if writer.cool {
		writer.displayCool(row + len(writer.contents))
	}
}

func (writer *HozumiWriter) writer_contents_pararrel(row int) {
	var channum int
	if writer.cool {
		channum = len(writer.contents) + 1
	} else {
		channum = len(writer.contents)
	}

	c := make(chan int, channum)

	for i, content := range writer.contents {
		go func() {
			writer.draw_row(content, row + i)
			c <- 1
		}()
		time.Sleep(50 * time.Millisecond)
	}
	if writer.cool {
		go func() {
			writer.displayCool(row + len(writer.contents))
			c <- 1
		}()
	}
	for i := 0; i < channum; i++ {
		<-c
	}
}

func (writer *HozumiWriter) draw_row(message string, y int) {
	str := ""
	for _, letter := range strings.Split(message, "") {
		str = str + letter
		set_row(str, y, termbox.ColorDefault)
		termbox.Flush()
		time.Sleep(writer.intervalDisplayRow)
	}
	clear_row(y)
	time.Sleep(writer.intervalDisplayRow)
	str = ""
	for _, letter := range strings.Split(message, "") {
		str = str + letter
		set_row(str, y, termbox.ColorDefault)
		termbox.Flush()
		time.Sleep(writer.intervalDisplayOneLetter)
	}
	time.Sleep(writer.intervalDisplayRow)
}

func (writer *HozumiWriter) displayCool(y int) {
	content := "Cooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooool!"
	str := ""
	for _, letter := range strings.Split(content, "") {
		str = str + letter
		set_row(str, y, termbox.ColorYellow)
		termbox.Flush()
		time.Sleep(writer.intervalDisplayCool)
	}
}

func set_row(message string, y int, fg termbox.Attribute) {

	x := 0

	for len(message) > 0 {
		c, w := utf8.DecodeRuneInString(message)
		if c == utf8.RuneError {
			c = '?'
			w = 1
		}
		message = message[w:]
		termbox.SetCell(x, y, c, fg, termbox.ColorDefault)
		x += runewidth.RuneWidth(c)
	}
}

func clear_row(y int) {
	xmax, _ := termbox.Size()
	for x := 0; x < xmax; x++ {
		termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
	}
}
<commit_msg>Execute go fmt<commit_after>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"os"
	"strings"
	"time"
	"unicode/utf8"
)

var versionName = "2.0.0"

var message = `
Hozumi Command

USAGE:
  hozumi [option] param1 param2 param3...

VERSION:
  %s

OPTIONS:
  -h, --help                            He displays help message.
  -v, --version                         He displays his version.
  -s, --speed {low|middle|high}         He displays by specified speed.
  -c. --cool                            He sometimes shouts, "Cool".
  -p  --parallel                        He displays in parallel.
`

var opts struct {
	Help     bool   `short:"h" long:"help" description:"He displays help message."`
	Version  bool   `short:"v" long:"version" description:"He displays his version."`
	Speed    string `short:"s" long:"speed" description:"He displays by specified speed." default:"middle"`
	Cool     bool   `short:"c" long:"cool" description:"He sometimes shouts, \"Cool\"."`
	Parallel bool   `short:"p" long:"parallel" description:"He displeys in parallel."`
}

func main() {
	hozumiWriter := setup()
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	go hozumiWriter.write()
loop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			break loop
		case termbox.EventResize:
			break loop
		}
	}
}

type HozumiWriter struct {
	contents                 []string
	intervalDisplayRow       time.Duration
	intervalDisplayOneLetter time.Duration
	intervalDisplayCool      time.Duration
	cool                     bool
	dashboard                []string
}

func setup() *HozumiWriter {
	p := flags.NewParser(&opts, flags.PrintErrors)
	args, err := p.Parse()

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

	if opts.Help {
		displayHelpMessage()
		os.Exit(0)
	}

	if opts.Version {
		fmt.Printf("Hozumi Command version (%s)\n", versionName)
		os.Exit(0)
	}

	writer := new(HozumiWriter)

	if len(args) > 0 {
		writer.contents = args
	} else {
		writer.contents = []string{"ほずみ"}
	}
	var intervalDisplayRow time.Duration
	var intervalDisplayOneLetter time.Duration

	if opts.Speed == "low" {
		intervalDisplayRow = 600 * time.Millisecond
		intervalDisplayOneLetter = 270 * time.Millisecond
	} else if opts.Speed == "middle" {
		intervalDisplayRow = 300 * time.Millisecond
		intervalDisplayOneLetter = 180 * time.Millisecond
	} else if opts.Speed == "high" {
		intervalDisplayRow = 150 * time.Millisecond
		intervalDisplayOneLetter = 90 * time.Millisecond
	} else if opts.Speed != "" {
		displayHelpMessage()
		os.Exit(1)
	}
	writer.intervalDisplayRow = intervalDisplayRow
	writer.intervalDisplayOneLetter = intervalDisplayOneLetter
	writer.cool = opts.Cool
	writer.intervalDisplayCool = 10 * time.Millisecond
	return writer
}

func displayHelpMessage() {
	fmt.Printf(message, versionName)
}

func (writer *HozumiWriter) write() {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	_, ymax := termbox.Size()
	for {
		y := 0
		for y < ymax {
			if opts.Parallel {
				writer.writer_contents_pararrel(y)
			} else {
				writer.write_contents(y)
			}
			y = y + len(writer.contents)
			if writer.cool {
				y++
			}
		}
		termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	}
}

func (writer *HozumiWriter) write_contents(row int) {
	for i, content := range writer.contents {
		writer.draw_row(content, row+i)
		time.Sleep(50 * time.Millisecond)
	}
	if writer.cool {
		writer.displayCool(row + len(writer.contents))
	}
}

func (writer *HozumiWriter) writer_contents_pararrel(row int) {
	var channum int
	if writer.cool {
		channum = len(writer.contents) + 1
	} else {
		channum = len(writer.contents)
	}

	c := make(chan int, channum)

	for i, content := range writer.contents {
		go func() {
			writer.draw_row(content, row+i)
			c <- 1
		}()
		time.Sleep(50 * time.Millisecond)
	}
	if writer.cool {
		go func() {
			writer.displayCool(row + len(writer.contents))
			c <- 1
		}()
	}
	for i := 0; i < channum; i++ {
		<-c
	}
}

func (writer *HozumiWriter) draw_row(message string, y int) {
	str := ""
	for _, letter := range strings.Split(message, "") {
		str = str + letter
		set_row(str, y, termbox.ColorDefault)
		termbox.Flush()
		time.Sleep(writer.intervalDisplayRow)
	}
	clear_row(y)
	time.Sleep(writer.intervalDisplayRow)
	str = ""
	for _, letter := range strings.Split(message, "") {
		str = str + letter
		set_row(str, y, termbox.ColorDefault)
		termbox.Flush()
		time.Sleep(writer.intervalDisplayOneLetter)
	}
	time.Sleep(writer.intervalDisplayRow)
}

func (writer *HozumiWriter) displayCool(y int) {
	content := "Cooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooool!"
	str := ""
	for _, letter := range strings.Split(content, "") {
		str = str + letter
		set_row(str, y, termbox.ColorYellow)
		termbox.Flush()
		time.Sleep(writer.intervalDisplayCool)
	}
}

func set_row(message string, y int, fg termbox.Attribute) {

	x := 0

	for len(message) > 0 {
		c, w := utf8.DecodeRuneInString(message)
		if c == utf8.RuneError {
			c = '?'
			w = 1
		}
		message = message[w:]
		termbox.SetCell(x, y, c, fg, termbox.ColorDefault)
		x += runewidth.RuneWidth(c)
	}
}

func clear_row(y int) {
	xmax, _ := termbox.Size()
	for x := 0; x < xmax; x++ {
		termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
	}
}
<|endoftext|>


<commit_before>package main
import (
	"flag"
	"os"
	"fmt"
	"path/filepath"
	"os/exec"
	"bytes"
	"strings"
	"time"
	"errors"
	"log"
)

var locks = flag.String("lock", "/tmp/lockfiles/", "where to look for lockfiles")
var lockDur = flag.Int("duration", 30, "duration in minutes for which lock files are considered valid")

func getRunningContainers() ([]string, error) {
	containers := make([]string, 0)
	cmd := exec.Command("docker", "ps", "-q")
	out := bytes.Buffer{}
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return containers, err
	}
	containers = strings.Split(out.String(), "\n")
	for i := range(containers) {
		// remove empty container IDs
		if containers[i] == "" {
			containers = append(containers[:i], containers[i+1:]...)
		}
	}
	return containers, nil
}

func killContainer(containerId string) error {
	out := bytes.Buffer{}
	cmd := exec.Command("docker", "kill", containerId)
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func killAllRunningContainers() error {
	containers, err := getRunningContainers()
	if err != nil {
		return err
	}
	for i := range(containers) {
		killContainer(containers[i])
	}
	return nil
}

// kill all containers or die trying
func firstDegree() {
	for {
		running, err:= getRunningContainers()
		if err != nil {
			log.Println(err)
		}
		if len(running) == 0 {
			break
		}
		err = killAllRunningContainers()
		if err != nil {
			log.Println(err)
		}
	}
}

func lockIsStale(lockFile string) (bool, error) {
	info, err := os.Stat(lockFile)
	if err != nil {
		return false, err
	}
	lockAge := time.Now().Sub(info.ModTime())
	if lockAge > time.Minute * time.Duration(*lockDur) {
		return true, nil
	} else {
		return false, nil
	}
}

func main() {
	flag.Parse()

	log.Println("")
	log.Println("         `( ◔ ౪◔)´")
	log.Println("                   dozey")
	log.Println("")
	log.Println(fmt.Sprintf("locks valid for %vm, lock: %v", *lockDur, *locks))

	fh, err := os.Open(*locks)
	if err != nil {
		log.Println(err)
	}
	defer fh.Close()
	locksFh, err := fh.Stat()
	if err != nil {
		panic(err)
		return
	}

	if locksFh.IsDir() {
		// locks is a directory
		log.Println("lock is a directory, scanning")
		fileList := []string{}
		err := filepath.Walk(*locks, func(path string, f os.FileInfo, err error) error {
			if ! f.IsDir() {
				fileList = append(fileList, path)
			}
			return nil
		})
		if err != nil {
			panic(err)
		}
		if (len(fileList) == 0) {
			log.Println("no locks found, killing containers")
			firstDegree()
		} else {
			counter := 0
			for i := range (fileList) {
				isStale, err := lockIsStale(fileList[i])
				if err != nil {
					panic(err)
				}
				if isStale {
					log.Println(fmt.Sprintf("found stale lock: %v, continuing..", fileList[i]))
				} else {
					log.Println("valid lock found, exiting...")
					return
				}
				counter++
			}
			log.Println(fmt.Sprintf("%v lock(s) checked", counter))
		}
	} else if locksFh.Mode().IsRegular() {
			// locks is a file
			log.Println("lock is a file, checking...")
			isStale, err := lockIsStale(*locks)
			if err != nil {
				panic(err)
			}
			if isStale {
				log.Println("WARNING: stale lock, killing containers and shutting down")
				firstDegree()
			} else {
				log.Println("valid lock found, exiting.")
			}
	} else {
		panic(errors.New(fmt.Sprintf("fucked up lockfile. -lock=%s", *locks)))
	}
	log.Println("shutting down...")
}
<commit_msg>added optional sleep argument to wait for logs to flush or whatever<commit_after>package main
import (
	"flag"
	"os"
	"fmt"
	"path/filepath"
	"os/exec"
	"bytes"
	"strings"
	"time"
	"errors"
	"log"
)

var locks = flag.String("lock", "/tmp/lockfiles/", "where to look for lockfiles")
var lockDur = flag.Int("duration", 30, "duration in minutes for which lock files are considered valid")
var sleepTime = flag.Int("sleep", 0, "duration to sleep at the end of script before exit 0")

func getRunningContainers() ([]string, error) {
	containers := make([]string, 0)
	cmd := exec.Command("docker", "ps", "-q")
	out := bytes.Buffer{}
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		return containers, err
	}
	containers = strings.Split(out.String(), "\n")
	for i := range(containers) {
		// remove empty container IDs
		if containers[i] == "" {
			containers = append(containers[:i], containers[i+1:]...)
		}
	}
	return containers, nil
}

func killContainer(containerId string) error {
	out := bytes.Buffer{}
	cmd := exec.Command("docker", "kill", containerId)
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Run()
	if err != nil {
		return err
	}
	return nil
}

func killAllRunningContainers() error {
	containers, err := getRunningContainers()
	if err != nil {
		return err
	}
	for i := range(containers) {
		killContainer(containers[i])
	}
	return nil
}

// kill all containers or die trying
func firstDegree() {
	for {
		running, err:= getRunningContainers()
		if err != nil {
			log.Println(err)
		}
		if len(running) == 0 {
			break
		}
		err = killAllRunningContainers()
		if err != nil {
			log.Println(err)
		}
	}
}

func lockIsStale(lockFile string) (bool, error) {
	info, err := os.Stat(lockFile)
	if err != nil {
		return false, err
	}
	lockAge := time.Now().Sub(info.ModTime())
	if lockAge > time.Minute * time.Duration(*lockDur) {
		return true, nil
	} else {
		return false, nil
	}
}

func main() {
	flag.Parse()

	log.Println("")
	log.Println("         `( ◔ ౪◔)´")
	log.Println("                   dozey")
	log.Println("")
	log.Println(fmt.Sprintf("locks valid for %vm, lock: %v", *lockDur, *locks))

	fh, err := os.Open(*locks)
	if err != nil {
		log.Println(err)
	}
	defer fh.Close()
	locksFh, err := fh.Stat()
	if err != nil {
		panic(err)
		return
	}

	if locksFh.IsDir() {
		// locks is a directory
		log.Println("lock is a directory, scanning")
		fileList := []string{}
		err := filepath.Walk(*locks, func(path string, f os.FileInfo, err error) error {
			if ! f.IsDir() {
				fileList = append(fileList, path)
			}
			return nil
		})
		if err != nil {
			panic(err)
		}
		if (len(fileList) == 0) {
			log.Println("no locks found, killing containers")
			firstDegree()
		} else {
			counter := 0
			for i := range (fileList) {
				isStale, err := lockIsStale(fileList[i])
				if err != nil {
					panic(err)
				}
				if isStale {
					log.Println(fmt.Sprintf("found stale lock: %v, continuing..", fileList[i]))
				} else {
					panic("valid lock found, exiting...")
				}
				counter++
			}
			log.Println(fmt.Sprintf("%v lock(s) checked", counter))
		}
	} else if locksFh.Mode().IsRegular() {
			// locks is a file
			log.Println("lock is a file, checking...")
			isStale, err := lockIsStale(*locks)
			if err != nil {
				panic(err)
			}
			if isStale {
				log.Println("WARNING: stale lock, killing containers and shutting down")
				firstDegree()
			} else {
				panic("valid lock found, exiting.")
			}
	} else {
		panic(errors.New(fmt.Sprintf("fucked up lockfile. -lock=%s", *locks)))
	}
	log.Println("shutting down...")
	time.Sleep(time.Second * time.Duration(*sleepTime))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/docopt/docopt-go"
	"github.com/ghodss/yaml"
)

func readData(format string, filename string) []byte {
	var bytes []byte
	if filename == "-" {
		bytes, _ = ioutil.ReadAll(os.Stdin)
	} else {
		bytes, _ = ioutil.ReadFile(os.Args[len(os.Args)-1])
	}
	return bytes
}

func parseData(input_data []byte, format string) (parsed_data interface{}, err error) {
	// TODO: Support more formats :)
	err = yaml.Unmarshal(input_data, &parsed_data)
	return parsed_data, err
}

func outputData(input_data interface{}, format string) (output_data []byte, err error) {
	// TODO: Support more formats
	if format == "json" {
		output_data, err = json.MarshalIndent(input_data, "", "  ")
		// TODO: Detect auto better
	} else if format == "yaml" || format == "yml" || format == "auto" {
		output_data, err = yaml.Marshal(input_data)
	} else {
		fmt.Println(string(json))
		return 0
	}
}

func parseArgs() map[string]interface{} {
	usage := `uq - Universal (de)serializer

Usage:
  uq [-s FORMAT] [-t FORMAT] [FILE]

Options:
  -s <FORMAT>, --source <FORMAT>  Specify input format. [default: auto]
  -t <FORMAT>, --target <FORMAT>  Specify output format. [default: auto]
  -h --help     Show this screen
  --version     Show version

Formats:
  * json
  * yaml|yml
`

	arguments, _ := docopt.Parse(usage, nil, true, "0.0.1", false)
	return arguments
}

func main() {
	args := parseArgs()
	fmt.Print("args: ")
	fmt.Println(args)
	var filename string
	if args["FILE"] == nil {
		filename = "-"
	} else {
		filename = args["FILE"].(string)
	}
	data := readData(args["--source"].(string), filename)
	exitcode := outputData(data)
	os.Exit(exitcode)
}
<commit_msg>Use bytes and interface<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/docopt/docopt-go"
	"github.com/ghodss/yaml"
)

func readData(filename string) (bytes []byte, err error) {
	if filename == "-" {
		bytes, err = ioutil.ReadAll(os.Stdin)
	} else {
		bytes, err = ioutil.ReadFile(os.Args[len(os.Args)-1])
	}
	return bytes, err
}

func parseData(input_data []byte, format string) (parsed_data interface{}, err error) {
	// TODO: Support more formats :)
	err = yaml.Unmarshal(input_data, &parsed_data)
	return parsed_data, err
}

func outputData(input_data interface{}, format string) (output_data []byte, err error) {
	// TODO: Support more formats
	if format == "json" {
		output_data, err = json.MarshalIndent(input_data, "", "  ")
		// TODO: Detect auto better
	} else if format == "yaml" || format == "yml" || format == "auto" {
		output_data, err = yaml.Marshal(input_data)
	} else {
		panic("Non supported output format")
	}

	return output_data, err
}

func parseArgs() map[string]interface{} {
	usage := `uq - Universal (de)serializer

Usage:
  uq [-s FORMAT] [-t FORMAT] [FILE]

Options:
  -s <FORMAT>, --source <FORMAT>  Specify input format. [default: auto]
  -t <FORMAT>, --target <FORMAT>  Specify output format. [default: auto]
  -h --help     Show this screen
  --version     Show version

Formats:
  * json
  * yaml|yml
`

	arguments, _ := docopt.Parse(usage, nil, true, "0.0.1", false)
	return arguments
}

func main() {
	args := parseArgs()
	fmt.Print("args: ")
	fmt.Println(args)

	var filename string
	if args["FILE"] == nil {
		filename = "-"
	} else {
		filename = args["FILE"].(string)
	}
	data, _ := readData(filename)

	parsed_data, _ := parseData(data, args["--source"].(string))

	output_data, _ := outputData(parsed_data, args["--target"].(string))

	fmt.Println(string(output_data))
}
<|endoftext|>


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

package main

import (
	"os"
	"strings"

	// _ "net/http/pprof"

	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/cf/trace"
	"github.com/cloudfoundry/cli/plugin"
	"github.com/ecsteam/cloudfoundry-top-plugin/top"
	"github.com/ecsteam/cloudfoundry-top-plugin/util"
	"github.com/simonleung8/flags"
)

type TopCmd struct {
	ui terminal.UI
}

func (c *TopCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "top",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 8,
			Build: 4,
		},
		MinCliVersion: plugin.VersionType{
			Major: 6,
			Minor: 17,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "top",
				HelpText: "Displays top stats - by Kurt Kellner of ECS Team",
				UsageDetails: plugin.Usage{
					Usage: "cf top",
					Options: map[string]string{
						"no-top-check": "-ntc, do not check if there are other instances of top running on this OS",
						"cygwin":       "-c, force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )",
						"nozzles":      "-n, specify the number of nozzle instances (default: 2)",
						"debug":        "-d, enable debugging",
					},
				},
			},
		},
	}
}

func main() {

	/*
		go func() {
			runtime.SetBlockProfileRate(1)
			log.Println(http.ListenAndServe("localhost:6060", http.DefaultServeMux))
		}()
	*/

	plugin.Start(new(TopCmd))
}

func (c *TopCmd) Run(cliConnection plugin.CliConnection, args []string) {
	var options *top.ClientOptions

	traceLogger := trace.NewLogger(os.Stdout, true, os.Getenv("CF_TRACE"), "")
	c.ui = terminal.NewUI(os.Stdin, os.Stdout, terminal.NewTeePrinter(os.Stdout), traceLogger)

	switch args[0] {
	case "top":
		options = c.buildClientOptions(args)
	case "example-alternate-command":
	default:
		return
	}

	if options == nil {
		return
	}

	if options.Nozzles > 10 {
		c.ui.Failed("Can not specify more then 10 nozzle instances")
		return
	}
	if options.Nozzles < 1 {
		c.ui.Failed("Can not specify less then 1 nozzle instance")
		return
	}

	// TODO: THis is for testing only
	/*
		for i := 0; i < 10; i++ {
			token, err := cliConnection.AccessToken()
			if err != nil {
				c.ui.Failed(err.Error())
				break
			}
			fmt.Printf("Token: %v\n\n", token)
		}
		if true {
			return
		}
	*/

	cfTrace := os.Getenv("CF_TRACE")
	if strings.ToLower(cfTrace) == "true" {
		c.ui.Failed("The cf top plugin will not run with CF_TRACE environment variable set to true")
		return
	}

	if !options.Cygwin && util.IsCygwin() {
		c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top -cygwin'")
		return
	}

	/***********************************************************
	Trying to find a way to detect cygwin but not detect cygwin if cmd.exe is spawned from cygwin

	values := os.Environ()
	for _, v := range values  {
		fmt.Printf("value: [%v]\n", v)
	}

	fmt.Printf("Separator: [%v]\n", os.PathSeparator)
	fmt.Printf("PathListSeparator: [%v]\n", os.PathListSeparator)
	fmt.Printf("Geteuid: %v\n", os.Geteuid())
	fmt.Printf("Getppid: %v\n", os.Getppid())
	p, e := os.FindProcess(os.Getppid())
	fmt.Printf("Getppid: %+v [Err:%v]\n", p, e)

	if strings.Contains(strings.ToLower(os.Getenv("OS")), "windows") {
		shell := os.Getenv("SHELL")
		if len(shell) > 0 {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	}
	fmt.Printf("runtime.GOOS: [%v]\n", runtime.GOOS)
	*/

	/*
		if strings.ToLower(osType) == "cygwin" {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	*/

	metadata := c.GetMetadata()

	client := top.NewClient(cliConnection, options, c.ui, &metadata)
	client.Start()
}

func (c *TopCmd) buildClientOptions(args []string) *top.ClientOptions {
	var debug bool
	var noTopCheck bool
	var cygwin bool
	var nozzles int

	fc := flags.New()
	fc.NewBoolFlag("debug", "d", "used for debugging")
	fc.NewBoolFlag("no-top-check", "ntc", "Do not check if there are other instances of top running")
	fc.NewBoolFlag("cygwin", "c", "force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )")
	fc.NewIntFlagWithDefault("nozzles", "n", "number of nozzles", 2)
	//fc.NewStringFlag("filter", "f", "specify message filter such as LogMessage, ValueMetric, CounterEvent, HttpStartStop")
	err := fc.Parse(args[1:]...)

	if err != nil {
		c.ui.Failed(err.Error())
		return nil
	}
	if fc.IsSet("debug") {
		debug = fc.Bool("debug")
	}
	if fc.IsSet("no-top-check") {
		noTopCheck = fc.Bool("no-top-check")
	}
	if fc.IsSet("cygwin") {
		cygwin = fc.Bool("cygwin")
	}

	nozzles = fc.Int("nozzles")

	/*
		if fc.IsSet("filter") {
			filter = fc.String("filter")
		}
	*/
	return &top.ClientOptions{
		Debug:      debug,
		NoTopCheck: noTopCheck,
		Cygwin:     cygwin,
		Nozzles:    nozzles,
	}
}
<commit_msg>Build version v0.8.5<commit_after>// Copyright (c) 2016 ECS Team, Inc. - All Rights Reserved
// https://github.com/ECSTeam/cloudfoundry-top-plugin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"os"
	"strings"

	// _ "net/http/pprof"

	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/cf/trace"
	"github.com/cloudfoundry/cli/plugin"
	"github.com/ecsteam/cloudfoundry-top-plugin/top"
	"github.com/ecsteam/cloudfoundry-top-plugin/util"
	"github.com/simonleung8/flags"
)

type TopCmd struct {
	ui terminal.UI
}

func (c *TopCmd) GetMetadata() plugin.PluginMetadata {
	return plugin.PluginMetadata{
		Name: "top",
		Version: plugin.VersionType{
			Major: 0,
			Minor: 8,
			Build: 5,
		},
		MinCliVersion: plugin.VersionType{
			Major: 6,
			Minor: 17,
			Build: 0,
		},
		Commands: []plugin.Command{
			{
				Name:     "top",
				HelpText: "Displays top stats - by Kurt Kellner of ECS Team",
				UsageDetails: plugin.Usage{
					Usage: "cf top",
					Options: map[string]string{
						"no-top-check": "-ntc, do not check if there are other instances of top running on this OS",
						"cygwin":       "-c, force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )",
						"nozzles":      "-n, specify the number of nozzle instances (default: 2)",
						"debug":        "-d, enable debugging",
					},
				},
			},
		},
	}
}

func main() {

	/*
		go func() {
			runtime.SetBlockProfileRate(1)
			log.Println(http.ListenAndServe("localhost:6060", http.DefaultServeMux))
		}()
	*/

	plugin.Start(new(TopCmd))
}

func (c *TopCmd) Run(cliConnection plugin.CliConnection, args []string) {
	var options *top.ClientOptions

	traceLogger := trace.NewLogger(os.Stdout, true, os.Getenv("CF_TRACE"), "")
	c.ui = terminal.NewUI(os.Stdin, os.Stdout, terminal.NewTeePrinter(os.Stdout), traceLogger)

	switch args[0] {
	case "top":
		options = c.buildClientOptions(args)
	case "example-alternate-command":
	default:
		return
	}

	if options == nil {
		return
	}

	if options.Nozzles > 10 {
		c.ui.Failed("Can not specify more then 10 nozzle instances")
		return
	}
	if options.Nozzles < 1 {
		c.ui.Failed("Can not specify less then 1 nozzle instance")
		return
	}

	// TODO: THis is for testing only
	/*
		for i := 0; i < 10; i++ {
			token, err := cliConnection.AccessToken()
			if err != nil {
				c.ui.Failed(err.Error())
				break
			}
			fmt.Printf("Token: %v\n\n", token)
		}
		if true {
			return
		}
	*/

	cfTrace := os.Getenv("CF_TRACE")
	if strings.ToLower(cfTrace) == "true" {
		c.ui.Failed("The cf top plugin will not run with CF_TRACE environment variable set to true")
		return
	}

	if !options.Cygwin && util.IsCygwin() {
		c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top -cygwin'")
		return
	}

	/***********************************************************
	Trying to find a way to detect cygwin but not detect cygwin if cmd.exe is spawned from cygwin

	values := os.Environ()
	for _, v := range values  {
		fmt.Printf("value: [%v]\n", v)
	}

	fmt.Printf("Separator: [%v]\n", os.PathSeparator)
	fmt.Printf("PathListSeparator: [%v]\n", os.PathListSeparator)
	fmt.Printf("Geteuid: %v\n", os.Geteuid())
	fmt.Printf("Getppid: %v\n", os.Getppid())
	p, e := os.FindProcess(os.Getppid())
	fmt.Printf("Getppid: %+v [Err:%v]\n", p, e)

	if strings.Contains(strings.ToLower(os.Getenv("OS")), "windows") {
		shell := os.Getenv("SHELL")
		if len(shell) > 0 {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	}
	fmt.Printf("runtime.GOOS: [%v]\n", runtime.GOOS)
	*/

	/*
		if strings.ToLower(osType) == "cygwin" {
			c.ui.Failed("The cf top plugin will not run under cygwin.  Use this to run: 'cmd /c start cf top'")
			return
		}
	*/

	metadata := c.GetMetadata()

	client := top.NewClient(cliConnection, options, c.ui, &metadata)
	client.Start()
}

func (c *TopCmd) buildClientOptions(args []string) *top.ClientOptions {
	var debug bool
	var noTopCheck bool
	var cygwin bool
	var nozzles int

	fc := flags.New()
	fc.NewBoolFlag("debug", "d", "used for debugging")
	fc.NewBoolFlag("no-top-check", "ntc", "Do not check if there are other instances of top running")
	fc.NewBoolFlag("cygwin", "c", "force run under cygwin (Use this to run: 'cmd /c start cf top -cygwin' )")
	fc.NewIntFlagWithDefault("nozzles", "n", "number of nozzles", 2)
	//fc.NewStringFlag("filter", "f", "specify message filter such as LogMessage, ValueMetric, CounterEvent, HttpStartStop")
	err := fc.Parse(args[1:]...)

	if err != nil {
		c.ui.Failed(err.Error())
		return nil
	}
	if fc.IsSet("debug") {
		debug = fc.Bool("debug")
	}
	if fc.IsSet("no-top-check") {
		noTopCheck = fc.Bool("no-top-check")
	}
	if fc.IsSet("cygwin") {
		cygwin = fc.Bool("cygwin")
	}

	nozzles = fc.Int("nozzles")

	/*
		if fc.IsSet("filter") {
			filter = fc.String("filter")
		}
	*/
	return &top.ClientOptions{
		Debug:      debug,
		NoTopCheck: noTopCheck,
		Cygwin:     cygwin,
		Nozzles:    nozzles,
	}
}
<|endoftext|>


<commit_before>// POST /stream/<name> or PUT /stream/<name>
//     Broadcast a WebM video/audio file.
//
//     Accepted input: valid WebM split into arbitrarily many requests in absolutely
//     any way. Multiple files can be concatenated into a single stream as long as they
//     contain exactly the same tracks (i.e. their number, codecs, and dimensions.
//     Otherwise any connected decoders will error and have to restart. Changing,
//     for example, bitrate or tags is fine.)
//
// GET /stream/<name>
//     Receive a published WebM stream. Note that the server makes no attempt
//     at buffering; if the stream is being broadcast faster than its native framerate,
//     the client will have to buffer and/or drop frames.
//
// GET /stream/<name> with Upgrade: websocket
//     Connect to a JSON-RPC v2.0 node.
//
//     Methods of `Chat`:
//
//        * `SetName(string)`: assign a (unique) name to this client. This is required to...
//        * `SendMessage(string)`: broadcast a simple text message to all viewers.
//        * `RequestHistory()`: ask the server to emit notifications containing the last
//          few broadcasted text messages.
//
//     TODO Methods of `Stream`.
//
//     Notifications:
//
//        * `Chat.Message(user string, text string)`: a broadcasted text message.
//
package main

import (
	"golang.org/x/net/websocket"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

func wantsWebsocket(r *http.Request) bool {
	upgrade, ok := r.Header["Upgrade"]
	if !ok {
		return false
	}

	for i := range upgrade {
		if upgrade[i] == "websocket" {
			return true
		}
	}
	// func is_a_language_that_has_no_Array_Contains_method_any_good() bool {
	return false
	// }
}

func (ctx *Context) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := ctx.RootHTTP(w, r); err != nil {
		log.Println("error rendering template", r.URL.Path, err.Error())
		if err = RenderError(w, http.StatusInternalServerError, ""); err != nil {
			log.Println("error rendering error", err.Error())
			http.Error(w, "Error while rendering error message.", http.StatusInternalServerError)
		}
	}
}

func (ctx *Context) RootHTTP(w http.ResponseWriter, r *http.Request) error {
	if r.URL.Path == "/" {
		return RenderError(w, http.StatusNotImplemented, "There is no UI yet.")
	}

	if strings.HasPrefix(r.URL.Path, "/stream/") {
		streamID := strings.TrimPrefix(r.URL.Path, "/stream/")

		switch r.Method {
		case "GET", "HEAD":
			stream, ok := ctx.Get(streamID)
			if !ok {
				return RenderError(w, http.StatusNotFound, "")
			}

			if wantsWebsocket(r) {
				websocket.Handler(stream.RunRPC).ServeHTTP(w, r)
				return nil
			}

			header := w.Header()
			header.Set("Cache-Control", "no-cache")
			if stream.HasVideo {
				header.Set("Content-Type", "video/webm")
			} else {
				header.Set("Content-Type", "audio/webm")
			}
			w.WriteHeader(http.StatusOK)

			ch := make(chan []byte, 60)
			defer close(ch)

			stream.Connect(ch, false)
			defer stream.Disconnect(ch)

			for chunk := range ch {
				if stream.Closed {
					break
				}
				_, err := w.Write(chunk)
				if err != nil {
					break
				}
			}
			return nil

		case "PUT", "POST":
			stream, ok := ctx.Acquire(streamID)
			if !ok {
				return RenderError(w, http.StatusForbidden, "Stream ID already taken.")
			}

			defer stream.Close()

			buffer := [16384]byte{}
			for {
				n, err := r.Body.Read(buffer[:])
				if n != 0 {
					if _, err2 := stream.Write(buffer[:n]); err2 != nil {
						return RenderError(w, http.StatusBadRequest, err2.Error())
					}
				}
				if err != nil {
					w.WriteHeader(http.StatusNoContent)
					return nil
				}
			}
		}
	}

	streamID := strings.TrimPrefix(r.URL.Path, "/")
	stream, ok := ctx.Get(streamID)
	if !ok {
		return RenderError(w, http.StatusNotFound, "")
	}

	return Render(w, http.StatusOK, "room.html", roomViewModel{streamID, stream})
}

type noIndexFilesystem struct {
	fs http.FileSystem
}

func (fs noIndexFilesystem) Open(name string) (http.File, error) {
	f, err := fs.fs.Open(name)
	if err != nil {
		return nil, err
	}
	if stat, _ := f.Stat(); stat.IsDir() {
		return nil, os.ErrNotExist
	}
	return f, nil
}

func main() {
	ctx := Context{Timeout: time.Second * 10, ChatHistory: 20}
	mux := http.NewServeMux()
	mux.Handle("/static/", http.FileServer(noIndexFilesystem{http.Dir(".")}))
	mux.Handle("/", &ctx)
	http.ListenAndServe(":8000", mux)
}
<commit_msg>Make the 404 message marginally clearer.<commit_after>// POST /stream/<name> or PUT /stream/<name>
//     Broadcast a WebM video/audio file.
//
//     Accepted input: valid WebM split into arbitrarily many requests in absolutely
//     any way. Multiple files can be concatenated into a single stream as long as they
//     contain exactly the same tracks (i.e. their number, codecs, and dimensions.
//     Otherwise any connected decoders will error and have to restart. Changing,
//     for example, bitrate or tags is fine.)
//
// GET /stream/<name>
//     Receive a published WebM stream. Note that the server makes no attempt
//     at buffering; if the stream is being broadcast faster than its native framerate,
//     the client will have to buffer and/or drop frames.
//
// GET /stream/<name> with Upgrade: websocket
//     Connect to a JSON-RPC v2.0 node.
//
//     Methods of `Chat`:
//
//        * `SetName(string)`: assign a (unique) name to this client. This is required to...
//        * `SendMessage(string)`: broadcast a simple text message to all viewers.
//        * `RequestHistory()`: ask the server to emit notifications containing the last
//          few broadcasted text messages.
//
//     TODO Methods of `Stream`.
//
//     Notifications:
//
//        * `Chat.Message(user string, text string)`: a broadcasted text message.
//
package main

import (
	"golang.org/x/net/websocket"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
)

func wantsWebsocket(r *http.Request) bool {
	upgrade, ok := r.Header["Upgrade"]
	if !ok {
		return false
	}

	for i := range upgrade {
		if upgrade[i] == "websocket" {
			return true
		}
	}
	// func is_a_language_that_has_no_Array_Contains_method_any_good() bool {
	return false
	// }
}

func (ctx *Context) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := ctx.RootHTTP(w, r); err != nil {
		log.Println("error rendering template", r.URL.Path, err.Error())
		if err = RenderError(w, http.StatusInternalServerError, ""); err != nil {
			log.Println("error rendering error", err.Error())
			http.Error(w, "Error while rendering error message.", http.StatusInternalServerError)
		}
	}
}

func (ctx *Context) RootHTTP(w http.ResponseWriter, r *http.Request) error {
	if r.URL.Path == "/" {
		return RenderError(w, http.StatusNotImplemented, "There is no UI yet.")
	}

	if strings.HasPrefix(r.URL.Path, "/stream/") {
		streamID := strings.TrimPrefix(r.URL.Path, "/stream/")

		switch r.Method {
		case "GET", "HEAD":
			stream, ok := ctx.Get(streamID)
			if !ok {
				return RenderError(w, http.StatusNotFound, "Invalid stream name.")
			}

			if wantsWebsocket(r) {
				websocket.Handler(stream.RunRPC).ServeHTTP(w, r)
				return nil
			}

			header := w.Header()
			header.Set("Cache-Control", "no-cache")
			if stream.HasVideo {
				header.Set("Content-Type", "video/webm")
			} else {
				header.Set("Content-Type", "audio/webm")
			}
			w.WriteHeader(http.StatusOK)

			ch := make(chan []byte, 60)
			defer close(ch)

			stream.Connect(ch, false)
			defer stream.Disconnect(ch)

			for chunk := range ch {
				if stream.Closed {
					break
				}
				_, err := w.Write(chunk)
				if err != nil {
					break
				}
			}
			return nil

		case "PUT", "POST":
			stream, ok := ctx.Acquire(streamID)
			if !ok {
				return RenderError(w, http.StatusForbidden, "Stream ID already taken.")
			}

			defer stream.Close()

			buffer := [16384]byte{}
			for {
				n, err := r.Body.Read(buffer[:])
				if n != 0 {
					if _, err2 := stream.Write(buffer[:n]); err2 != nil {
						return RenderError(w, http.StatusBadRequest, err2.Error())
					}
				}
				if err != nil {
					w.WriteHeader(http.StatusNoContent)
					return nil
				}
			}
		}
	}

	streamID := strings.TrimPrefix(r.URL.Path, "/")
	stream, ok := ctx.Get(streamID)
	if !ok {
		return RenderError(w, http.StatusNotFound, "Invalid stream name.")
	}

	return Render(w, http.StatusOK, "room.html", roomViewModel{streamID, stream})
}

type noIndexFilesystem struct {
	fs http.FileSystem
}

func (fs noIndexFilesystem) Open(name string) (http.File, error) {
	f, err := fs.fs.Open(name)
	if err != nil {
		return nil, err
	}
	if stat, _ := f.Stat(); stat.IsDir() {
		return nil, os.ErrNotExist
	}
	return f, nil
}

func main() {
	ctx := Context{Timeout: time.Second * 10, ChatHistory: 20}
	mux := http.NewServeMux()
	mux.Handle("/static/", http.FileServer(noIndexFilesystem{http.Dir(".")}))
	mux.Handle("/", &ctx)
	http.ListenAndServe(":8000", mux)
}
<|endoftext|>


<commit_before>package main

import (
	"html/template"
	"io/ioutil"
	"log"
	"regexp"

	"net/http"

	"flag"
	//"github.com/FogCreek/mini"

	"github.com/JackKnifed/blackfriday"
	"github.com/JackKnifed/gnosis"
	//"github.com/russross/blackfriday"
)

type WikiPage struct {
	Title string
	//Body  stringo
	Body template.HTML
}

var templates = template.Must(template.ParseFiles("wiki.html"))

var validWiki = regexp.MustCompile("^/([a-zA-Z0-9_ ]+)$")

var configFile = flag.String("config", "", "specify a configuration file")

//var validFiles = regexp.MustCompile("^/raw/([a-zA-Z0-9]+)\\.(jpg|gif|jpeg|md|png)$")

//var validSupport = regexp.MustCompile("^/global/([a-zA-Z0-9]+)\\.(css|js)$")

func markdownHandler(responsePipe http.ResponseWriter, request *http.Request) {
	validRequest := validWiki.FindStringSubmatch(request.URL.Path)
	config := gnosis.GetConfig()
	if validRequest == nil {
		http.Error(responsePipe, "Request not allowed", 403)
	}
	contents, err := ioutil.ReadFile(config.mainserver.prefix + validRequest[1] + ".md")
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
	// parse any markdown in the input
	body := template.HTML(blackfriday.MarkdownCommon(contents))

	response := WikiPage{Title: validRequest[1], Body: body}
	err = templates.ExecuteTemplate(responsePipe, "wiki.html", response)
	if err != nil {
		http.Error(responsePipe, err.Error(), http.StatusInternalServerError)
	}
}

/*
func contentHandler(responsePipe http.ResponseWriter, request *http.Request) {
	validRequest := validFiles.FindStringSubmatch(request.URL.Path)
	if validRequest == nil {
		http.Error(responsePipe, "Request not allowed", 403)
	}
	strippedRequest := http.StripPrefix("/raw/", validRequest[0])
	http.ServeFile(responsePipe, request, strippedRequest)
	http.FileServer()
	contents, err := loadFile(validRequest)
	if err != nil {
		http.Error(responsePipe, err, 500)
	}
	response := contents
	err := templates.ExecuteTemplate(responsePipe, "markdown.html", p)
	if err != nil {
		http.Error(responsePipe, err.Error(), http.StatusInternalServerError)
	}

}
*/

/*
func loadFile(filename string) ([]byte, error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return contents, nil
}
*/

func main() {
	flag.Parse()

	gnosis.LoadConfig(*configFile)

	config := gnosis.GetConfig()

	rawFiles := http.FileServer(http.Dir(config.mainserver.path))
	siteFiles := http.FileServer(http.Dir(config.mainserver.path))

	http.Handle("/raw/", http.StripPrefix("/raw/", rawFiles))
	http.Handle("/site/", http.StripPrefix("/site/", siteFiles))
	http.HandleFunc("/", markdownHandler)

	log.Println(http.ListenAndServe(":"+config.global.port, nil))

}
<commit_msg>removed an errant character<commit_after>package main

import (
	"html/template"
	"io/ioutil"
	"log"
	"regexp"

	"net/http"

	"flag"

	"github.com/JackKnifed/blackfriday"
	"github.com/JackKnifed/gnosis"
	//"github.com/russross/blackfriday"
)

type WikiPage struct {
	Title string
	//Body  string
	Body template.HTML
}

var templates = template.Must(template.ParseFiles("wiki.html"))

var validWiki = regexp.MustCompile("^/([a-zA-Z0-9_ ]+)$")

var configFile = flag.String("config", "", "specify a configuration file")

//var validFiles = regexp.MustCompile("^/raw/([a-zA-Z0-9]+)\\.(jpg|gif|jpeg|md|png)$")

//var validSupport = regexp.MustCompile("^/global/([a-zA-Z0-9]+)\\.(css|js)$")

func markdownHandler(responsePipe http.ResponseWriter, request *http.Request) {
	validRequest := validWiki.FindStringSubmatch(request.URL.Path)
	config := gnosis.GetConfig()
	if validRequest == nil {
		http.Error(responsePipe, "Request not allowed", 403)
	}
	contents, err := ioutil.ReadFile(config.mainserver.prefix + validRequest[1] + ".md")
	if err != nil {
		http.Error(responsePipe, err.Error(), 500)
	}
	// parse any markdown in the input
	body := template.HTML(blackfriday.MarkdownCommon(contents))

	response := WikiPage{Title: validRequest[1], Body: body}
	err = templates.ExecuteTemplate(responsePipe, "wiki.html", response)
	if err != nil {
		http.Error(responsePipe, err.Error(), http.StatusInternalServerError)
	}
}

/*
func contentHandler(responsePipe http.ResponseWriter, request *http.Request) {
	validRequest := validFiles.FindStringSubmatch(request.URL.Path)
	if validRequest == nil {
		http.Error(responsePipe, "Request not allowed", 403)
	}
	strippedRequest := http.StripPrefix("/raw/", validRequest[0])
	http.ServeFile(responsePipe, request, strippedRequest)
	http.FileServer()
	contents, err := loadFile(validRequest)
	if err != nil {
		http.Error(responsePipe, err, 500)
	}
	response := contents
	err := templates.ExecuteTemplate(responsePipe, "markdown.html", p)
	if err != nil {
		http.Error(responsePipe, err.Error(), http.StatusInternalServerError)
	}

}
*/

/*
func loadFile(filename string) ([]byte, error) {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return contents, nil
}
*/

func main() {
	flag.Parse()

	gnosis.LoadConfig(*configFile)

	config := gnosis.GetConfig()

	rawFiles := http.FileServer(http.Dir(config.mainserver.path))
	siteFiles := http.FileServer(http.Dir(config.mainserver.path))

	http.Handle("/raw/", http.StripPrefix("/raw/", rawFiles))
	http.Handle("/site/", http.StripPrefix("/site/", siteFiles))
	http.HandleFunc("/", markdownHandler)

	log.Println(http.ListenAndServe(":"+config.global.port, nil))

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
)

var config = CiConfg{}

func BitBucket(w http.ResponseWriter, r *http.Request) {
	log.Println("======bitbucket payload======")
	log.Println(string(r.Body))
	log.Println("======end payload======")
}

func GitHub(w http.ResponseWriter, r *http.Request) {
	log.Println("======github payload======")
	log.Println(string(r.Body))
	log.Println("======end payload======")
}

func main() {

	config, err := LoadConfig()
	if err != nil {
		log.Fatal(err)
	}
	log.Println(config)

	http.HandleFunc("/bitbucket", BitBucket)
	http.HandleFunc("/github", GitHub)

	log.Println("goci start to listening on port", config.Port)
	log.Fatal(http.ListenAndServe(":" + config.Port, nil))
}
<commit_msg>fix build error<commit_after>package main

import (
	// "fmt"
	"io/ioutil"
	"log"
	"net/http"
)

var config = CiConfg{}

func BitBucket(w http.ResponseWriter, r *http.Request) {
	log.Println("======bitbucket payload======")
	defer r.Body.Close()
	body, _ := ioutil.ReadAll(r.Body)
	log.Println(string(body))
	log.Println("======end payload======")
}

func GitHub(w http.ResponseWriter, r *http.Request) {
	log.Println("======github payload======")
	defer r.Body.Close()
	body, _ := ioutil.ReadAll(r.Body)
	log.Println(string(body))
	log.Println("======end payload======")
}

func main() {

	config, err := LoadConfig()
	if err != nil {
		log.Fatal(err)
	}
	log.Println(config)

	http.HandleFunc("/bitbucket", BitBucket)
	http.HandleFunc("/github", GitHub)

	log.Println("goci start to listening on port", config.Port)
	log.Fatal(http.ListenAndServe(":"+config.Port, nil))
}
<|endoftext|>