<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/jrperritt/gophercloud/rackspace"
	rsV1Servers "github.com/jrperritt/gophercloud/rackspace/compute/v1/servers"
	"github.com/rackspace/gophercloud"
	osV2Servers "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/pagination"
	rsV2Servers "github.com/rackspace/gophercloud/rackspace/compute/v2/servers"
	"github.com/rackspace/gophercloud/rackspace/identity/v2/tokens"
)

const (
	metadataKey     = "rax:reboot_window"
	metadataTimeFmt = "2006-01-02T15:04:05Z"
)

func main() {
	outputToCSV := *flag.Bool("csv", false, "Output a CSV file")
	flag.Parse()

	if flag.NArg() != 2 {
		fmt.Println("You must supply a username and API key after all other args.")
		os.Exit(1)
	}

	username, apiKey := flag.Arg(0), flag.Arg(1)

	opts := gophercloud.AuthOptions{
		Username: username,
		APIKey:   apiKey,
	}

	provider, err := rackspace.AuthenticatedClient(opts)
	if err != nil {
		fmt.Printf("Unable to authenticate: %v\n", err)
		os.Exit(1)
	}

	regions, fg := Regions(provider, opts)

	fmt.Printf("Regions with a compute endpoint: %s\n", strings.Join(regions, ", "))
	if fg {
		fmt.Println("You have a first-gen endpoint, too.")
	}

	var numUnaffected int
	var entries []entry

	// Iterate through regions with an NG compute endpoint. Collect data about each server.
	for _, region := range regions {
		compute, err := rackspace.NewComputeV2(provider, gophercloud.EndpointOpts{
			Region: region,
		})
		if err != nil {
			fmt.Printf("Unable to locate a v2 compute endpoint in region %s: %v\n", region, err)
			continue
		}

		err = rsV2Servers.List(compute, nil).EachPage(func(page pagination.Page) (bool, error) {
			s, err := osV2Servers.ExtractServers(page)
			if err != nil {
				return false, err
			}

			for _, server := range s {
				entry, err := ConstructEntry(server, "Next Gen", region)
				if err != nil {
					if strings.Contains(err.Error(), "not present") {
						numUnaffected++
						continue
					}
					fmt.Printf("%s\n", err)
					continue
				} else {
					entries = append(entries, *entry)
				}
			}

			return true, nil
		})
	}

	// Iterate through regions with an FG compute endpoint. Collect data about each server.
	compute, err := rackspace.NewComputeV1(provider, gophercloud.EndpointOpts{
		Availability: gophercloud.AvailabilityPublic,
	})
	if err != nil {
		fmt.Printf("Unable to locate a v1 compute endpoint: %v\n", err)
	}

	err = rsV1Servers.List(compute, rsV1Servers.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
		s, err := osV2Servers.ExtractServers(page)
		if err != nil {
			return false, err
		}

		for _, server := range s {
			entry, err := ConstructEntry(server, "First Gen", "DFW")
			if err != nil {
				if strings.Contains(err.Error(), "not present") {
					numUnaffected++
					continue
				}
				fmt.Printf("%s\n", err)
				continue
			} else {
				entries = append(entries, *entry)
			}
		}

		return true, nil
	})
	if err != nil {
		fmt.Printf("Error listing servers: %+v\n", err)
	}

	fmt.Printf("Metadatum %s was not present in the result for %d of your servers", metadataKey, numUnaffected)

	if outputToCSV {
		outputCSV(entries)
	} else {
		outputTabular(entries)
	}
}

// Regions acquires the service catalog and returns a slice of every region that contains a next-gen
// server endpoint, and a boolean indicating whether or not this customer has access to FG servers.
func Regions(provider *gophercloud.ProviderClient, opts gophercloud.AuthOptions) ([]string, bool) {
	service := rackspace.NewIdentityV2(provider)

	result := tokens.Create(service, tokens.WrapOptions(opts))
	catalog, err := result.ExtractServiceCatalog()
	if err != nil {
		fmt.Printf("Unable to retrieve the service catalog: %v\n", err)
		os.Exit(1)
	}

	var regions []string
	var fg bool
	for _, entry := range catalog.Entries {
		if entry.Type == "compute" {
			for _, endpoint := range entry.Endpoints {
				if endpoint.Region == "" {
					fg = true
				} else {
					regions = append(regions, endpoint.Region)
				}
			}
		}
	}
	return regions, fg
}

// ConstructEntry extracts the metadata key and builds an entry for a server.
func ConstructEntry(server osV2Servers.Server, genType, region string) (*entry, error) {
	window, ok := server.Metadata[metadataKey]
	if !ok {
		return nil, fmt.Errorf("Metadatum %s was not present in the result for server %s", metadataKey, server.ID)
	}

	windowString, ok := window.(string)
	if !ok {
		return nil, fmt.Errorf("Metadatum %s for server %s was not a string: %#v", metadataKey, server.ID, window)
	}

	// Expected format: 2014-01-28T00:00:00Z;2014-01-28T03:00:00Z

	parts := strings.Split(windowString, ";")
	if len(parts) != 2 {
		return nil, fmt.Errorf("Unexpected metadatum format for server %s: %s", server.ID, windowString)
	}

	start, err := time.Parse(metadataTimeFmt, parts[0])
	if err != nil {
		return nil, fmt.Errorf("Unable to parse window start time for server %s: %s", server.ID, parts[0])
	}

	end, err := time.Parse(metadataTimeFmt, parts[1])
	if err != nil {
		return nil, fmt.Errorf("Unable to parse window end time for server %s: %s", server.ID, parts[1])
	}

	e := &entry{
		Server:      server,
		Region:      region,
		GenType:     genType,
		WindowStart: start,
		WindowEnd:   end,
	}
	return e, nil
}
<commit_msg>don't list servers without a client<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/jrperritt/gophercloud/rackspace"
	rsV1Servers "github.com/jrperritt/gophercloud/rackspace/compute/v1/servers"
	"github.com/rackspace/gophercloud"
	osV2Servers "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
	"github.com/rackspace/gophercloud/pagination"
	rsV2Servers "github.com/rackspace/gophercloud/rackspace/compute/v2/servers"
	"github.com/rackspace/gophercloud/rackspace/identity/v2/tokens"
)

const (
	metadataKey     = "rax:reboot_window"
	metadataTimeFmt = "2006-01-02T15:04:05Z"
)

func main() {
	outputToCSV := *flag.Bool("csv", false, "Output a CSV file")
	flag.Parse()

	if flag.NArg() != 2 {
		fmt.Println("You must supply a username and API key after all other args.")
		os.Exit(1)
	}

	username, apiKey := flag.Arg(0), flag.Arg(1)

	opts := gophercloud.AuthOptions{
		Username: username,
		APIKey:   apiKey,
	}

	provider, err := rackspace.AuthenticatedClient(opts)
	if err != nil {
		fmt.Printf("Unable to authenticate: %v\n", err)
		os.Exit(1)
	}

	regions, fg := Regions(provider, opts)

	fmt.Printf("Regions with a compute endpoint: %s\n", strings.Join(regions, ", "))
	if fg {
		fmt.Println("You have a first-gen endpoint, too.")
	}

	var numUnaffected int
	var entries []entry

	// Iterate through regions with an NG compute endpoint. Collect data about each server.
	for _, region := range regions {
		compute, err := rackspace.NewComputeV2(provider, gophercloud.EndpointOpts{
			Region: region,
		})
		if err != nil {
			fmt.Printf("Unable to locate a v2 compute endpoint in region %s: %v\n", region, err)
			continue
		}

		err = rsV2Servers.List(compute, nil).EachPage(func(page pagination.Page) (bool, error) {
			s, err := osV2Servers.ExtractServers(page)
			if err != nil {
				return false, err
			}

			for _, server := range s {
				entry, err := ConstructEntry(server, "Next Gen", region)
				if err != nil {
					if strings.Contains(err.Error(), "not present") {
						numUnaffected++
						continue
					}
					fmt.Printf("%s\n", err)
					continue
				} else {
					entries = append(entries, *entry)
				}
			}

			return true, nil
		})
	}

	// Iterate through regions with an FG compute endpoint. Collect data about each server.
	compute, err := rackspace.NewComputeV1(provider, gophercloud.EndpointOpts{
		Availability: gophercloud.AvailabilityPublic,
	})
	if err != nil {
		fmt.Printf("Unable to locate a v1 compute endpoint: %v\n", err)
	} else {
		err = rsV1Servers.List(compute, rsV1Servers.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
			s, err := osV2Servers.ExtractServers(page)
			if err != nil {
				return false, err
			}

			for _, server := range s {
				entry, err := ConstructEntry(server, "First Gen", "DFW")
				if err != nil {
					if strings.Contains(err.Error(), "not present") {
						numUnaffected++
						continue
					}
					fmt.Printf("%s\n", err)
					continue
				} else {
					entries = append(entries, *entry)
				}
			}

			return true, nil
		})
		if err != nil {
			fmt.Printf("Error listing servers: %+v\n", err)
		}
	}

	fmt.Printf("Metadatum %s was not present in the result for %d of your servers", metadataKey, numUnaffected)

	if outputToCSV {
		outputCSV(entries)
	} else {
		outputTabular(entries)
	}
}

// Regions acquires the service catalog and returns a slice of every region that contains a next-gen
// server endpoint, and a boolean indicating whether or not this customer has access to FG servers.
func Regions(provider *gophercloud.ProviderClient, opts gophercloud.AuthOptions) ([]string, bool) {
	service := rackspace.NewIdentityV2(provider)

	result := tokens.Create(service, tokens.WrapOptions(opts))
	catalog, err := result.ExtractServiceCatalog()
	if err != nil {
		fmt.Printf("Unable to retrieve the service catalog: %v\n", err)
		os.Exit(1)
	}

	var regions []string
	var fg bool
	for _, entry := range catalog.Entries {
		if entry.Type == "compute" {
			for _, endpoint := range entry.Endpoints {
				if endpoint.Region == "" {
					fg = true
				} else {
					regions = append(regions, endpoint.Region)
				}
			}
		}
	}
	return regions, fg
}

// ConstructEntry extracts the metadata key and builds an entry for a server.
func ConstructEntry(server osV2Servers.Server, genType, region string) (*entry, error) {
	window, ok := server.Metadata[metadataKey]
	if !ok {
		return nil, fmt.Errorf("Metadatum %s was not present in the result for server %s", metadataKey, server.ID)
	}

	windowString, ok := window.(string)
	if !ok {
		return nil, fmt.Errorf("Metadatum %s for server %s was not a string: %#v", metadataKey, server.ID, window)
	}

	// Expected format: 2014-01-28T00:00:00Z;2014-01-28T03:00:00Z

	parts := strings.Split(windowString, ";")
	if len(parts) != 2 {
		return nil, fmt.Errorf("Unexpected metadatum format for server %s: %s", server.ID, windowString)
	}

	start, err := time.Parse(metadataTimeFmt, parts[0])
	if err != nil {
		return nil, fmt.Errorf("Unable to parse window start time for server %s: %s", server.ID, parts[0])
	}

	end, err := time.Parse(metadataTimeFmt, parts[1])
	if err != nil {
		return nil, fmt.Errorf("Unable to parse window end time for server %s: %s", server.ID, parts[1])
	}

	e := &entry{
		Server:      server,
		Region:      region,
		GenType:     genType,
		WindowStart: start,
		WindowEnd:   end,
	}
	return e, nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"fmt"
	"github.com/cptaffe/mpris2"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Printf(os.Args[0] + " [play | pause | playpause]\n")
	} else {
		players, err := mpris2.Players()
		if err != nil {
			fmt.Printf("Error: %s\n", err)
		}
		if len(players) > 0 {
			player := players[0]
			switch os.Args[1] {
			case "playpause":
				player.PlayPause()
			case "next":
				player.Next()
			case "prev":
				player.Previous()
			default:
				fmt.Printf("%s is currently unsupported\n", os.Args[1])
			}
		}
	}
}
<commit_msg>update<commit_after>package main

import (
	"os"
	"fmt"
	"github.com/cptaffe/mpris2"
)

func main() {
	if len(os.Args) != 2 {
		fmt.Printf(os.Args[0] + " [play | pause | playpause]\n")
	} else {
		players, err := mpris2.Players()
		if err != nil {
			fmt.Printf("Error: %s\n", err)
		}

		for _, player := range players {
			fmt.Printf("Name: %s\n", player.Name)
		}

		if len(players) > 0 {
			player := players[0]
			switch os.Args[1] {
			case "playpause":
				player.PlayPause()
			case "next":
				player.Next()
			case "prev":
				player.Previous()
			default:
				fmt.Printf("%s is currently unsupported\n", os.Args[1])
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
)

const VERSION = "0.1.0"

func main() {
	log.Printf("resolutionizerd %s starting...", VERSION)

	log.Fatalln(http.ListenAndServe(":8080", http.FileServer(http.Dir("./client"))))
}
<commit_msg>Add support for injecting the port and client dir.<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
)

const VERSION = "0.1.0"

var clientDir string

func init() {
	flag.StringVar(&clientDir, "client", "./client", "the directory where the client data is stored")
}

func main() {
	log.Printf("resolutionizerd %s starting...", VERSION)

	log.Fatalln(http.ListenAndServe(":"+os.Getenv("PORT"), http.FileServer(http.Dir(clientDir))))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	kafka "github.com/Shopify/sarama"
	"github.com/jeffchao/gomkafka/gomkafka"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func run() {
	go handleSignals()
	work()
}

func work() {
	client, producer, err := gomkafka.Gomkafka()
	if err != nil {
		panic(err)
	}
	defer client.Close()
	defer producer.Close()

	msg := ""

	for {
		_, err := fmt.Scanf("%s\n", &msg)
		if err != nil {
			return
		}

		log.Println("sending")
		err = producer.QueueMessage("monitoring", nil, kafka.StringEncoder(msg))
		log.Println("sent")
		if err != nil {
			panic(err)
		}

		select {
		case err = <-producer.Errors():
			if err != nil {
				panic(err)
			}
		default:
			// Perform a noop so sarama can can catch disconnect on the other end.
		}

		time.Sleep(1 * time.Millisecond)
	}
}

func handleSignals() {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, os.Interrupt)

	for s := range signals {
		switch s {
		case syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM, syscall.SIGKILL, os.Interrupt:
			// Catch signals that might terminate the process on behalf all goroutines.
			quit()
		}
	}
}

func quit() {
	// Perform any necessary cleanup here.
	os.Exit(1)
}

func main() {
	run()
}
<commit_msg>Remove remaining debug log. Comply with rsyslog.<commit_after>package main

import (
	"fmt"
	kafka "github.com/Shopify/sarama"
	"github.com/jeffchao/gomkafka/gomkafka"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func run() {
	go handleSignals()
	work()
}

func work() {
	client, producer, err := gomkafka.Gomkafka()
	if err != nil {
		panic(err)
	}
	defer client.Close()
	defer producer.Close()

	msg := ""

	for {
		_, err := fmt.Scanf("%s\n", &msg)
		if err != nil {
			return
		}

		err = producer.QueueMessage("monitoring", nil, kafka.StringEncoder(msg))
		if err != nil {
			panic(err)
		}

		select {
		case err = <-producer.Errors():
			if err != nil {
				panic(err)
			}
		default:
			// Perform a noop so sarama can can catch disconnect on the other end.
		}

		time.Sleep(1 * time.Millisecond)
	}
}

func handleSignals() {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, os.Interrupt)

	for s := range signals {
		switch s {
		case syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM, syscall.SIGKILL, os.Interrupt:
			// Catch signals that might terminate the process on behalf all goroutines.
			quit()
		}
	}
}

func quit() {
	// Perform any necessary cleanup here.
	os.Exit(1)
}

func main() {
	run()
}
<|endoftext|>


<commit_before>package bnblog

import (
	"appengine"
	"appengine/datastore"
	"encoding/base64"
	"fmt"
	"github.com/codegangsta/martini"
	"github.com/russross/blackfriday"
	"net/http"
	"strings"
	"text/template"
	"time"
)

var PostTemplate = template.Must(template.ParseFiles("public2/pagetempl.html"))
var HomeTemplate = template.Must(template.ParseFiles("public2/hometempl.html"))

type Post struct {
	Author  string
	Content string `datastore:",noindex"`
	Date    time.Time
	Slug    string
	Title   string
}

type PostFormatted struct {
	Author  string
	Content string `datastore:",noindex"`
	Date    string
	Slug    string
	Title   string
}

func init() {
	m := martini.Classic()
	m.Get("/post/:name", ReadPost)
	m.Get("/raw/:name", ReadRawPost)
	m.Post("/admin/new", PublishPost)
	m.Get("/admin/", Admin)
	m.Get("/", ListPosts)
	m.Get("/all", ListPosts)
	m.Get("/rss.xml", GetRSS)
	m.Get("/sitemap.xml", GetSitemap)
	m.Get("/admin/run_gc", Run_GC)
	m.Get("/admin/backup.tar", Producebackup)
	m.Get("/admin/remove/:name", RemovePost)
	m.Post("/admin/uploadfile", UploadFile)

	m.Get("/lessons/:year/:month/:day/:title", MigrateOldURLS)
	m.Get("/lessons/:year/:month/:day/:title/", MigrateOldURLS)
	m.Get("/errors/:year/:month/:day/:title", MigrateOldURLS)
	m.Get("/errors/:year/:month/:day/:title/", MigrateOldURLS)
	m.Get("/posts/errors/:year/:month/:day/:title", MigrateOldURLS)
	m.Get("/posts/errors/:year/:month/:day/:title/", MigrateOldURLS)
	m.Get("/asset/:tag", ReadFile)

	m.Use(func(res http.ResponseWriter, req *http.Request) {
		res.Header().Add("Cache-Control", "public")
		res.Header().Add("X-Powered-uW0t", "marBy-m8")
		res.Header().Add("X-Served-By", GimmeDC(res, req))
		res.Header().Add("X-Served-For", req.Header.Get("CF-RAY"))
	})

	m.Use(martini.Static("public2"))

	http.Handle("/", m)
}

func MigrateOldURLS(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	http.Redirect(rw, req, fmt.Sprintf("https://blog.benjojo.co.uk/post/%s-%s-%s-%s.md", params["year"], params["month"], params["day"], params["title"]), http.StatusMovedPermanently)
}

func ReadPost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	// c := appengine.NewContext(r)
	// key := datastore.NewIncompleteKey(c, "Greeting", PostKey(c))
	// _, err := datastore.Put(c, key, &g)

	c := appengine.NewContext(req)
	k := datastore.NewKey(c, "Post", params["name"], 0, nil)
	post := Post{}
	err := datastore.Get(c, k, &post)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	postd, _ := base64.StdEncoding.DecodeString(post.Content)
	// post.Content = strings.Replace(string(postd), "\n", "\r\n\r\n", -1)
	post.Content = string(postd)
	output := blackfriday.MarkdownCommon([]byte(post.Content))
	lines := strings.Split(string(postd), "\n")
	layoutData := struct {
		Title   string
		Content string
	}{
		Title:   lines[0],
		Content: string(output),
	}

	err = PostTemplate.Execute(rw, layoutData)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}
}

func ReadRawPost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)
	k := datastore.NewKey(c, "Post", params["name"], 0, nil)
	post := Post{}
	err := datastore.Get(c, k, &post)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	postd, _ := base64.StdEncoding.DecodeString(post.Content)
	rw.Write(postd)
}

func ListPosts(rw http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)
	q := datastore.NewQuery("Post").Order("-Date").Limit(100)
	posts := make([]Post, 0, 100)

	if _, err := q.GetAll(c, &posts); err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}
	FormattedPosts := make([]PostFormatted, 0)

	for _, v := range posts {
		if !strings.HasPrefix(v.Slug, "DRAFT-") {
			newpost := PostFormatted{
				Author:  v.Author,
				Content: v.Content,
				Date:    v.Date.Format("2006-01-02 15:04:05"),
				Slug:    v.Slug,
				Title:   v.Title,
			}
			FormattedPosts = append(FormattedPosts, newpost)
		}
	}

	layoutData := struct {
		Posts []PostFormatted
	}{
		Posts: FormattedPosts,
	}

	err := HomeTemplate.Execute(rw, layoutData)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}

}
<commit_msg>Added 404's for lost posts<commit_after>package bnblog

import (
	"appengine"
	"appengine/datastore"
	"encoding/base64"
	"fmt"
	"github.com/codegangsta/martini"
	"github.com/russross/blackfriday"
	"net/http"
	"strings"
	"text/template"
	"time"
)

var PostTemplate = template.Must(template.ParseFiles("public2/pagetempl.html"))
var HomeTemplate = template.Must(template.ParseFiles("public2/hometempl.html"))

type Post struct {
	Author  string
	Content string `datastore:",noindex"`
	Date    time.Time
	Slug    string
	Title   string
}

type PostFormatted struct {
	Author  string
	Content string `datastore:",noindex"`
	Date    string
	Slug    string
	Title   string
}

func init() {
	m := martini.Classic()
	m.Get("/post/:name", ReadPost)
	m.Get("/raw/:name", ReadRawPost)
	m.Post("/admin/new", PublishPost)
	m.Get("/admin/", Admin)
	m.Get("/", ListPosts)
	m.Get("/all", ListPosts)
	m.Get("/rss.xml", GetRSS)
	m.Get("/sitemap.xml", GetSitemap)
	m.Get("/admin/run_gc", Run_GC)
	m.Get("/admin/backup.tar", Producebackup)
	m.Get("/admin/remove/:name", RemovePost)
	m.Post("/admin/uploadfile", UploadFile)

	m.Get("/lessons/:year/:month/:day/:title", MigrateOldURLS)
	m.Get("/lessons/:year/:month/:day/:title/", MigrateOldURLS)
	m.Get("/errors/:year/:month/:day/:title", MigrateOldURLS)
	m.Get("/errors/:year/:month/:day/:title/", MigrateOldURLS)
	m.Get("/posts/errors/:year/:month/:day/:title", MigrateOldURLS)
	m.Get("/posts/errors/:year/:month/:day/:title/", MigrateOldURLS)
	m.Get("/asset/:tag", ReadFile)

	m.Use(func(res http.ResponseWriter, req *http.Request) {
		res.Header().Add("Cache-Control", "public")
		res.Header().Add("X-Powered-uW0t", "marBy-m8")
		res.Header().Add("X-Served-By", GimmeDC(res, req))
		res.Header().Add("X-Served-For", req.Header.Get("CF-RAY"))
	})

	m.Use(martini.Static("public2"))

	http.Handle("/", m)
}

func MigrateOldURLS(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	http.Redirect(rw, req, fmt.Sprintf("https://blog.benjojo.co.uk/post/%s-%s-%s-%s.md", params["year"], params["month"], params["day"], params["title"]), http.StatusMovedPermanently)
}

func ReadPost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	// c := appengine.NewContext(r)
	// key := datastore.NewIncompleteKey(c, "Greeting", PostKey(c))
	// _, err := datastore.Put(c, key, &g)

	c := appengine.NewContext(req)
	k := datastore.NewKey(c, "Post", params["name"], 0, nil)
	post := Post{}
	err := datastore.Get(c, k, &post)

	if err != nil {
		if fmt.Sprint(err) == "datastore: no such entity" {
			http.Error(rw, "This blog post cannot be found, Please check your URL", http.StatusNotFound)
			return
		}

		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	postd, _ := base64.StdEncoding.DecodeString(post.Content)
	// post.Content = strings.Replace(string(postd), "\n", "\r\n\r\n", -1)
	post.Content = string(postd)
	output := blackfriday.MarkdownCommon([]byte(post.Content))
	lines := strings.Split(string(postd), "\n")
	layoutData := struct {
		Title   string
		Content string
	}{
		Title:   lines[0],
		Content: string(output),
	}

	err = PostTemplate.Execute(rw, layoutData)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}
}

func ReadRawPost(rw http.ResponseWriter, req *http.Request, params martini.Params) {
	c := appengine.NewContext(req)
	k := datastore.NewKey(c, "Post", params["name"], 0, nil)
	post := Post{}
	err := datastore.Get(c, k, &post)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}

	postd, _ := base64.StdEncoding.DecodeString(post.Content)
	rw.Write(postd)
}

func ListPosts(rw http.ResponseWriter, req *http.Request) {
	c := appengine.NewContext(req)
	q := datastore.NewQuery("Post").Order("-Date").Limit(100)
	posts := make([]Post, 0, 100)

	if _, err := q.GetAll(c, &posts); err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
		return
	}
	FormattedPosts := make([]PostFormatted, 0)

	for _, v := range posts {
		if !strings.HasPrefix(v.Slug, "DRAFT-") {
			newpost := PostFormatted{
				Author:  v.Author,
				Content: v.Content,
				Date:    v.Date.Format("2006-01-02 15:04:05"),
				Slug:    v.Slug,
				Title:   v.Title,
			}
			FormattedPosts = append(FormattedPosts, newpost)
		}
	}

	layoutData := struct {
		Posts []PostFormatted
	}{
		Posts: FormattedPosts,
	}

	err := HomeTemplate.Execute(rw, layoutData)
	if err != nil {
		http.Error(rw, err.Error(), http.StatusInternalServerError)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/op/go-logging"
	"github.com/sorcix/irc"
	// "io"
	"io/ioutil"
	"strings"
)

const (
	server   = "irc.mindfang.org"
	port     = 6667
	username = "pcc31"
	nickname = "randomTesting"
)

var log = logging.MustGetLogger("Random Encounters")

func getNSPass() (string, error) {
	contents, err := ioutil.ReadFile("nspass")
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(contents)), nil
}

func handshake(conn *irc.Conn) (err error) {
	err = conn.Encode(&irc.Message{
		Command: "NICK",
		Params:  []string{nickname},
	})
	if err != nil {
		return err
	}
	return conn.Encode(&irc.Message{
		Command:  "USER",
		Params:   []string{username, "0", "*"},
		Trailing: "Hello world",
	})
}

func main() {
	fmt.Println("Hello world")
	// nspass, err := getNSPass()
	// if err != nil {
	// 	log.Fatalf("Unable to get Nickserv password: %s", err)
	// }
	// db stuff probably
	conn, err := irc.Dial(fmt.Sprintf("%s:%d", server, port))
	if err != nil {
		log.Fatalf("Could not connect to the server: %s", err)
	}
	// say hello
	err = handshake(conn)
	if err != nil {
		conn.Close()
		log.Fatalf("Could not handshake: %s", err)
	}
	var m *irc.Message
	for {
		m, err = conn.Decode()
		if err != nil {
			log.Error("Could not read message: %s", err)
			break
		}
		log.Info("Got message: %+v", m)
		if m.Command == "PING" {
			m.Command = "PONG"
			err = conn.Encode(m)
			if err != nil {
				log.Error("Couldn't pong: %s", err)
			}
		}
	}
	conn.Close()
	log.Info("It worked!")
}
<commit_msg>Refactorify + ignore spam messages<commit_after>package main

import (
	"fmt"
	"github.com/op/go-logging"
	"github.com/sorcix/irc"
	"io"
	"io/ioutil"
	"strings"
)

const (
	server   = "irc.mindfang.org"
	port     = 6667
	username = "pcc31"
	nickname = "randomTesting"
)

var log = logging.MustGetLogger("Random Encounters")

func getNSPass() (string, error) {
	contents, err := ioutil.ReadFile("nspass")
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(contents)), nil
}

func handshake(conn *irc.Conn) (err error) {
	err = conn.Encode(&irc.Message{
		Command: "NICK",
		Params:  []string{nickname},
	})
	if err != nil {
		return err
	}
	return conn.Encode(&irc.Message{
		Command:  "USER",
		Params:   []string{username, "0", "*"},
		Trailing: "Hello world",
	})
}

func handlePing(conn *irc.Conn, message *irc.Message) (err error) {
	// Ha ha ha this is so dodgy
	message.Command = "PONG"
	return conn.Encode(message)
}

func readPump(conn *irc.Conn) (err error) {
	var toIgnore = [...]string{"001", "002", "003", "005", "251", "252", "254", "255", "265", "266"}
	var shouldIgnore = make(map[string]bool, len(toIgnore))
	for _, num := range toIgnore {
		shouldIgnore[num] = true
	}
	var m *irc.Message

	for {
		m, err = conn.Decode()
		if err != nil {
			return err
		}
		// Ignore informative spam
		if shouldIgnore[m.Command] {
			continue
		}
		// Start of glorious message type switches
		if m.Command == "PING" {
			err = handlePing(conn, m)
			if err != nil {
				log.Error("Couldn't pong: %s", err)
			}
		} else {
			log.Info("Got message: %+v", m)
		}
	}
}

func main() {
	fmt.Println("Hello world")
	// nspass, err := getNSPass()
	// if err != nil {
	// 	log.Fatalf("Unable to get Nickserv password: %s", err)
	// }
	// db stuff probably
	conn, err := irc.Dial(fmt.Sprintf("%s:%d", server, port))
	if err != nil {
		log.Fatalf("Could not connect to the server: %s", err)
	}
	// say hello
	err = handshake(conn)
	if err != nil {
		conn.Close()
		log.Fatalf("Could not handshake: %s", err)
	}

	// Blocking
	err = readPump(conn)

	if err == io.EOF {
		log.Info("Server hung up")
	} else if err != nil {
		log.Critical("Could not read message: %s", err)
	}

	conn.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const buffer = 500
const workers = 20

// ping is an empty struct to send through channels
// as a notification that something finished.
type ping struct{}

var root string
var extensions []string
var pattern *regexp.Regexp
var insensitive = false

var pipe = make(chan string, buffer)
var done = make(chan ping)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

// search is a filepath.WalkFunc suitable for passing to
// filepath.Walk which passes the filenames found into a channel.
func search(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	if !info.Mode().IsRegular() {
		return nil
	}
	if len(extensions) > 0 {
		for _, ext := range extensions {
			if filepath.Ext(path) == ext {
				pipe <- path
				return nil
			}
		}
		return nil
	}
	pipe <- path
	return nil
}

// init parses the command-line arguments into the values
// used to execute. There should be a pattern at the very
// least. Optionally, a path (defaulting to "."), and
// file extensions to search may be provided.
func init() {
	args := os.Args[1:]
	if len(args) == 0 {
		log.Fatal("No arguments passed.")
	}
	args = getExts(args)
	args = getRoot(args)
	args = getCaseStr(args)
	if len(args) != 1 {
		log.Fatal("Unable to find pattern.")
	}
	pat := args[0]
	if insensitive {
		pat = strings.ToLower(pat)
	}
	p, err := regexp.Compile(pat)
	if err != nil {
		log.Fatalf("Unable to compile pattern %q: %q\n", pat, err)
	}
	pattern = p
}

// getCaseStr accepts command-line flags and strips out
// the -i flag (if it exists). It returns a boolean for whether
// the regex should be case-insensitive and the args.
func getCaseStr(args []string) []string {
	var unused []string
	for _, val := range args {
		if val == "-i" {
			insensitive = true
		} else {
			unused = append(unused, val)
		}
	}
	return unused
}

// getExts sets the extensions global variable,
// removes any extension arguments from args,
// and returns args for further processing.
func getExts(args []string) []string {
	var unused []string
	for _, val := range args {
		if strings.HasPrefix(val, "--") {
			if len(val) < 3 {
				log.Fatalf("Invalid extension: '%s'\n", val)
			}
			extensions = append(extensions, "."+val[2:])
		} else {
			unused = append(unused, val)
		}
	}
	return unused
}

// getRoot finds a valid directory in the command-line
// args, sets it to the global "root" variable, and
// returns the remaining arguments.
func getRoot(args []string) []string {
	var unused []string
	for _, val := range args {
		if isDir(val) {
			if root != "" {
				log.Fatalf("Too many directory arguments\n")
			} else {
				root = val
			}
		} else {
			unused = append(unused, val)
		}
	}
	if root == "" {
		root = "."
	}
	return unused
}

func main() {
	for i := 0; i < workers; i++ {
		go checkFile()
	}
	filepath.Walk(root, search)
	close(pipe)
	for i := 0; i < workers; i++ {
		<-done
	}
	os.Stdout.Sync()
}

// checkFile takes a filename and reads the file to determine
// whether the file contains the regex in the global pattern.
func checkFile() {
	for filename := range pipe {
		file, err := os.Open(filename)
		defer file.Close()
		if err != nil {
			log.Fatal(err)
			return
		}
		scanner := bufio.NewScanner(file)
		var fileType string
		line := 0
		for scanner.Scan() {
			line++
			txt := scanner.Text()
			if line == 1 {
				fileType = http.DetectContentType(scanner.Bytes())
			}
			if insensitive {
				txt = strings.ToLower(txt)
			}
			found := pattern.FindIndex([]byte(txt))
			if found != nil {
				if fileType[:4] != "text" {
					break
				}
				fmt.Printf("%s:%d:%s\n", filename, line, txt)
			}
		}
		file.Close()
	}
	done <- ping{}
}

func isDir(path string) bool {
	stat, err := os.Stat(path)
	if err != nil {
		return false
	}
	return stat.IsDir()
}
<commit_msg>fix output printing<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

const buffer = 500
const workers = 10

// ping is an empty struct to send through channels
// as a notification that something finished.
type ping struct{}

var root string
var extensions []string
var pattern *regexp.Regexp
var insensitive = false

var filenames = make(chan string, buffer)
var output = make(chan []string)
var done = make(chan ping)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

// search is a filepath.WalkFunc suitable for passing to
// filepath.Walk which passes the filenames found into a channel.
func search(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	if !info.Mode().IsRegular() {
		return nil
	}
	if len(extensions) > 0 {
		for _, ext := range extensions {
			if filepath.Ext(path) == ext {
				filenames <- path
				return nil
			}
		}
		return nil
	}
	filenames <- path
	return nil
}

// init parses the command-line arguments into the values
// used to execute. There should be a pattern at the very
// least. Optionally, a path (defaulting to "."), and
// file extensions to search may be provided.
func init() {
	args := os.Args[1:]
	if len(args) == 0 {
		log.Fatal("No arguments passed.")
	}
	args = getExts(args)
	args = getRoot(args)
	args = getCaseStr(args)
	if len(args) != 1 {
		log.Fatal("Unable to find pattern.")
	}
	pat := args[0]
	if insensitive {
		pat = strings.ToLower(pat)
	}
	p, err := regexp.Compile(pat)
	if err != nil {
		log.Fatalf("Unable to compile pattern %q: %q\n", pat, err)
	}
	pattern = p
}

// getCaseStr accepts command-line flags and strips out
// the -i flag (if it exists). It returns a boolean for whether
// the regex should be case-insensitive and the args.
func getCaseStr(args []string) []string {
	var unused []string
	for _, val := range args {
		if val == "-i" {
			insensitive = true
		} else {
			unused = append(unused, val)
		}
	}
	return unused
}

// getExts sets the extensions global variable,
// removes any extension arguments from args,
// and returns args for further processing.
func getExts(args []string) []string {
	var unused []string
	for _, val := range args {
		if strings.HasPrefix(val, "--") {
			if len(val) < 3 {
				log.Fatalf("Invalid extension: '%s'\n", val)
			}
			extensions = append(extensions, "."+val[2:])
		} else {
			unused = append(unused, val)
		}
	}
	return unused
}

// getRoot finds a valid directory in the command-line
// args, sets it to the global "root" variable, and
// returns the remaining arguments.
func getRoot(args []string) []string {
	var unused []string
	for _, val := range args {
		if isDir(val) {
			if root != "" {
				log.Fatalf("Too many directory arguments\n")
			} else {
				root = val
			}
		} else {
			unused = append(unused, val)
		}
	}
	if root == "" {
		root = "."
	}
	return unused
}

func main() {
	for i := 0; i < workers; i++ {
		go checkFile()
	}

	go func() {
		filepath.Walk(root, search)
		close(filenames)
	}()

	go func() {
		for i := 0; i < workers; i++ {
			<-done
		}
		close(output)
	}()

	for lines := range output {
		for _, line := range lines {
			fmt.Println(line)
		}
	}
	os.Stdout.Sync()
}

// checkFile takes a filename and reads the file to determine
// whether the file contains the regex in the global pattern.
func checkFile() {
	for filename := range filenames {
		file, err := os.Open(filename)
		defer file.Close()
		if err != nil {
			log.Fatal(err)
			return
		}
		scanner := bufio.NewScanner(file)
		var fileType string
		line := 0
		var lines []string
		for scanner.Scan() {
			line++
			txt := scanner.Text()
			if line == 1 {
				fileType = http.DetectContentType(scanner.Bytes())
			}
			if insensitive {
				txt = strings.ToLower(txt)
			}
			found := pattern.FindIndex([]byte(txt))
			if found != nil {
				if fileType[:4] != "text" {
					break
				}
				lines = append(lines, fmt.Sprintf("%s:%d:%s", filename, line, txt))
			}
		}
		output <- lines
		file.Close()
	}
	done <- ping{}
}

func isDir(path string) bool {
	stat, err := os.Stat(path)
	if err != nil {
		return false
	}
	return stat.IsDir()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math/rand"
	"time"

	"github.com/jroimartin/gocui"

	"home.leo-peltier.fr/teafortwo/game"
)

func main() {
	rand.Seed(time.Now().UnixNano())
	board := &game.Board{}
	board.PlaceRandom()

	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Fatalf("unable to init term: %s", err)
	}
	defer g.Close()

	g.SetManagerFunc(layout(board))

	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}

	if err := g.SetKeybinding("board", gocui.KeyArrowRight, gocui.ModNone, makeShiftCallback(board, game.DirRight)); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("board", gocui.KeyArrowDown, gocui.ModNone, makeShiftCallback(board, game.DirDown)); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("board", gocui.KeyArrowLeft, gocui.ModNone, makeShiftCallback(board, game.DirLeft)); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("board", gocui.KeyArrowUp, gocui.ModNone, makeShiftCallback(board, game.DirUp)); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		panic(err)
	}
}

func layout(b *game.Board) func(*gocui.Gui) error {
	return func(g *gocui.Gui) error {
		if v, err := g.SetView("board", 0, 0, 30, 18); err != nil {
			if err != gocui.ErrUnknownView {
				return err
			}

			g.SetCurrentView("board")
			v.Frame = false
			fmt.Fprintln(v, b.String())
		}

		if v, err := g.SetView("score", 32, 1, 62, 3); err != nil {
			if err != gocui.ErrUnknownView {
				return err
			}

			fmt.Fprintln(v, "score: 0")
		}
		return nil
	}
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}

func makeShiftCallback(b *game.Board, dir game.Direction) func(*gocui.Gui, *gocui.View) error {
	return func(g *gocui.Gui, v *gocui.View) error {
		if !b.Shift(dir) {
			return nil
		}

		if err := b.PlaceRandom(); err != nil {
			return err
		}

		v.Clear()
		fmt.Fprintln(v, b.String())

		// TODO: actually handle the endgame, panic'ing is not exactly user-friendly.
		if !b.HasMovesLeft() {
			return fmt.Errorf("no moves left, score: %d", b.Score())
		}

		score, err := g.View("score")
		if err != nil {
			return fmt.Errorf("unable to get score view: %s", err)
		}

		score.Clear()
		fmt.Fprintf(score, "score: %d", b.Score())

		return nil
	}
}
<commit_msg>Remove leftovers<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"time"

	"github.com/jroimartin/gocui"

	"home.leo-peltier.fr/teafortwo/game"
)

func main() {
	rand.Seed(time.Now().UnixNano())
	board := &game.Board{}
	board.PlaceRandom()

	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Fatalf("unable to init term: %s", err)
	}
	defer g.Close()

	g.SetManagerFunc(layout(board))

	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("", 'q', gocui.ModNone, quit); err != nil {
		log.Panicln(err)
	}

	if err := g.SetKeybinding("board", gocui.KeyArrowRight, gocui.ModNone, makeShiftCallback(board, game.DirRight)); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("board", gocui.KeyArrowDown, gocui.ModNone, makeShiftCallback(board, game.DirDown)); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("board", gocui.KeyArrowLeft, gocui.ModNone, makeShiftCallback(board, game.DirLeft)); err != nil {
		log.Panicln(err)
	}
	if err := g.SetKeybinding("board", gocui.KeyArrowUp, gocui.ModNone, makeShiftCallback(board, game.DirUp)); err != nil {
		log.Panicln(err)
	}

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func layout(b *game.Board) func(*gocui.Gui) error {
	return func(g *gocui.Gui) error {
		if v, err := g.SetView("board", 0, 0, 30, 18); err != nil {
			if err != gocui.ErrUnknownView {
				return err
			}

			g.SetCurrentView("board")
			v.Frame = false
			fmt.Fprintln(v, b.String())
		}

		if v, err := g.SetView("score", 32, 1, 62, 3); err != nil {
			if err != gocui.ErrUnknownView {
				return err
			}

			fmt.Fprintln(v, "score: 0")
		}
		return nil
	}
}

func quit(g *gocui.Gui, v *gocui.View) error {
	return gocui.ErrQuit
}

func makeShiftCallback(b *game.Board, dir game.Direction) func(*gocui.Gui, *gocui.View) error {
	return func(g *gocui.Gui, v *gocui.View) error {
		if !b.Shift(dir) {
			return nil
		}

		if err := b.PlaceRandom(); err != nil {
			return err
		}

		v.Clear()
		fmt.Fprintln(v, b.String())

		// TODO: actually handle the endgame, panic'ing is not exactly user-friendly.
		if !b.HasMovesLeft() {
			return fmt.Errorf("no moves left, score: %d", b.Score())
		}

		score, err := g.View("score")
		if err != nil {
			return fmt.Errorf("unable to get score view: %s", err)
		}

		score.Clear()
		fmt.Fprintf(score, "score: %d", b.Score())

		return nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/oyakata/kanjo/lib/wc"
	htmlTemplate "html/template"
	"log"
	"net/http"
)

func init() {
	// URLパターンに正規表現は渡せない。
	http.HandleFunc("/count/file", FileWordCountHandler)
	http.HandleFunc("/count", WordCountHandler)

	// 順番に注意。"/"を先頭に指定すると他のPathがマッチしない。
	http.HandleFunc("/", TopPageHandler)
}

func main() {
	port := 8080
	log.Printf("start server, port %v", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
}

// 1. [済]テンプレートエンジンを使って処理するよう変更
// 2. [済]JSONで返却する機能を追加
// 3. [済]ファイルを読み取って文字数を数える機能を追加
// 4. [済]文字数とバイト数を数えるよう変更
// 5. ユニットテストを追加
// 6. [済]最初のプログラムだと文字数ではなくバイト数を返してしまうので直す
// 7. logをファイルに出力するよう変更
// 8. [済]HTMLのエスケープがないので直す

type Context map[string]interface{}

func FileWordCountHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "POSTでアクセスしてください", http.StatusMethodNotAllowed)
		return
	}

	file, _, err := r.FormFile("file")
	if err != nil {
		http.Error(w, fmt.Sprintf("%v", err), http.StatusBadRequest)
	}

	defer func() {
		file.Close()
		r.MultipartForm.RemoveAll()
	}()

	count, bc, invalid := wc.WordCountInFile(file)

	tmpl, _ := htmlTemplate.New("file_wc").Parse(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>文字数カウント結果</title>

文字数カウント結果

			文字数は: {{.count}}

			バイト数は: {{.bc}}

			不正なバイト数は: {{.invalid}}

			でした。

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32">
			<input type="submit">
			</form>

			ファイルを調べたい場合はこちら。
			<form action="/count/file" method="POST" enctype="multipart/form-data">
			<input type="file" name="file">
			<input type="submit">
			</form>

	`)

	data := Context{
		"count":   count,
		"bc":      bc,
		"invalid": invalid,
	}
	if err := tmpl.Execute(w, data); err != nil {
		log.Panic(err)
	}
}

func TopPageHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>Welcome to kanjo.</title>

Hello, world.

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32">
			<input type="submit">
			</form>

			ファイルを調べたい場合はこちら。
			<form action="/count/file" method="POST" enctype="multipart/form-data">
			<input type="file" name="file">
			<input type="submit">
			</form>

	`))
}

func WordCountHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("format") == "json" {
		JSONWordCountHandler(w, r)
	} else {
		HTMLWordCountHandler(w, r)
	}
}

// json.Marshalは構造体の公開フィールドしか出力してくれないので注意。
// 小文字でJSONのキーを出力したければタグを指定する。
type WordCount struct {
	Text      string `json:"text"`
	Count     int    `json:"count"`
	ByteCount int    `json:"byte_count"`
}

func JSONWordCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	text := r.FormValue("text")
	count, bc, _ := wc.WordCountInString(text)

	result, err := json.Marshal(WordCount{text, count, bc})
	if err != nil {
		log.Panic(err)
	}
	w.Write(result)
}

func HTMLWordCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	text := r.FormValue("text")
	count, _, _ := wc.WordCountInString(text)

	tmpl, _ := htmlTemplate.New("wc").Parse(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>文字数カウント結果</title>

文字数カウント結果

			入力文字: {{.text}}

			文字数は: {{.count}}

			でした。

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32" class="{{.css}}">
			<input type="submit">
			</form>

	`)

	css := ""
	if count == 0 {
		css = "err"
	}

	data := Context{"text": text, "count": count, "css": css}
	if err := tmpl.Execute(w, data); err != nil {
		log.Panic(err)
	}
}
<commit_msg>garden<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/oyakata/kanjo/lib/wc"
	htmlTemplate "html/template"
	"log"
	"net/http"
)

func init() {
	// URLパターンに正規表現は渡せない。
	http.HandleFunc("/count/file", FileWordCountHandler)
	http.HandleFunc("/count", WordCountHandler)

	// 順番に注意。"/"を先頭に指定すると他のPathがマッチしない。
	http.HandleFunc("/", TopPageHandler)
}

func main() {
	port := 8080
	log.Printf("start server, port %v", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", port), nil))
}

// 1. [済]テンプレートエンジンを使って処理するよう変更
// 2. [済]JSONで返却する機能を追加
// 3. [済]ファイルを読み取って文字数を数える機能を追加
// 4. [済]文字数とバイト数を数えるよう変更
// 5. [済]ユニットテストを追加
// 6. [済]最初のプログラムだと文字数ではなくバイト数を返してしまうので直す
// 7. logをファイルに出力するよう変更
// 8. [済]HTMLのエスケープがないので直す

type Context map[string]interface{}

func FileWordCountHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "POSTでアクセスしてください", http.StatusMethodNotAllowed)
		return
	}

	file, _, err := r.FormFile("file")
	if err != nil {
		http.Error(w, fmt.Sprintf("%v", err), http.StatusBadRequest)
	}

	defer func() {
		file.Close()
		r.MultipartForm.RemoveAll()
	}()

	count, bc, invalid := wc.WordCountInFile(file)

	tmpl, _ := htmlTemplate.New("file_wc").Parse(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>文字数カウント結果</title>

文字数カウント結果

			文字数は: {{.count}}

			バイト数は: {{.bc}}

			不正なバイト数は: {{.invalid}}

			でした。

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32">
			<input type="submit">
			</form>

			ファイルを調べたい場合はこちら。
			<form action="/count/file" method="POST" enctype="multipart/form-data">
			<input type="file" name="file">
			<input type="submit">
			</form>

	`)

	data := Context{
		"count":   count,
		"bc":      bc,
		"invalid": invalid,
	}
	if err := tmpl.Execute(w, data); err != nil {
		log.Panic(err)
	}
}

func TopPageHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	w.Write([]byte(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>Welcome to kanjo.</title>

Hello, world.

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32">
			<input type="submit">
			</form>

			ファイルを調べたい場合はこちら。
			<form action="/count/file" method="POST" enctype="multipart/form-data">
			<input type="file" name="file">
			<input type="submit">
			</form>

	`))
}

func WordCountHandler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("format") == "json" {
		JSONWordCountHandler(w, r)
	} else {
		HTMLWordCountHandler(w, r)
	}
}

// json.Marshalは構造体の公開フィールドしか出力してくれないので注意。
// 小文字でJSONのキーを出力したければタグを指定する。
type WordCount struct {
	Text      string `json:"text"`
	Count     int    `json:"count"`
	ByteCount int    `json:"byte_count"`
}

func JSONWordCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")

	text := r.FormValue("text")
	count, bc, _ := wc.WordCountInString(text)

	result, err := json.Marshal(WordCount{text, count, bc})
	if err != nil {
		log.Panic(err)
	}
	w.Write(result)
}

func HTMLWordCountHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")

	text := r.FormValue("text")
	count, _, _ := wc.WordCountInString(text)

	tmpl, _ := htmlTemplate.New("wc").Parse(`

			<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
			<title>文字数カウント結果</title>

文字数カウント結果

			入力文字: {{.text}}

			文字数は: {{.count}}

			でした。

			文字を入力してください。
			<form action="/count" method="GET">
			<input type="text" name="text" size="32" class="{{.css}}">
			<input type="submit">
			</form>

	`)

	css := ""
	if count == 0 {
		css = "err"
	}

	data := Context{"text": text, "count": count, "css": css}
	if err := tmpl.Execute(w, data); err != nil {
		log.Panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"html/template"
	"net/http"
	"sync"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"

	local "eirka-index/config"
)

var (
	sitemap map[string]*SiteData
	mu      sync.RWMutex
)

func init() {

	// map to hold site data so we dont hit the database every time
	sitemap = make(map[string]*SiteData)

	// Database connection settings
	dbase := db.Database{
		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

}

func main() {

	// parse our template
	t := template.Must(template.New("templates").Delims("[[", "]]").Parse(index))
	t = template.Must(t.Parse(head))
	t = template.Must(t.Parse(header))
	t = template.Must(t.Parse(navmenu))
	t = template.Must(t.ParseGlob(fmt.Sprintf("%s/includes/*.tmpl", local.Settings.Directories.AssetsDir)))

	r := gin.Default()

	// load template into gin
	r.SetHTMLTemplate(t)

	// use the details middleware
	r.Use(Details())

	r.GET("/", IndexController)
	r.GET("/page/:id", IndexController)
	r.GET("/thread/:id/:page", IndexController)
	r.GET("/directory", IndexController)
	r.GET("/image/:id", IndexController)
	r.GET("/tags/:page", IndexController)
	r.GET("/tags", IndexController)
	r.GET("/tag/:id/:page", IndexController)
	r.GET("/account", IndexController)
	r.GET("/trending", IndexController)
	r.GET("/favorites/:page", IndexController)
	r.GET("/favorites", IndexController)
	r.GET("/error", IndexController)

	r.NoRoute(ErrorController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Index.Address, local.Settings.Index.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}
<commit_msg>fix import<commit_after>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"html/template"
	"net/http"
	"sync"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"

	local "github.com/eirka/eirka-index/config"
)

var (
	sitemap map[string]*SiteData
	mu      sync.RWMutex
)

func init() {

	// map to hold site data so we dont hit the database every time
	sitemap = make(map[string]*SiteData)

	// Database connection settings
	dbase := db.Database{
		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

}

func main() {

	// parse our template
	t := template.Must(template.New("templates").Delims("[[", "]]").Parse(index))
	t = template.Must(t.Parse(head))
	t = template.Must(t.Parse(header))
	t = template.Must(t.Parse(navmenu))
	t = template.Must(t.ParseGlob(fmt.Sprintf("%s/includes/*.tmpl", local.Settings.Directories.AssetsDir)))

	r := gin.Default()

	// load template into gin
	r.SetHTMLTemplate(t)

	// use the details middleware
	r.Use(Details())

	r.GET("/", IndexController)
	r.GET("/page/:id", IndexController)
	r.GET("/thread/:id/:page", IndexController)
	r.GET("/directory", IndexController)
	r.GET("/image/:id", IndexController)
	r.GET("/tags/:page", IndexController)
	r.GET("/tags", IndexController)
	r.GET("/tag/:id/:page", IndexController)
	r.GET("/account", IndexController)
	r.GET("/trending", IndexController)
	r.GET("/favorites/:page", IndexController)
	r.GET("/favorites", IndexController)
	r.GET("/error", IndexController)

	r.NoRoute(ErrorController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Index.Address, local.Settings.Index.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/docker/go-units"
	"golang.org/x/net/websocket"

	"fmt"

	"github.com/aerokube/selenoid/config"
	"github.com/aerokube/selenoid/protect"
	"github.com/aerokube/selenoid/service"
	"github.com/aerokube/selenoid/session"
	"github.com/docker/docker/client"
)

type memLimit int64

func (m *memLimit) String() string {
	return units.HumanSize(float64(*m))
}

func (limit *memLimit) Set(s string) error {
	v, err := units.RAMInBytes(s)
	if err != nil {
		return fmt.Errorf("set memory limit: %v", err)
	}
	*limit = memLimit(v)
	return nil
}

type cpuLimit int64

func (limit *cpuLimit) String() string {
	return strconv.FormatFloat(float64(*limit/1000000000), 'f', -1, 64)
}

func (limit *cpuLimit) Set(s string) error {
	v, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return fmt.Errorf("set cpu limit: %v", err)
	}
	*limit = cpuLimit(v * 1000000000)
	return nil
}

var (
	hostname                 string
	disableDocker            bool
	disableQueue             bool
	enableFileUpload         bool
	listen                   string
	timeout                  time.Duration
	newSessionAttemptTimeout time.Duration
	sessionDeleteTimeout     time.Duration
	serviceStartupTimeout    time.Duration
	limit                    int
	retryCount               int
	containerNetwork         string
	sessions                 = session.NewMap()
	confPath                 string
	logConfPath              string
	conf                     *config.Config
	queue                    *protect.Queue
	manager                  service.Manager
	cli                      *client.Client

	startTime = time.Now()

	version     bool
	gitRevision string = "HEAD"
	buildStamp  string = "unknown"
)

func init() {
	var mem memLimit
	var cpu cpuLimit
	flag.BoolVar(&disableDocker, "disable-docker", false, "Disable docker support")
	flag.BoolVar(&disableQueue, "disable-queue", false, "Disable wait queue")
	flag.BoolVar(&enableFileUpload, "enable-file-upload", false, "File upload support")
	flag.StringVar(&listen, "listen", ":4444", "Network address to accept connections")
	flag.StringVar(&confPath, "conf", "config/browsers.json", "Browsers configuration file")
	flag.StringVar(&logConfPath, "log-conf", "config/container-logs.json", "Container logging configuration file")
	flag.IntVar(&limit, "limit", 5, "Simultaneous container runs")
	flag.IntVar(&retryCount, "retry-count", 1, "New session attempts retry count")
	flag.DurationVar(&timeout, "timeout", 60*time.Second, "Session idle timeout in time.Duration format")
	flag.DurationVar(&newSessionAttemptTimeout, "session-attempt-timeout", 30*time.Second, "New session attempt timeout in time.Duration format")
	flag.DurationVar(&sessionDeleteTimeout, "session-delete-timeout", 30*time.Second, "Session delete timeout in time.Duration format")
	flag.DurationVar(&serviceStartupTimeout, "service-startup-timeout", 30*time.Second, "Service startup timeout in time.Duration format")
	flag.BoolVar(&version, "version", false, "Show version and exit")
	flag.Var(&mem, "mem", "Containers memory limit e.g. 128m or 1g")
	flag.Var(&cpu, "cpu", "Containers cpu limit as float e.g. 0.2 or 1.0")
	flag.StringVar(&containerNetwork, "container-network", "default", "Network to be used for containers")
	flag.Parse()

	if version {
		showVersion()
		os.Exit(0)
	}

	var err error
	hostname, err = os.Hostname()
	if err != nil {
		log.Fatalf("%s: %v", os.Args[0], err)
	}
	queue = protect.New(limit, disableQueue)
	conf = config.NewConfig()
	err = conf.Load(confPath, logConfPath)
	if err != nil {
		log.Fatalf("%s: %v", os.Args[0], err)
	}
	onSIGHUP(func() {
		err := conf.Load(confPath, logConfPath)
		if err != nil {
			log.Printf("%s: %v", os.Args[0], err)
		}
	})
	cancelOnSignal()
	inDocker := false
	_, err = os.Stat("/.dockerenv")
	if err == nil {
		inDocker = true
	}
	environment := service.Environment{
		InDocker:       inDocker,
		CPU:            int64(cpu),
		Memory:         int64(mem),
		Network:        containerNetwork,
		StartupTimeout: serviceStartupTimeout,
	}
	if disableDocker {
		manager = &service.DefaultManager{Environment: &environment, Config: conf}
		return
	}
	dockerHost := os.Getenv("DOCKER_HOST")
	if dockerHost == "" {
		dockerHost = client.DefaultDockerHost
	}
	_, addr, _, err := client.ParseHost(dockerHost)
	if err != nil {
		log.Fatal(err)
	}
	ip, _, _ := net.SplitHostPort(addr)
	environment.IP = ip
	cli, err = client.NewEnvClient()
	if err != nil {
		log.Fatalf("new docker client: %v\n", err)
	}
	manager = &service.DefaultManager{Environment: &environment, Client: cli, Config: conf}
}

func cancelOnSignal() {
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-sig
		sessions.Each(func(k string, s *session.Session) {
			if enableFileUpload {
				os.RemoveAll(path.Join(os.TempDir(), k))
			}
			s.Cancel()
		})
		if !disableDocker {
			err := cli.Close()
			if err != nil {
				log.Fatalf("close docker client: %v", err)
				os.Exit(1)
			}
		}
		os.Exit(0)
	}()
}

func onSIGHUP(fn func()) {
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGHUP)
	go func() {
		for {
			<-sig
			fn()
		}
	}()
}

func mux() http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc("/session", queue.Check(queue.Protect(post(create))))
	mux.HandleFunc("/session/", proxy)
	return mux
}

func post(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	}
}

func ping(w http.ResponseWriter, _ *http.Request) {
	json.NewEncoder(w).Encode(struct {
		Uptime         string `json:"uptime"`
		LastReloadTime string `json:"lastReloadTime"`
	}{time.Since(startTime).String(), conf.LastReloadTime.String()})
}

func handler() http.Handler {
	root := http.NewServeMux()
	root.HandleFunc("/wd/hub/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Content-Type", "application/json")
		r.URL.Scheme = "http"
		r.URL.Host = (&request{r}).localaddr()
		r.URL.Path = strings.TrimPrefix(r.URL.Path, "/wd/hub")
		mux().ServeHTTP(w, r)
	})
	root.HandleFunc("/error", func(w http.ResponseWriter, r *http.Request) {
		jsonError(w, "Session not found", http.StatusNotFound)
	})
	root.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		json.NewEncoder(w).Encode(conf.State(sessions, limit, queue.Queued(), queue.Pending()))
	})
	root.HandleFunc("/ping", ping)
	root.Handle("/vnc/", websocket.Handler(vnc))
	root.Handle("/logs/", websocket.Handler(logs))
	if enableFileUpload {
		root.HandleFunc("/file", fileUpload)
	}
	return root
}

func showVersion() {
	fmt.Printf("Git Revision: %s\n", gitRevision)
	fmt.Printf("UTC Build Time: %s\n", buildStamp)
}

func main() {
	log.Printf("Timezone: %s\n", time.Local)
	log.Printf("Listening on %s\n", listen)
	log.Fatal(http.ListenAndServe(listen, handler()))
}
<commit_msg>More clear timeout message<commit_after>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	"github.com/docker/go-units"
	"golang.org/x/net/websocket"

	"fmt"

	"github.com/aerokube/selenoid/config"
	"github.com/aerokube/selenoid/protect"
	"github.com/aerokube/selenoid/service"
	"github.com/aerokube/selenoid/session"
	"github.com/docker/docker/client"
)

type memLimit int64

func (m *memLimit) String() string {
	return units.HumanSize(float64(*m))
}

func (limit *memLimit) Set(s string) error {
	v, err := units.RAMInBytes(s)
	if err != nil {
		return fmt.Errorf("set memory limit: %v", err)
	}
	*limit = memLimit(v)
	return nil
}

type cpuLimit int64

func (limit *cpuLimit) String() string {
	return strconv.FormatFloat(float64(*limit/1000000000), 'f', -1, 64)
}

func (limit *cpuLimit) Set(s string) error {
	v, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return fmt.Errorf("set cpu limit: %v", err)
	}
	*limit = cpuLimit(v * 1000000000)
	return nil
}

var (
	hostname                 string
	disableDocker            bool
	disableQueue             bool
	enableFileUpload         bool
	listen                   string
	timeout                  time.Duration
	newSessionAttemptTimeout time.Duration
	sessionDeleteTimeout     time.Duration
	serviceStartupTimeout    time.Duration
	limit                    int
	retryCount               int
	containerNetwork         string
	sessions                 = session.NewMap()
	confPath                 string
	logConfPath              string
	conf                     *config.Config
	queue                    *protect.Queue
	manager                  service.Manager
	cli                      *client.Client

	startTime = time.Now()

	version     bool
	gitRevision string = "HEAD"
	buildStamp  string = "unknown"
)

func init() {
	var mem memLimit
	var cpu cpuLimit
	flag.BoolVar(&disableDocker, "disable-docker", false, "Disable docker support")
	flag.BoolVar(&disableQueue, "disable-queue", false, "Disable wait queue")
	flag.BoolVar(&enableFileUpload, "enable-file-upload", false, "File upload support")
	flag.StringVar(&listen, "listen", ":4444", "Network address to accept connections")
	flag.StringVar(&confPath, "conf", "config/browsers.json", "Browsers configuration file")
	flag.StringVar(&logConfPath, "log-conf", "config/container-logs.json", "Container logging configuration file")
	flag.IntVar(&limit, "limit", 5, "Simultaneous container runs")
	flag.IntVar(&retryCount, "retry-count", 1, "New session attempts retry count")
	flag.DurationVar(&timeout, "timeout", 60*time.Second, "Session idle timeout in time.Duration format")
	flag.DurationVar(&newSessionAttemptTimeout, "session-attempt-timeout", 30*time.Second, "New session attempt timeout in time.Duration format")
	flag.DurationVar(&sessionDeleteTimeout, "session-delete-timeout", 30*time.Second, "Session delete timeout in time.Duration format")
	flag.DurationVar(&serviceStartupTimeout, "service-startup-timeout", 30*time.Second, "Service startup timeout in time.Duration format")
	flag.BoolVar(&version, "version", false, "Show version and exit")
	flag.Var(&mem, "mem", "Containers memory limit e.g. 128m or 1g")
	flag.Var(&cpu, "cpu", "Containers cpu limit as float e.g. 0.2 or 1.0")
	flag.StringVar(&containerNetwork, "container-network", "default", "Network to be used for containers")
	flag.Parse()

	if version {
		showVersion()
		os.Exit(0)
	}

	var err error
	hostname, err = os.Hostname()
	if err != nil {
		log.Fatalf("%s: %v", os.Args[0], err)
	}
	queue = protect.New(limit, disableQueue)
	conf = config.NewConfig()
	err = conf.Load(confPath, logConfPath)
	if err != nil {
		log.Fatalf("%s: %v", os.Args[0], err)
	}
	onSIGHUP(func() {
		err := conf.Load(confPath, logConfPath)
		if err != nil {
			log.Printf("%s: %v", os.Args[0], err)
		}
	})
	cancelOnSignal()
	inDocker := false
	_, err = os.Stat("/.dockerenv")
	if err == nil {
		inDocker = true
	}
	environment := service.Environment{
		InDocker:       inDocker,
		CPU:            int64(cpu),
		Memory:         int64(mem),
		Network:        containerNetwork,
		StartupTimeout: serviceStartupTimeout,
	}
	if disableDocker {
		manager = &service.DefaultManager{Environment: &environment, Config: conf}
		return
	}
	dockerHost := os.Getenv("DOCKER_HOST")
	if dockerHost == "" {
		dockerHost = client.DefaultDockerHost
	}
	_, addr, _, err := client.ParseHost(dockerHost)
	if err != nil {
		log.Fatal(err)
	}
	ip, _, _ := net.SplitHostPort(addr)
	environment.IP = ip
	cli, err = client.NewEnvClient()
	if err != nil {
		log.Fatalf("new docker client: %v\n", err)
	}
	manager = &service.DefaultManager{Environment: &environment, Client: cli, Config: conf}
}

func cancelOnSignal() {
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-sig
		sessions.Each(func(k string, s *session.Session) {
			if enableFileUpload {
				os.RemoveAll(path.Join(os.TempDir(), k))
			}
			s.Cancel()
		})
		if !disableDocker {
			err := cli.Close()
			if err != nil {
				log.Fatalf("close docker client: %v", err)
				os.Exit(1)
			}
		}
		os.Exit(0)
	}()
}

func onSIGHUP(fn func()) {
	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGHUP)
	go func() {
		for {
			<-sig
			fn()
		}
	}()
}

func mux() http.Handler {
	mux := http.NewServeMux()
	mux.HandleFunc("/session", queue.Check(queue.Protect(post(create))))
	mux.HandleFunc("/session/", proxy)
	return mux
}

func post(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}
		next.ServeHTTP(w, r)
	}
}

func ping(w http.ResponseWriter, _ *http.Request) {
	json.NewEncoder(w).Encode(struct {
		Uptime         string `json:"uptime"`
		LastReloadTime string `json:"lastReloadTime"`
	}{time.Since(startTime).String(), conf.LastReloadTime.String()})
}

func handler() http.Handler {
	root := http.NewServeMux()
	root.HandleFunc("/wd/hub/", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Add("Content-Type", "application/json")
		r.URL.Scheme = "http"
		r.URL.Host = (&request{r}).localaddr()
		r.URL.Path = strings.TrimPrefix(r.URL.Path, "/wd/hub")
		mux().ServeHTTP(w, r)
	})
	root.HandleFunc("/error", func(w http.ResponseWriter, r *http.Request) {
		jsonError(w, "Session timed out or not found", http.StatusNotFound)
	})
	root.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
		json.NewEncoder(w).Encode(conf.State(sessions, limit, queue.Queued(), queue.Pending()))
	})
	root.HandleFunc("/ping", ping)
	root.Handle("/vnc/", websocket.Handler(vnc))
	root.Handle("/logs/", websocket.Handler(logs))
	if enableFileUpload {
		root.HandleFunc("/file", fileUpload)
	}
	return root
}

func showVersion() {
	fmt.Printf("Git Revision: %s\n", gitRevision)
	fmt.Printf("UTC Build Time: %s\n", buildStamp)
}

func main() {
	log.Printf("Timezone: %s\n", time.Local)
	log.Printf("Listening on %s\n", listen)
	log.Fatal(http.ListenAndServe(listen, handler()))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"

	"github.com/yuya-takeyama/argf"
)

var (
	name  = "catn"
	usage = fmt.Sprintf("usage: %s N [FILE]...", name)
)

func printErr(err error) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func main() {
	if len(os.Args) < 2 || os.Args[1] == "--help" {
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(2)
	}

	n, err := strconv.Atoi(os.Args[1])
	if err != nil {
		printErr(err)
		os.Exit(2)
	}

	r, err := argf.From(os.Args[2:])
	if err != nil {
		printErr(err)
		os.Exit(2)
	}

	src, err := ioutil.ReadAll(r)
	if err != nil {
		printErr(err)
		os.Exit(1)
	}

	switch {
	case n < 0:
		for {
			os.Stdout.Write(src)
		}
	default:
		for i := 0; i < n; i++ {
			os.Stdout.Write(src)
		}
	}
}
<commit_msg>Use if-else instead of switch if branches are two<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"

	"github.com/yuya-takeyama/argf"
)

var (
	name  = "catn"
	usage = fmt.Sprintf("usage: %s N [FILE]...", name)
)

func printErr(err error) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func main() {
	if len(os.Args) < 2 || os.Args[1] == "--help" {
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(2)
	}

	n, err := strconv.Atoi(os.Args[1])
	if err != nil {
		printErr(err)
		os.Exit(2)
	}

	r, err := argf.From(os.Args[2:])
	if err != nil {
		printErr(err)
		os.Exit(2)
	}

	src, err := ioutil.ReadAll(r)
	if err != nil {
		printErr(err)
		os.Exit(1)
	}

	if n < 0 {
		for {
			os.Stdout.Write(src)
		}
	} else {
		for i := 0; i < n; i++ {
			os.Stdout.Write(src)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"./schemas"
	"flag"
	"fmt"
	"github.com/Shopify/sarama"
	"github.com/companieshouse/chs.go/avro"
	"github.com/companieshouse/chs.go/avro/schema"
	"github.com/companieshouse/chs.go/kafka/producer"
	"os"
	"os/signal"
	"strconv"
	"strings"
)

// Assigns all flags to variables
var (
	brokerPtr         = flag.String("broker", "", "Broker")
	topicPtr          = flag.String("topic", "", "Topic name")
	schemaPtr         = flag.String("schema", "", "Schema")
	schemaRegistryPtr = flag.String("schema-registry", "", "Schema Registry")
	partitionPtr      = flag.Int64("partition", 0, "Partition")
	zookeeperPtr      = flag.String("zookeeper", "", "Zookeeper")
	offsetPtr         = flag.String("offset", "-1", "Offset number")
	jsonOutPtr        = flag.Int("json-out", -1, "Does deserialized JSON get printed to terminal?")
)

func main() {
	flag.Parse()

	fmt.Println("broker:", *brokerPtr)
	fmt.Println("topic:", *topicPtr)
	fmt.Println("schema:", *schemaPtr)
	fmt.Println("schema-registry:", *schemaRegistryPtr)
	fmt.Println("partition:", *partitionPtr)
	fmt.Println("zookeeper-registry:", *zookeeperPtr)
	fmt.Println("offset:", *offsetPtr)
	fmt.Println("json-out:", *jsonOutPtr)

	// create offset array
	offsetArray := createOffsetArray(*offsetPtr)

	// create default config for sarama
	config := sarama.NewConfig()

	//create consumer
	consumer, err := sarama.NewConsumer([]string{*brokerPtr}, config)
	if err != nil {
		panic(err)
	}

	// create messages chan
	messages := make(chan *sarama.ConsumerMessage)
	go consumePartition(consumer, *topicPtr, int32(*partitionPtr), messages, offsetArray)

	// create signals chan
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt)

	consumed := 0
ConsumerLoop:
	for {
		select {
		case msg := <-messages:

			schemaStruct := schemas.IdentifySchema(*topicPtr)
			var err error

			// Get schema from schema registry and use it to create avro consumer
			schema, err := schema.Get(*schemaRegistryPtr, *topicPtr)
			consumerAvro := &avro.Schema{
				Definition: schema,
			}

			// Unmarshal message value and assign it to schemaStruct
			if err = consumerAvro.Unmarshal(msg.Value, schemaStruct); err != nil {
				fmt.Println("Error unmarshalling avro:")
			}

			// create avro producer
			producerAvro := &avro.Schema{
				Definition: schema,
			}

			// Marshall schemaStruct that contains message value ready for republishing
			messageBytes, err := producerAvro.Marshal(schemaStruct)
			if err != nil {
				fmt.Println("Error Marshalling avro:")
			}

			// create producer message
			producerMessage := &producer.Message{
				Value: messageBytes,
				Topic: *topicPtr,
			}

			//create new producer
			p, err := producer.New(&producer.Config{Acks: &producer.WaitForAll, BrokerAddrs: []string{*brokerPtr}})
			if err != nil {
				os.Exit(1)
			}

			// republish message
			partition, offset, err := p.Send(producerMessage)
			if err != nil {
				fmt.Println("Error republishing message:")
			}
			fmt.Println("Message republished!", partition, offset)

			consumed++
		case <-signals:
			fmt.Println("break")
			break ConsumerLoop
		}
	}
}

// The offset slice is passed into method and is iterated over and each message
// related to the offset in the topic/partition is outputted into the 'out' chan
func consumePartition(consumer sarama.Consumer, topic string, partition int32, out chan *sarama.ConsumerMessage, offsetArray []int64) {
	for offset := range offsetArray {
		partitionConsumer, err := consumer.ConsumePartition(topic, partition, int64(offset))
		if err != nil {
			panic(err)
		}

		select {
		case msg := <-partitionConsumer.Messages():
			partitionConsumer.Close()
			out <- msg
		}
	}
}

// This creates the offset array depending on whether a range or a single value
// is entered as an argument to the tool
func createOffsetArray(offset string) []int64 {
	arraySize := make([]int64, 0)
	if strings.ContainsAny(offset, "-") {
		slice := strings.Split(offset, "-")
		minRange, err := strconv.ParseInt(slice[0], 10, 64)
		maxRange, err := strconv.ParseInt(slice[1], 10, 64)
		if err != nil {
			panic(err)
		}

		index := 0
		for value := minRange; value <= maxRange; value++ {
			arraySize = append(arraySize, value)
			index++
		}
	} else {
		value, err := strconv.ParseInt(offset, 10, 64)
		if err != nil {
			panic(err)
		}
		arraySize = append(arraySize, value)
	}
	return arraySize
}
<commit_msg>Organise imports using goimports<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"

	"./schemas"
	"github.com/Shopify/sarama"
	"github.com/companieshouse/chs.go/avro"
	"github.com/companieshouse/chs.go/avro/schema"
	"github.com/companieshouse/chs.go/kafka/producer"
)

// Assigns all flags to variables
var (
	brokerPtr         = flag.String("broker", "", "Broker")
	topicPtr          = flag.String("topic", "", "Topic name")
	schemaPtr         = flag.String("schema", "", "Schema")
	schemaRegistryPtr = flag.String("schema-registry", "", "Schema Registry")
	partitionPtr      = flag.Int64("partition", 0, "Partition")
	zookeeperPtr      = flag.String("zookeeper", "", "Zookeeper")
	offsetPtr         = flag.String("offset", "-1", "Offset number")
	jsonOutPtr        = flag.Int("json-out", -1, "Does deserialized JSON get printed to terminal?")
)

func main() {
	flag.Parse()

	fmt.Println("broker:", *brokerPtr)
	fmt.Println("topic:", *topicPtr)
	fmt.Println("schema:", *schemaPtr)
	fmt.Println("schema-registry:", *schemaRegistryPtr)
	fmt.Println("partition:", *partitionPtr)
	fmt.Println("zookeeper-registry:", *zookeeperPtr)
	fmt.Println("offset:", *offsetPtr)
	fmt.Println("json-out:", *jsonOutPtr)

	// create offset array
	offsetArray := createOffsetArray(*offsetPtr)

	// create default config for sarama
	config := sarama.NewConfig()

	//create consumer
	consumer, err := sarama.NewConsumer([]string{*brokerPtr}, config)
	if err != nil {
		panic(err)
	}

	// create messages chan
	messages := make(chan *sarama.ConsumerMessage)
	go consumePartition(consumer, *topicPtr, int32(*partitionPtr), messages, offsetArray)

	// create signals chan
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt)

	consumed := 0
ConsumerLoop:
	for {
		select {
		case msg := <-messages:

			schemaStruct := schemas.IdentifySchema(*topicPtr)
			var err error

			// Get schema from schema registry and use it to create avro consumer
			schema, err := schema.Get(*schemaRegistryPtr, *topicPtr)
			consumerAvro := &avro.Schema{
				Definition: schema,
			}

			// Unmarshal message value and assign it to schemaStruct
			if err = consumerAvro.Unmarshal(msg.Value, schemaStruct); err != nil {
				fmt.Println("Error unmarshalling avro:")
			}

			// create avro producer
			producerAvro := &avro.Schema{
				Definition: schema,
			}

			// Marshall schemaStruct that contains message value ready for republishing
			messageBytes, err := producerAvro.Marshal(schemaStruct)
			if err != nil {
				fmt.Println("Error Marshalling avro:")
			}

			// create producer message
			producerMessage := &producer.Message{
				Value: messageBytes,
				Topic: *topicPtr,
			}

			//create new producer
			p, err := producer.New(&producer.Config{Acks: &producer.WaitForAll, BrokerAddrs: []string{*brokerPtr}})
			if err != nil {
				os.Exit(1)
			}

			// republish message
			partition, offset, err := p.Send(producerMessage)
			if err != nil {
				fmt.Println("Error republishing message:")
			}
			fmt.Println("Message republished!", partition, offset)

			consumed++
		case <-signals:
			fmt.Println("break")
			break ConsumerLoop
		}
	}
}

// The offset slice is passed into method and is iterated over and each message
// related to the offset in the topic/partition is outputted into the 'out' chan
func consumePartition(consumer sarama.Consumer, topic string, partition int32, out chan *sarama.ConsumerMessage, offsetArray []int64) {
	for offset := range offsetArray {
		partitionConsumer, err := consumer.ConsumePartition(topic, partition, int64(offset))
		if err != nil {
			panic(err)
		}

		select {
		case msg := <-partitionConsumer.Messages():
			partitionConsumer.Close()
			out <- msg
		}
	}
}

// This creates the offset array depending on whether a range or a single value
// is entered as an argument to the tool
func createOffsetArray(offset string) []int64 {
	arraySize := make([]int64, 0)
	if strings.ContainsAny(offset, "-") {
		slice := strings.Split(offset, "-")
		minRange, err := strconv.ParseInt(slice[0], 10, 64)
		maxRange, err := strconv.ParseInt(slice[1], 10, 64)
		if err != nil {
			panic(err)
		}

		index := 0
		for value := minRange; value <= maxRange; value++ {
			arraySize = append(arraySize, value)
			index++
		}
	} else {
		value, err := strconv.ParseInt(offset, 10, 64)
		if err != nil {
			panic(err)
		}
		arraySize = append(arraySize, value)
	}
	return arraySize
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
	"github.com/spirit-contrib/inlet_http"
)

const (
	SPIRIT_NAME    = "inlet_http_api"
	METHOD_OPTIONS = "OPTIONS"
)

var (
	conf InletHTTPAPIConfig

	proxyAPI = make(map[string]bool)
)

func main() {

	httpAPISpirit := spirit.NewClassicSpirit(SPIRIT_NAME, "an http inlet with POST request", "1.0.0")
	httpAPIComponent := spirit.NewBaseComponent(SPIRIT_NAME)

	inletHTTP := inlet_http.NewInletHTTP()

	httpAPIComponent.RegisterHandler("callback", inletHTTP.CallBack)
	httpAPIComponent.RegisterHandler("error", inletHTTP.Error)

	funcStartInletHTTP := func() error {
		conf = LoadConfig("./conf/inlet_http_api.conf")

		graphProvider := NewAPIGraphProvider(API_HEADER, conf.Address, conf.Graphs)

		httpConf := inlet_http.Config{
			Address:    conf.HTTP.Address,
			Domain:     conf.HTTP.CookiesDomain,
			EnableStat: conf.HTTP.EnableStat,
		}

		inletHTTP.Option(inlet_http.SetHTTPConfig(httpConf),
			inlet_http.SetGraphProvider(graphProvider),
			inlet_http.SetResponseHandler(responseHandle),
			inlet_http.SetErrorResponseHandler(errorResponseHandler),
			inlet_http.SetRequestDecoder(requestDecoder),
			inlet_http.SetRequestPayloadHook(requestPayloadHook),
			inlet_http.SetTimeoutHeader(API_CALL_TIMEOUT))

		inletHTTP.Requester().SetMessageSenderFactory(httpAPISpirit.GetMessageSenderFactory())

		go inletHTTP.Run(conf.HTTP.PATH, func(r martini.Router) {
			r.Post("", inletHTTP.Handler)
			r.Options("", optionHandle)
		})

		return nil
	}

	httpAPISpirit.Hosting(httpAPIComponent).Build().Run(funcStartInletHTTP)
}

type APIResponse struct {
	Code           uint64      `json:"code"`
	ErrorId        string      `json:"error_id,omitempty"`
	ErrorNamespace string      `json:"error_namespace,omitempty"`
	Message        string      `json:"message"`
	Result         interface{} `json:"result"`
}

func requestDecoder(data []byte) (ret map[string]interface{}, err error) {
	str := strings.TrimSpace(string(data))
	if str != "" {
		ret = make(map[string]interface{})
		err = json.Unmarshal(data, &ret)
	}
	return
}

func requestPayloadHook(r *http.Request, apiName string, body []byte, payload *spirit.Payload) (err error) {
	if r.Header.Get(MULTI_CALL) == "1" {
		multiAPIReq := map[string]interface{}{}
		if e := json.Unmarshal(body, &multiAPIReq); e != nil {
			err = ERR_UNMARSHAL_MULTI_REQUEST_FAILED.New(errors.Params{"err": e, "api": apiName})
			return
		} else if reqContent, exist := multiAPIReq[apiName]; exist {
			payload.SetContent(reqContent)
		} else {
			err = ERR_MULTI_API_REQUEST_NOT_EXIST.New(errors.Params{"api": apiName})
			return
		}
	}

	if apiName == "" {
		err = ERR_API_NAME_IS_EMPTY.New()
		return
	}

	if proxyAPI != nil {
		if isProxy, _ := proxyAPI[apiName]; isProxy {
			newPayload := spirit.Payload{}

			if e := newPayload.UnSerialize(body); e != nil {
				err = ERR_PARSE_PROXY_PAYLOAD_FIALED.New(errors.Params{"api": apiName, "err": e})
				logs.Error(err)
				return
			} else {
				payload.CopyFrom(&newPayload)
			}
		}
	}

	payload.SetContext(conf.HTTP.APIHeader, apiName)

	return
}

func optionHandle(w http.ResponseWriter, r *http.Request) {
	if r.Method == METHOD_OPTIONS {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Write([]byte(""))
	}
}

func errorResponseHandler(err error, w http.ResponseWriter, r *http.Request) {
	//statusCode := http.StatusInternalServerError

	// if ERR_API_GRAPH_IS_NOT_EXIST.IsEqual(err) {
	// 	statusCode = http.StatusNotFound
	// } else if inlet_http.ERR_REQUEST_TIMEOUT.IsEqual(err) {
	// 	statusCode = http.StatusRequestTimeout
	// 	apiName := r.Header.Get(conf.HTTP.APIHeader)
	// 	err = ERR_API_REQUEST_TIMEOUT.New(errors.Params{"api": apiName})
	// }

	//for temp support client side to receive
	statusCode := http.StatusOK

	var resp APIResponse
	if errCode, ok := err.(errors.ErrCode); ok {
		resp = APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}
	} else {
		resp = APIResponse{
			Code:           500,
			ErrorId:        "",
			ErrorNamespace: INLET_HTTP_API_ERR_NS,
			Message:        err.Error(),
			Result:         nil,
		}
	}

	writeResponseWithStatusCode(&resp, w, r, statusCode)
}

func responseHandle(graphsResponse map[string]inlet_http.GraphResponse, w http.ResponseWriter, r *http.Request) {
	//TODO: improve handle logic
	//X-X-API-MULTI-CALL PROCESS

	multiResp := map[string]APIResponse{}
	for apiName, graphResponse := range graphsResponse {
		if graphResponse.Error != nil {
			if errCode, ok := graphResponse.Error.(errors.ErrCode); ok {
				multiResp[apiName] = APIResponse{
					Code:           errCode.Code(),
					ErrorId:        errCode.Id(),
					ErrorNamespace: errCode.Namespace(),
					Message:        errCode.Error(),
					Result:         nil,
				}
			} else {
				multiResp[apiName] = APIResponse{
					Code:           500,
					ErrorId:        "",
					ErrorNamespace: INLET_HTTP_API_ERR_NS,
					Message:        graphResponse.Error.Error(),
					Result:         nil,
				}
			}
		} else if graphResponse.RespPayload.IsCorrect() {
			multiResp[apiName] = APIResponse{
				Code:   graphResponse.RespPayload.Error().Code,
				Result: graphResponse.RespPayload.GetContent(),
			}
		} else {
			multiResp[apiName] = APIResponse{
				Code:           graphResponse.RespPayload.Error().Code,
				ErrorId:        graphResponse.RespPayload.Error().Id,
				ErrorNamespace: graphResponse.RespPayload.Error().Namespace,
				Message:        graphResponse.RespPayload.Error().Message,
				Result:         nil,
			}
		}
	}

	if r.Header.Get(MULTI_CALL) == "1" {
		resp := APIResponse{
			Code:   0,
			Result: multiResp,
		}
		writeResponse(&resp, w, r)
		return
	}

	lenGraphsResponse := len(graphsResponse)

	//response count is did not equal 1
	if lenGraphsResponse != 1 {
		err := ERR_PAYLOAD_RESPONSE_COUNT_NOT_MATCH.New()
		errCode, _ := err.(errors.ErrCode)
		resp := APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}

		writeResponse(&resp, w, r)
		return
	}

	for _, resp := range multiResp {
		writeResponse(&resp, w, r)
		return
	}
}

func writeResponse(v interface{}, w http.ResponseWriter, r *http.Request) {
	writeResponseWithStatusCode(v, w, r, http.StatusOK)
}

func writeResponseWithStatusCode(v interface{}, w http.ResponseWriter, r *http.Request, code int) {
	if data, e := json.Marshal(v); e != nil {
		err := ERR_MARSHAL_STRUCT_ERROR.New(errors.Params{"err": e})
		logs.Error(err)
		if _, ok := v.(error); !ok {
			writeResponseWithStatusCode(&err, w, r, code)
		}
	} else {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(code)
		w.Write(data)
	}
}

func writeAccessHeaders(w http.ResponseWriter, r *http.Request) {
	refer := r.Referer()
	if refer == "" {
		refer = r.Header.Get("Origin")
	}

	if refProtocol, refDomain, isAllowd := conf.HTTP.ParseOrigin(refer); isAllowd {
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		origin := refProtocol + "://" + refDomain
		if origin == "://" ||
			refProtocol == "chrome-extension" { //issue of post man, chrome limit.
			origin = "*"
		}
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST")
	w.Header().Set("Access-Control-Allow-Headers", conf.HTTP.allowHeaders())
}

func writeBasicHeaders(w http.ResponseWriter, r *http.Request) {
	for key, value := range conf.HTTP.responseHeaders {
		w.Header().Set(key, value)
	}
}
<commit_msg>update spirit package changes<commit_after>package main

import (
	"encoding/json"
	"net/http"
	"strings"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
	"github.com/spirit-contrib/inlet_http"
)

const (
	SPIRIT_NAME    = "inlet_http_api"
	METHOD_OPTIONS = "OPTIONS"
)

var (
	conf InletHTTPAPIConfig

	proxyAPI = make(map[string]bool)
)

func main() {

	httpAPISpirit := spirit.NewClassicSpirit(SPIRIT_NAME, "an http inlet with POST request", "1.0.0")
	httpAPIComponent := spirit.NewBaseComponent(SPIRIT_NAME)

	inletHTTP := inlet_http.NewInletHTTP()

	httpAPIComponent.RegisterHandler("callback", inletHTTP.CallBack)
	httpAPIComponent.RegisterHandler("error", inletHTTP.Error)

	funcStartInletHTTP := func(configFile string) error {
		conf = LoadConfig(configFile)

		graphProvider := NewAPIGraphProvider(API_HEADER, conf.Address, conf.Graphs)

		httpConf := inlet_http.Config{
			Address:    conf.HTTP.Address,
			Domain:     conf.HTTP.CookiesDomain,
			EnableStat: conf.HTTP.EnableStat,
		}

		inletHTTP.Option(inlet_http.SetHTTPConfig(httpConf),
			inlet_http.SetGraphProvider(graphProvider),
			inlet_http.SetResponseHandler(responseHandle),
			inlet_http.SetErrorResponseHandler(errorResponseHandler),
			inlet_http.SetRequestDecoder(requestDecoder),
			inlet_http.SetRequestPayloadHook(requestPayloadHook),
			inlet_http.SetTimeoutHeader(API_CALL_TIMEOUT))

		inletHTTP.Requester().SetMessageSenderFactory(httpAPISpirit.GetMessageSenderFactory())

		go inletHTTP.Run(conf.HTTP.PATH, func(r martini.Router) {
			r.Post("", inletHTTP.Handler)
			r.Options("", optionHandle)
		})

		return nil
	}

	httpAPISpirit.Hosting(httpAPIComponent).Build().Run(funcStartInletHTTP)
}

type APIResponse struct {
	Code           uint64      `json:"code"`
	ErrorId        string      `json:"error_id,omitempty"`
	ErrorNamespace string      `json:"error_namespace,omitempty"`
	Message        string      `json:"message"`
	Result         interface{} `json:"result"`
}

func requestDecoder(data []byte) (ret map[string]interface{}, err error) {
	str := strings.TrimSpace(string(data))
	if str != "" {
		ret = make(map[string]interface{})
		err = json.Unmarshal(data, &ret)
	}
	return
}

func requestPayloadHook(r *http.Request, apiName string, body []byte, payload *spirit.Payload) (err error) {
	if r.Header.Get(MULTI_CALL) == "1" {
		multiAPIReq := map[string]interface{}{}
		if e := json.Unmarshal(body, &multiAPIReq); e != nil {
			err = ERR_UNMARSHAL_MULTI_REQUEST_FAILED.New(errors.Params{"err": e, "api": apiName})
			return
		} else if reqContent, exist := multiAPIReq[apiName]; exist {
			payload.SetContent(reqContent)
		} else {
			err = ERR_MULTI_API_REQUEST_NOT_EXIST.New(errors.Params{"api": apiName})
			return
		}
	}

	if apiName == "" {
		err = ERR_API_NAME_IS_EMPTY.New()
		return
	}

	if proxyAPI != nil {
		if isProxy, _ := proxyAPI[apiName]; isProxy {
			newPayload := spirit.Payload{}

			if e := newPayload.UnSerialize(body); e != nil {
				err = ERR_PARSE_PROXY_PAYLOAD_FIALED.New(errors.Params{"api": apiName, "err": e})
				logs.Error(err)
				return
			} else {
				payload.CopyFrom(&newPayload)
			}
		}
	}

	payload.SetContext(conf.HTTP.APIHeader, apiName)

	return
}

func optionHandle(w http.ResponseWriter, r *http.Request) {
	if r.Method == METHOD_OPTIONS {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Write([]byte(""))
	}
}

func errorResponseHandler(err error, w http.ResponseWriter, r *http.Request) {
	//statusCode := http.StatusInternalServerError

	// if ERR_API_GRAPH_IS_NOT_EXIST.IsEqual(err) {
	// 	statusCode = http.StatusNotFound
	// } else if inlet_http.ERR_REQUEST_TIMEOUT.IsEqual(err) {
	// 	statusCode = http.StatusRequestTimeout
	// 	apiName := r.Header.Get(conf.HTTP.APIHeader)
	// 	err = ERR_API_REQUEST_TIMEOUT.New(errors.Params{"api": apiName})
	// }

	//for temp support client side to receive
	statusCode := http.StatusOK

	var resp APIResponse
	if errCode, ok := err.(errors.ErrCode); ok {
		resp = APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}
	} else {
		resp = APIResponse{
			Code:           500,
			ErrorId:        "",
			ErrorNamespace: INLET_HTTP_API_ERR_NS,
			Message:        err.Error(),
			Result:         nil,
		}
	}

	writeResponseWithStatusCode(&resp, w, r, statusCode)
}

func responseHandle(graphsResponse map[string]inlet_http.GraphResponse, w http.ResponseWriter, r *http.Request) {
	//TODO: improve handle logic
	//X-X-API-MULTI-CALL PROCESS

	multiResp := map[string]APIResponse{}
	for apiName, graphResponse := range graphsResponse {
		if graphResponse.Error != nil {
			if errCode, ok := graphResponse.Error.(errors.ErrCode); ok {
				multiResp[apiName] = APIResponse{
					Code:           errCode.Code(),
					ErrorId:        errCode.Id(),
					ErrorNamespace: errCode.Namespace(),
					Message:        errCode.Error(),
					Result:         nil,
				}
			} else {
				multiResp[apiName] = APIResponse{
					Code:           500,
					ErrorId:        "",
					ErrorNamespace: INLET_HTTP_API_ERR_NS,
					Message:        graphResponse.Error.Error(),
					Result:         nil,
				}
			}
		} else if graphResponse.RespPayload.IsCorrect() {
			multiResp[apiName] = APIResponse{
				Code:   graphResponse.RespPayload.Error().Code,
				Result: graphResponse.RespPayload.GetContent(),
			}
		} else {
			multiResp[apiName] = APIResponse{
				Code:           graphResponse.RespPayload.Error().Code,
				ErrorId:        graphResponse.RespPayload.Error().Id,
				ErrorNamespace: graphResponse.RespPayload.Error().Namespace,
				Message:        graphResponse.RespPayload.Error().Message,
				Result:         nil,
			}
		}
	}

	if r.Header.Get(MULTI_CALL) == "1" {
		resp := APIResponse{
			Code:   0,
			Result: multiResp,
		}
		writeResponse(&resp, w, r)
		return
	}

	lenGraphsResponse := len(graphsResponse)

	//response count is did not equal 1
	if lenGraphsResponse != 1 {
		err := ERR_PAYLOAD_RESPONSE_COUNT_NOT_MATCH.New()
		errCode, _ := err.(errors.ErrCode)
		resp := APIResponse{
			Code:           errCode.Code(),
			ErrorId:        errCode.Id(),
			ErrorNamespace: errCode.Namespace(),
			Message:        errCode.Error(),
			Result:         nil,
		}

		writeResponse(&resp, w, r)
		return
	}

	for _, resp := range multiResp {
		writeResponse(&resp, w, r)
		return
	}
}

func writeResponse(v interface{}, w http.ResponseWriter, r *http.Request) {
	writeResponseWithStatusCode(v, w, r, http.StatusOK)
}

func writeResponseWithStatusCode(v interface{}, w http.ResponseWriter, r *http.Request, code int) {
	if data, e := json.Marshal(v); e != nil {
		err := ERR_MARSHAL_STRUCT_ERROR.New(errors.Params{"err": e})
		logs.Error(err)
		if _, ok := v.(error); !ok {
			writeResponseWithStatusCode(&err, w, r, code)
		}
	} else {
		writeAccessHeaders(w, r)
		writeBasicHeaders(w, r)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(code)
		w.Write(data)
	}
}

func writeAccessHeaders(w http.ResponseWriter, r *http.Request) {
	refer := r.Referer()
	if refer == "" {
		refer = r.Header.Get("Origin")
	}

	if refProtocol, refDomain, isAllowd := conf.HTTP.ParseOrigin(refer); isAllowd {
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		origin := refProtocol + "://" + refDomain
		if origin == "://" ||
			refProtocol == "chrome-extension" { //issue of post man, chrome limit.
			origin = "*"
		}
		w.Header().Set("Access-Control-Allow-Origin", origin)
	}

	w.Header().Set("Access-Control-Allow-Methods", "POST")
	w.Header().Set("Access-Control-Allow-Headers", conf.HTTP.allowHeaders())
}

func writeBasicHeaders(w http.ResponseWriter, r *http.Request) {
	for key, value := range conf.HTTP.responseHeaders {
		w.Header().Set(key, value)
	}
}
<|endoftext|>