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

package dictd

import (
	"strconv"
	"time"
)

/* socket.go - transport-aware interface for the dict protocol.
 *
 * In particular, this file contains a net/textproto based interface
 * to the rest of the go-dictd project, as well as parsing code for
 * the incoming requests. */

import (
	"errors"
	"log"
	"net"
	"net/textproto"
	"strings"
)

/* Session contains state data that lasts throughout the connection. */
type Session struct {
	MsgId      string
	Client     string
	Connection *textproto.Conn
	DictServer *Server
	Options    map[string]bool
}

/* Take an incoming line `line`, and split it according to the command
 * line spec in the RFC. */
func tokenizeLine(line string) ([]string, error) {
	var tokens []string
	chunks := strings.Split(line, " ")

	for _, v := range chunks {
		el := strings.Trim(v, " \t\n\r")
		if el != "" {
			tokens = append(tokens, el)
		}
	}

	if len(tokens) == 0 {
		return nil, errors.New("Busted command")
	}

	return tokens, nil
}

/* Parse an incoming line, and return a `dict.Command` suitable for
 * passing to internal (or external) handlers. */
func parseLine(line string) (*Command, error) {
	tokens, err := tokenizeLine(line)
	if err != nil {
		return nil, err
	}
	command := Command{
		Command: strings.ToUpper(tokens[0]),
		Params:  tokens[1:],
	}
	return &command, nil
}

/* Given a dict.Session and a dict.Command, route the command to the proper
 * handler, and dispatch the command. */
func handleCommand(session *Session, command *Command) {
	log.Printf("Incomming command from %s: %s", session.MsgId, command.Command)
	handler := session.DictServer.GetHandler(command)
	if handler == nil {
		unknownCommandHandler(session, *command)
	} else {
		handler(session, *command)
	}
}

/* Helper for commands to write out a text block */
func WriteTextBlock(session *Session, stream string) {
	if session.Options["MIME"] {
		session.Connection.Writer.PrintfLine(
			"Content-type: text/plain; charset=utf-8\n" +
				"Content-transfer-encoding: 8bit\n",
		)

	}

	writer := session.Connection.Writer.DotWriter()
	writer.Write([]byte(stream))
	writer.Close()
}

/* Helper for commands to write out a code line */
func WriteCode(session *Session, code int, message string) {
	session.Connection.Writer.PrintfLine("%d %s", code, message)
}

/* Helper to generate a "unique" Message ID for the client to use.
 *
 * It's not super vital, since we don't support AUTH yet. */
func generateMsgId(server *Server) string {
	return strconv.FormatInt(time.Now().UnixNano(), 10) +
		".0@" +
		server.Name
}

/* Given a `dict.Server` and a `net.Conn`, do a bringup, and run the
 * `ReadLine` loop, dispatching commands to the correct internals. */
func Handle(server *Server, conn net.Conn) {
	proto := textproto.NewConn(conn)

	session := Session{
		MsgId:      generateMsgId(server),
		Client:     "",
		Connection: proto,
		DictServer: server,
		Options:    map[string]bool{},
	}

	session.Options["MIME"] = false /* Requiredish */

	/* Right, so we've got a connection, let's send the 220 and let the
	 * client know we're happy. */
	handshakeHandler(&session)

	for {
		line, err := proto.ReadLine()
		if err != nil {
			log.Printf("Error: %s", err)
			/* Usually an EOF */
			return
		}
		command, err := parseLine(line)
		if err != nil {
			log.Printf("Error: %s", err)
			continue
		}
		handleCommand(&session, command)
	}
}
<commit_msg>Fix up imports.<commit_after>/**
 * Copyright (c) Paul R. Tagliamonte, 2015
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE. */

package dictd

/* socket.go - transport-aware interface for the dict protocol.
 *
 * In particular, this file contains a net/textproto based interface
 * to the rest of the go-dictd project, as well as parsing code for
 * the incoming requests. */

import (
	"errors"
	"log"
	"net"
	"net/textproto"
	"strconv"
	"strings"
	"time"
)

/* Session contains state data that lasts throughout the connection. */
type Session struct {
	MsgId      string
	Client     string
	Connection *textproto.Conn
	DictServer *Server
	Options    map[string]bool
}

/* Take an incoming line `line`, and split it according to the command
 * line spec in the RFC. */
func tokenizeLine(line string) ([]string, error) {
	var tokens []string
	chunks := strings.Split(line, " ")

	for _, v := range chunks {
		el := strings.Trim(v, " \t\n\r")
		if el != "" {
			tokens = append(tokens, el)
		}
	}

	if len(tokens) == 0 {
		return nil, errors.New("Busted command")
	}

	return tokens, nil
}

/* Parse an incoming line, and return a `dict.Command` suitable for
 * passing to internal (or external) handlers. */
func parseLine(line string) (*Command, error) {
	tokens, err := tokenizeLine(line)
	if err != nil {
		return nil, err
	}
	command := Command{
		Command: strings.ToUpper(tokens[0]),
		Params:  tokens[1:],
	}
	return &command, nil
}

/* Given a dict.Session and a dict.Command, route the command to the proper
 * handler, and dispatch the command. */
func handleCommand(session *Session, command *Command) {
	log.Printf("Incomming command from %s: %s", session.MsgId, command.Command)
	handler := session.DictServer.GetHandler(command)
	if handler == nil {
		unknownCommandHandler(session, *command)
	} else {
		handler(session, *command)
	}
}

/* Helper for commands to write out a text block */
func WriteTextBlock(session *Session, stream string) {
	if session.Options["MIME"] {
		session.Connection.Writer.PrintfLine(
			"Content-type: text/plain; charset=utf-8\n" +
				"Content-transfer-encoding: 8bit\n",
		)

	}

	writer := session.Connection.Writer.DotWriter()
	writer.Write([]byte(stream))
	writer.Close()
}

/* Helper for commands to write out a code line */
func WriteCode(session *Session, code int, message string) {
	session.Connection.Writer.PrintfLine("%d %s", code, message)
}

/* Helper to generate a "unique" Message ID for the client to use.
 *
 * It's not super vital, since we don't support AUTH yet. */
func generateMsgId(server *Server) string {
	return strconv.FormatInt(time.Now().UnixNano(), 10) +
		".0@" +
		server.Name
}

/* Given a `dict.Server` and a `net.Conn`, do a bringup, and run the
 * `ReadLine` loop, dispatching commands to the correct internals. */
func Handle(server *Server, conn net.Conn) {
	proto := textproto.NewConn(conn)

	session := Session{
		MsgId:      generateMsgId(server),
		Client:     "",
		Connection: proto,
		DictServer: server,
		Options:    map[string]bool{},
	}

	session.Options["MIME"] = false /* Requiredish */

	/* Right, so we've got a connection, let's send the 220 and let the
	 * client know we're happy. */
	handshakeHandler(&session)

	for {
		line, err := proto.ReadLine()
		if err != nil {
			log.Printf("Error: %s", err)
			/* Usually an EOF */
			return
		}
		command, err := parseLine(line)
		if err != nil {
			log.Printf("Error: %s", err)
			continue
		}
		handleCommand(&session, command)
	}
}
<|endoftext|>


<commit_before>package spec

import "github.com/opencontainers/runtime-spec/specs-go"

var (
	AnyContainerDevices = []specs.LinuxDeviceCgroup{
		// runc allows these
		{Access: "m", Type: "c", Major: deviceWildcard(), Minor: deviceWildcard(), Allow: true},
		{Access: "m", Type: "b", Major: deviceWildcard(), Minor: deviceWildcard(), Allow: true},

		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(3), Allow: true},          // /dev/null
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(8), Allow: true},          // /dev/random
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(7), Allow: true},          // /dev/full
		{Access: "rwm", Type: "c", Major: intRef(5), Minor: intRef(0), Allow: true},          // /dev/tty
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(5), Allow: true},          // /dev/zero
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(9), Allow: true},          // /dev/urandom
		{Access: "rwm", Type: "c", Major: intRef(5), Minor: intRef(1), Allow: true},          // /dev/console
		{Access: "rwm", Type: "c", Major: intRef(136), Minor: deviceWildcard(), Allow: true}, // /dev/pts/*
		{Access: "rwm", Type: "c", Major: intRef(5), Minor: intRef(2), Allow: true},          // /dev/ptmx
		{Access: "rwm", Type: "c", Major: intRef(10), Minor: intRef(200), Allow: true},       // /dev/net/tun

		// we allow this
		{Access: "rwm", Type: "c", Major: intRef(10), Minor: intRef(229), Allow: true}, // /dev/fuse
	}

	PrivilegedOnlyDevices = []specs.LinuxDeviceCgroup{
		{Allow: false, Access: "rwm"},
	}
)

func intRef(i int64) *int64  { return &i }
func deviceWildcard() *int64 { return intRef(-1) }
<commit_msg>containerd does not grant access to /dev/console<commit_after>package spec

import "github.com/opencontainers/runtime-spec/specs-go"

var (
	AnyContainerDevices = []specs.LinuxDeviceCgroup{
		// runc allows these
		{Access: "m", Type: "c", Major: deviceWildcard(), Minor: deviceWildcard(), Allow: true},
		{Access: "m", Type: "b", Major: deviceWildcard(), Minor: deviceWildcard(), Allow: true},

		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(3), Allow: true},          // /dev/null
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(8), Allow: true},          // /dev/random
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(7), Allow: true},          // /dev/full
		{Access: "rwm", Type: "c", Major: intRef(5), Minor: intRef(0), Allow: true},          // /dev/tty
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(5), Allow: true},          // /dev/zero
		{Access: "rwm", Type: "c", Major: intRef(1), Minor: intRef(9), Allow: true},          // /dev/urandom
		{Access: "rwm", Type: "c", Major: intRef(136), Minor: deviceWildcard(), Allow: true}, // /dev/pts/*
		{Access: "rwm", Type: "c", Major: intRef(5), Minor: intRef(2), Allow: true},          // /dev/ptmx
		{Access: "rwm", Type: "c", Major: intRef(10), Minor: intRef(200), Allow: true},       // /dev/net/tun

		// we allow this
		{Access: "rwm", Type: "c", Major: intRef(10), Minor: intRef(229), Allow: true}, // /dev/fuse
	}

	PrivilegedOnlyDevices = []specs.LinuxDeviceCgroup{
		{Allow: false, Access: "rwm"},
	}
)

func intRef(i int64) *int64  { return &i }
func deviceWildcard() *int64 { return intRef(-1) }
<|endoftext|>


<commit_before>package google

import (
	"errors"
	"net/http"
	"net/url"

	"fmt"

	"strings"

	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/Seklfreak/Robyul2/helpers"
)

// based on https://github.com/devsnek/googlebot/blob/rewrite/src/util/google.js
const (
	UserAgent = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) Gecko/20100101 Firefox/53."
	BaseUrl   = "https://www.google.com"
	SearchUrl = BaseUrl + "/search"
)

type linkResult struct {
	Link  string
	Title string
	Text  string
}

type imageResult struct {
	Title string
	URL   string
	Link  string
}

func getSearchQueries(queryText string, nsfw, friendly bool) (query string) {
	safeText := "on"
	if nsfw {
		safeText = "off"
	}

	parsedUrl, err := url.Parse("https://google.com")
	if err != nil {
		panic(err)
	}
	queryBuilder := parsedUrl.Query()
	queryBuilder.Add("q", queryText)
	queryBuilder.Add("safe", safeText)

	if !friendly {
		queryBuilder.Add("lr", "lang_en")
		queryBuilder.Add("hl", "en")
	}

	return queryBuilder.Encode()
}

func getImageSearchQuries(queryText string, nsfw, friendly bool) (query string) {
	safeText := "active"
	if nsfw {
		safeText = "disabled"
	}

	parsedUrl, err := url.Parse("https://google.com")
	if err != nil {
		panic(err)
	}
	queryBuilder := parsedUrl.Query()
	queryBuilder.Add("q", queryText)
	queryBuilder.Add("safe", safeText)
	queryBuilder.Add("ie", "ISO-8859-1")
	queryBuilder.Add("source", "hp")
	queryBuilder.Add("tbm", "isch")
	queryBuilder.Add("gbv", "1")
	queryBuilder.Add("gs_l", "img")

	if !friendly {
		queryBuilder.Add("hl", "en")
	}

	return queryBuilder.Encode()
}

func search(query string, nsfw bool, transport *http.Transport) (results []linkResult, err error) {
	client := &http.Client{
		Timeout: time.Duration(10 * time.Second),
	}

	if transport != nil {
		client.Transport = transport
	}

	request, err := http.NewRequest("GET", SearchUrl+"?"+getSearchQueries(query, nsfw, false), nil)
	if err != nil {
		return results, err
	}

	request.Header.Set("User-Agent", UserAgent)

	response, err := client.Do(request)
	if err != nil {
		if strings.Contains(err.Error(), "http.httpError") ||
			strings.Contains(err.Error(), "url.Error") ||
			strings.Contains(err.Error(), "Timeout") {
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return search(query, nsfw, &proxy)
		}
		return results, err
	}

	if response.StatusCode != 200 {
		if response.StatusCode == 503 { // too many requests
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return search(query, nsfw, &proxy)
		}
		return results, errors.New(fmt.Sprintf("unexpected status code: %d", response.StatusCode))
	}

	doc, err := goquery.NewDocumentFromResponse(response)
	if err != nil {
		return results, err
	}

	doc.Find("div[class=rc]").Each(func(_ int, selection *goquery.Selection) {
		link := selection.Find("h3[class=r]")
		text := selection.Find("span[class=st]")
		result := linkResult{
			Link:  link.Children().First().AttrOr("href", ""),
			Title: link.Children().First().Text(),
			Text:  text.Text(),
		}
		if result.Link != "" && result.Title != "" {
			results = append(results, result)
		}
	})

	if len(results) <= 0 {
		return results, errors.New("no search results")
	}

	return results, nil
}

func imageSearch(query string, nsfw bool, transport *http.Transport) (results []imageResult, err error) {
	client := &http.Client{
		Timeout: time.Duration(10 * time.Second),
	}

	if transport != nil {
		client.Transport = transport
	}

	request, err := http.NewRequest("GET", SearchUrl+"?"+getImageSearchQuries(query, nsfw, false), nil)
	if err != nil {
		return results, err
	}

	request.Header.Set("User-Agent", UserAgent)

	response, err := client.Do(request)
	if err != nil {
		if strings.Contains(err.Error(), "http.httpError") || strings.Contains(err.Error(), "url.Error") {
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return imageSearch(query, nsfw, &proxy)
		}
		return results, err
	}

	if response.StatusCode != 200 {
		if response.StatusCode == 503 { // too many requests
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return imageSearch(query, nsfw, &proxy)
		}
		return results, errors.New(fmt.Sprintf("unexpected status code: %d", response.StatusCode))
	}

	doc, err := goquery.NewDocumentFromResponse(response)
	if err != nil {
		return results, err
	}

	doc.Find("td a").Each(func(_ int, selection *goquery.Selection) {
		image := selection.Find("img")
		result := imageResult{
			URL:   image.AttrOr("src", ""),
			Link:  selection.AttrOr("href", ""),
			Title: image.AttrOr("alt", "Image result"),
		}
		if strings.HasPrefix(result.Link, "/url?") {
			result.Link = BaseUrl + result.Link
		}

		if result.URL != "" && result.Link != "" {
			results = append(results, result)
		}
	})

	if len(results) <= 0 {
		return results, errors.New("no search results")
	}

	return results, nil
}
<commit_msg>[google] more error catching 💣<commit_after>package google

import (
	"errors"
	"net/http"
	"net/url"

	"fmt"

	"strings"

	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/Seklfreak/Robyul2/helpers"
)

// based on https://github.com/devsnek/googlebot/blob/rewrite/src/util/google.js
const (
	UserAgent = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) Gecko/20100101 Firefox/53."
	BaseUrl   = "https://www.google.com"
	SearchUrl = BaseUrl + "/search"
)

type linkResult struct {
	Link  string
	Title string
	Text  string
}

type imageResult struct {
	Title string
	URL   string
	Link  string
}

func getSearchQueries(queryText string, nsfw, friendly bool) (query string) {
	safeText := "on"
	if nsfw {
		safeText = "off"
	}

	parsedUrl, err := url.Parse("https://google.com")
	if err != nil {
		panic(err)
	}
	queryBuilder := parsedUrl.Query()
	queryBuilder.Add("q", queryText)
	queryBuilder.Add("safe", safeText)

	if !friendly {
		queryBuilder.Add("lr", "lang_en")
		queryBuilder.Add("hl", "en")
	}

	return queryBuilder.Encode()
}

func getImageSearchQuries(queryText string, nsfw, friendly bool) (query string) {
	safeText := "active"
	if nsfw {
		safeText = "disabled"
	}

	parsedUrl, err := url.Parse("https://google.com")
	if err != nil {
		panic(err)
	}
	queryBuilder := parsedUrl.Query()
	queryBuilder.Add("q", queryText)
	queryBuilder.Add("safe", safeText)
	queryBuilder.Add("ie", "ISO-8859-1")
	queryBuilder.Add("source", "hp")
	queryBuilder.Add("tbm", "isch")
	queryBuilder.Add("gbv", "1")
	queryBuilder.Add("gs_l", "img")

	if !friendly {
		queryBuilder.Add("hl", "en")
	}

	return queryBuilder.Encode()
}

func search(query string, nsfw bool, transport *http.Transport) (results []linkResult, err error) {
	client := &http.Client{
		Timeout: time.Duration(10 * time.Second),
	}

	if transport != nil {
		client.Transport = transport
	}

	request, err := http.NewRequest("GET", SearchUrl+"?"+getSearchQueries(query, nsfw, false), nil)
	if err != nil {
		return results, err
	}

	request.Header.Set("User-Agent", UserAgent)

	response, err := client.Do(request)
	if err != nil {
		if strings.Contains(err.Error(), "http.httpError") ||
			strings.Contains(err.Error(), "url.Error") ||
			strings.Contains(err.Error(), "Timeout") ||
			strings.Contains(err.Error(), "net.OpError") {
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return search(query, nsfw, &proxy)
		}
		return results, err
	}

	if response.StatusCode != 200 {
		if response.StatusCode == 503 { // too many requests
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return search(query, nsfw, &proxy)
		}
		return results, errors.New(fmt.Sprintf("unexpected status code: %d", response.StatusCode))
	}

	doc, err := goquery.NewDocumentFromResponse(response)
	if err != nil {
		return results, err
	}

	doc.Find("div[class=rc]").Each(func(_ int, selection *goquery.Selection) {
		link := selection.Find("h3[class=r]")
		text := selection.Find("span[class=st]")
		result := linkResult{
			Link:  link.Children().First().AttrOr("href", ""),
			Title: link.Children().First().Text(),
			Text:  text.Text(),
		}
		if result.Link != "" && result.Title != "" {
			results = append(results, result)
		}
	})

	if len(results) <= 0 {
		return results, errors.New("no search results")
	}

	return results, nil
}

func imageSearch(query string, nsfw bool, transport *http.Transport) (results []imageResult, err error) {
	client := &http.Client{
		Timeout: time.Duration(10 * time.Second),
	}

	if transport != nil {
		client.Transport = transport
	}

	request, err := http.NewRequest("GET", SearchUrl+"?"+getImageSearchQuries(query, nsfw, false), nil)
	if err != nil {
		return results, err
	}

	request.Header.Set("User-Agent", UserAgent)

	response, err := client.Do(request)
	if err != nil {
		if strings.Contains(err.Error(), "http.httpError") ||
			strings.Contains(err.Error(), "url.Error") ||
			strings.Contains(err.Error(), "Timeout") ||
			strings.Contains(err.Error(), "net.OpError") {
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return imageSearch(query, nsfw, &proxy)
		}
		return results, err
	}

	if response.StatusCode != 200 {
		if response.StatusCode == 503 { // too many requests
			// try with proxy
			proxy, err := helpers.GetRandomProxy()
			if err != nil {
				return results, err
			}
			return imageSearch(query, nsfw, &proxy)
		}
		return results, errors.New(fmt.Sprintf("unexpected status code: %d", response.StatusCode))
	}

	doc, err := goquery.NewDocumentFromResponse(response)
	if err != nil {
		return results, err
	}

	doc.Find("td a").Each(func(_ int, selection *goquery.Selection) {
		image := selection.Find("img")
		result := imageResult{
			URL:   image.AttrOr("src", ""),
			Link:  selection.AttrOr("href", ""),
			Title: image.AttrOr("alt", "Image result"),
		}
		if strings.HasPrefix(result.Link, "/url?") {
			result.Link = BaseUrl + result.Link
		}

		if result.URL != "" && result.Link != "" {
			results = append(results, result)
		}
	})

	if len(results) <= 0 {
		return results, errors.New("no search results")
	}

	return results, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package workers_test

import (
	"github.com/juju/errors"
	gitjujutesting "github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/testing"
	"github.com/juju/juju/workload"
	"github.com/juju/juju/workload/context"
	"github.com/juju/juju/workload/workers"
)

type eventHandlerSuite struct {
	testing.BaseSuite

	stub      *gitjujutesting.Stub
	apiClient *stubAPIClient
}

var _ = gc.Suite(&eventHandlerSuite{})

func (s *eventHandlerSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)

	s.stub = &gitjujutesting.Stub{}
	s.apiClient = &stubAPIClient{stub: s.stub}
}

func (s *eventHandlerSuite) handler(events []workload.Event, apiClient context.APIClient, runner workers.Runner) error {
	s.stub.AddCall("handler", events, apiClient, runner)
	if err := s.stub.NextErr(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (s *eventHandlerSuite) checkUnhandled(c *gc.C, eh *workers.EventHandlers, expected ...[]workload.Event) {
	eventsChan, _, _, _ := workers.ExposeEventHandlers(eh)

	var unhandled [][]workload.Event
	for events := range eventsChan {
		unhandled = append(unhandled, events)
	}
	c.Check(unhandled, jc.DeepEquals, expected)
}

func (s *eventHandlerSuite) checkRegistered(c *gc.C, eh *workers.EventHandlers, expected ...string) {
	_, handlers, _, _ := workers.ExposeEventHandlers(eh)
	for _, handler := range handlers {
		err := handler(nil, s.apiClient, nil)
		c.Assert(err, jc.ErrorIsNil)
	}
	c.Check(s.stub.Calls(), gc.HasLen, len(expected))
	s.stub.CheckCallNames(c, expected...)
}

func (s *eventHandlerSuite) TestNewEventHandlers(c *gc.C) {
	eh := workers.NewEventHandlers()
	c.Assert(eh, gc.NotNil)
	eh.Close()

	s.checkUnhandled(c, eh)
	s.checkRegistered(c, eh)
	_, _, apiClient, runner := workers.ExposeEventHandlers(eh)
	c.Check(apiClient, gc.IsNil)
	c.Check(runner, gc.IsNil)
}

func (s *eventHandlerSuite) TestRegisterHandler(c *gc.C) {
	eh := workers.NewEventHandlers()
	defer eh.Close()
	eh.RegisterHandler(s.handler)

	s.checkRegistered(c, eh, "handler")
}

func (s *eventHandlerSuite) TestAddEventsOkay(c *gc.C) {
	events := []workload.Event{{
		Kind: workload.EventKindTracked,
		ID:   "spam/eggs",
	}}
	eh := workers.NewEventHandlers()
	eh.Reset(s.apiClient)
	go func() {
		eh.AddEvents(events...)
		eh.Close()
	}()

	s.checkUnhandled(c, eh, events)
}

func (s *eventHandlerSuite) TestAddEventsEmpty(c *gc.C) {
	eh := workers.NewEventHandlers()
	eh.Reset(s.apiClient)
	go func() {
		eh.AddEvents()
		eh.Close()
	}()

	s.checkUnhandled(c, eh)
}

func (s *eventHandlerSuite) TestStartEngine(c *gc.C) {
	events := []workload.Event{{
		Kind: workload.EventKindTracked,
		ID:   "spam/eggs",
	}}

	eh := workers.NewEventHandlers()
	eh.Reset(s.apiClient)
	eh.RegisterHandler(s.handler)
	engine, err := eh.StartEngine()
	c.Assert(err, jc.ErrorIsNil)

	eh.AddEvents(events...)

	engine.Kill()
	err = engine.Wait()
	c.Assert(err, jc.ErrorIsNil)
	eh.Close()

	s.checkUnhandled(c, eh)
	s.stub.CheckCallNames(c, "List", "handler")
	c.Check(s.stub.Calls()[1].Args[0], gc.DeepEquals, events)
	c.Check(s.stub.Calls()[1].Args[1], gc.DeepEquals, s.apiClient)
	// TODO(ericsnow) Check the runner.
}

type stubAPIClient struct {
	context.APIClient
	stub *gitjujutesting.Stub
}

func (c *stubAPIClient) List(ids ...string) ([]workload.Info, error) {
	c.stub.AddCall("List", ids)
	if err := c.stub.NextErr(); err != nil {
		return nil, errors.Trace(err)
	}

	return nil, nil
}
<commit_msg>Add TestReset.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package workers_test

import (
	"github.com/juju/errors"
	gitjujutesting "github.com/juju/testing"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"

	"github.com/juju/juju/testing"
	"github.com/juju/juju/workload"
	"github.com/juju/juju/workload/context"
	"github.com/juju/juju/workload/workers"
)

type eventHandlerSuite struct {
	testing.BaseSuite

	stub      *gitjujutesting.Stub
	apiClient *stubAPIClient
}

var _ = gc.Suite(&eventHandlerSuite{})

func (s *eventHandlerSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)

	s.stub = &gitjujutesting.Stub{}
	s.apiClient = &stubAPIClient{stub: s.stub}
}

func (s *eventHandlerSuite) handler(events []workload.Event, apiClient context.APIClient, runner workers.Runner) error {
	s.stub.AddCall("handler", events, apiClient, runner)
	if err := s.stub.NextErr(); err != nil {
		return errors.Trace(err)
	}

	return nil
}

func (s *eventHandlerSuite) checkUnhandled(c *gc.C, eh *workers.EventHandlers, expected ...[]workload.Event) {
	eventsChan, _, _, _ := workers.ExposeEventHandlers(eh)

	var unhandled [][]workload.Event
	for events := range eventsChan {
		unhandled = append(unhandled, events)
	}
	c.Check(unhandled, jc.DeepEquals, expected)
}

func (s *eventHandlerSuite) checkRegistered(c *gc.C, eh *workers.EventHandlers, expected ...string) {
	_, handlers, _, _ := workers.ExposeEventHandlers(eh)
	for _, handler := range handlers {
		err := handler(nil, s.apiClient, nil)
		c.Assert(err, jc.ErrorIsNil)
	}
	c.Check(s.stub.Calls(), gc.HasLen, len(expected))
	s.stub.CheckCallNames(c, expected...)
}

func (s *eventHandlerSuite) TestNewEventHandlers(c *gc.C) {
	eh := workers.NewEventHandlers()
	c.Assert(eh, gc.NotNil)
	eh.Close()

	s.checkUnhandled(c, eh)
	s.checkRegistered(c, eh)
	_, _, apiClient, runner := workers.ExposeEventHandlers(eh)
	c.Check(apiClient, gc.IsNil)
	c.Check(runner, gc.IsNil)
}

func (s *eventHandlerSuite) TestReset(c *gc.C) {
	eh := workers.NewEventHandlers()
	c.Assert(eh, gc.NotNil)
	err := eh.Reset(s.apiClient)
	c.Assert(err, jc.ErrorIsNil)
	eh.Close()

	s.checkUnhandled(c, eh)
	s.checkRegistered(c, eh)
	_, _, apiClient, runner := workers.ExposeEventHandlers(eh)
	c.Check(apiClient, gc.Equals, s.apiClient)
	c.Check(runner, gc.IsNil)
}

func (s *eventHandlerSuite) TestRegisterHandler(c *gc.C) {
	eh := workers.NewEventHandlers()
	defer eh.Close()
	eh.RegisterHandler(s.handler)

	s.checkRegistered(c, eh, "handler")
}

func (s *eventHandlerSuite) TestAddEventsOkay(c *gc.C) {
	events := []workload.Event{{
		Kind: workload.EventKindTracked,
		ID:   "spam/eggs",
	}}
	eh := workers.NewEventHandlers()
	eh.Reset(s.apiClient)
	go func() {
		eh.AddEvents(events...)
		eh.Close()
	}()

	s.checkUnhandled(c, eh, events)
}

func (s *eventHandlerSuite) TestAddEventsEmpty(c *gc.C) {
	eh := workers.NewEventHandlers()
	eh.Reset(s.apiClient)
	go func() {
		eh.AddEvents()
		eh.Close()
	}()

	s.checkUnhandled(c, eh)
}

func (s *eventHandlerSuite) TestStartEngine(c *gc.C) {
	events := []workload.Event{{
		Kind: workload.EventKindTracked,
		ID:   "spam/eggs",
	}}

	eh := workers.NewEventHandlers()
	eh.Reset(s.apiClient)
	eh.RegisterHandler(s.handler)
	engine, err := eh.StartEngine()
	c.Assert(err, jc.ErrorIsNil)

	eh.AddEvents(events...)

	engine.Kill()
	err = engine.Wait()
	c.Assert(err, jc.ErrorIsNil)
	eh.Close()

	s.checkUnhandled(c, eh)
	s.stub.CheckCallNames(c, "List", "handler")
	c.Check(s.stub.Calls()[1].Args[0], gc.DeepEquals, events)
	c.Check(s.stub.Calls()[1].Args[1], gc.DeepEquals, s.apiClient)
	// TODO(ericsnow) Check the runner.
}

type stubAPIClient struct {
	context.APIClient
	stub *gitjujutesting.Stub
}

func (c *stubAPIClient) List(ids ...string) ([]workload.Info, error) {
	c.stub.AddCall("List", ids)
	if err := c.stub.NextErr(); err != nil {
		return nil, errors.Trace(err)
	}

	return nil, nil
}
<|endoftext|>


<commit_before>package middleware

import (
	"github.com/plimble/kuja"
	"log"
)

type AddReq struct {
	A int
	B int
}

type AddResp struct {
	C int
}

type AddService struct{}

func (s *AddService) Add(ctx *kuja.Context, req *AddReq) (*AddResp, error) {
	resp := &AddResp{}
	resp.C = req.A + req.B
	return resp, nil
}
<commit_msg>remove import log<commit_after>package middleware

import (
	"github.com/plimble/kuja"
)

type AddReq struct {
	A int
	B int
}

type AddResp struct {
	C int
}

type AddService struct{}

func (s *AddService) Add(ctx *kuja.Context, req *AddReq) (*AddResp, error) {
	resp := &AddResp{}
	resp.C = req.A + req.B
	return resp, nil
}
<|endoftext|>


<commit_before>package errcheck

import (
	"go/types"

	"honnef.co/go/tools/functions"
	"honnef.co/go/tools/lint"
	"honnef.co/go/tools/ssa"
	"honnef.co/go/tools/ssa/ssautil"
)

type Checker struct {
	funcDescs *functions.Descriptions
}

func NewChecker() *Checker {
	return &Checker{}
}

func (c *Checker) Funcs() map[string]lint.Func {
	return map[string]lint.Func{
		"ERR1000": c.CheckErrcheck,
	}
}

func (c *Checker) Init(prog *lint.Program) {
	c.funcDescs = functions.NewDescriptions(prog.SSA)

	fns := ssautil.AllFunctions(prog.SSA)

	for fn := range fns {
		if fn.Blocks == nil {
			continue
		}
		if fn.Synthetic != "" && (fn.Package() == nil || fn != fn.Package().Members["init"]) {
			// Don't track synthetic functions, unless they're the
			// init function
			continue
		}
		pos := fn.Pos()
		if pos == 0 {
			for _, pkg := range prog.Packages {
				if pkg.Package == fn.Pkg {
					pos = pkg.Info.Files[0].Pos()
					break
				}
			}
		}
	}
}

func (c *Checker) CheckErrcheck(j *lint.Job) {
	for _, ssafn := range j.Program.InitialFunctions {
		for _, b := range ssafn.Blocks {
			for _, ins := range b.Instrs {
				ssacall, ok := ins.(ssa.CallInstruction)
				if !ok {
					continue
				}

				switch lint.CallName(ssacall.Common()) {
				case "fmt.Print", "fmt.Println", "fmt.Printf":
					continue
				}
				isRecover := false
				if builtin, ok := ssacall.Common().Value.(*ssa.Builtin); ok {
					isRecover = ok && builtin.Name() == "recover"
				}

				switch ins := ins.(type) {
				case ssa.Value:
					refs := ins.Referrers()
					if refs == nil || len(lint.FilterDebug(*refs)) != 0 {
						continue
					}
				case ssa.Instruction:
					// will be a 'go' or 'defer', neither of which has usable return values
				default:
					// shouldn't happen
					continue
				}

				if ssacall.Common().IsInvoke() {
					if sc, ok := ssacall.Common().Value.(*ssa.Call); ok {
						// TODO(dh): support multiple levels of
						// interfaces, not just one
						ssafn := sc.Common().StaticCallee()
						if ssafn != nil {
							ct := c.funcDescs.Get(ssafn).ConcreteReturnTypes
							// TODO(dh): support >1 concrete types
							if ct != nil && len(ct) == 1 {
								// TODO(dh): do we have access to a
								// cached method set somewhere?
								ms := types.NewMethodSet(ct[0].At(ct[0].Len() - 1).Type())
								// TODO(dh): where can we get the pkg
								// for Lookup? Passing nil works fine
								// for exported methods, but will fail
								// on unexported ones
								// TODO(dh): holy nesting and poor
								// variable names, clean this up
								fn, _ := ms.Lookup(nil, ssacall.Common().Method.Name()).Obj().(*types.Func)
								if fn != nil {
									ssafn := j.Program.SSA.FuncValue(fn)
									if ssafn != nil {
										if c.funcDescs.Get(ssafn).NilError {
											continue
										}
									}
								}
							}
						}
					}
				} else {
					ssafn := ssacall.Common().StaticCallee()
					if ssafn != nil {
						if c.funcDescs.Get(ssafn).NilError {
							// Don't complain when the error is known to be nil
							continue
						}
					}
				}
				switch lint.CallName(ssacall.Common()) {
				case "(*os.File).Close":
					recv := ssacall.Common().Args[0]
					if isReadOnlyFile(recv, nil) {
						continue
					}
				}

				res := ssacall.Common().Signature().Results()
				if res.Len() == 0 {
					continue
				}
				if !isRecover {
					last := res.At(res.Len() - 1)
					if types.TypeString(last.Type(), nil) != "error" {
						continue
					}
				}
				j.Errorf(ins, "unchecked error")
			}
		}
	}
}

func isReadOnlyFile(val ssa.Value, seen map[ssa.Value]bool) bool {
	if seen == nil {
		seen = map[ssa.Value]bool{}
	}
	if seen[val] {
		return true
	}
	seen[val] = true
	switch val := val.(type) {
	case *ssa.Phi:
		for _, edge := range val.Edges {
			if !isReadOnlyFile(edge, seen) {
				return false
			}
		}
		return true
	case *ssa.Extract:
		call, ok := val.Tuple.(*ssa.Call)
		if !ok {
			return false
		}
		switch lint.CallName(call.Common()) {
		case "os.Open":
			return true
		case "os.OpenFile":
			flags, ok := call.Common().Args[1].(*ssa.Const)
			return ok && flags.Uint64() == 0
		}
		return false
	}
	return false
}
<commit_msg>errcheck: delete dead code<commit_after>package errcheck

import (
	"go/types"

	"honnef.co/go/tools/functions"
	"honnef.co/go/tools/lint"
	"honnef.co/go/tools/ssa"
)

type Checker struct {
	funcDescs *functions.Descriptions
}

func NewChecker() *Checker {
	return &Checker{}
}

func (c *Checker) Funcs() map[string]lint.Func {
	return map[string]lint.Func{
		"ERR1000": c.CheckErrcheck,
	}
}

func (c *Checker) Init(prog *lint.Program) {
	c.funcDescs = functions.NewDescriptions(prog.SSA)
}

func (c *Checker) CheckErrcheck(j *lint.Job) {
	for _, ssafn := range j.Program.InitialFunctions {
		for _, b := range ssafn.Blocks {
			for _, ins := range b.Instrs {
				ssacall, ok := ins.(ssa.CallInstruction)
				if !ok {
					continue
				}

				switch lint.CallName(ssacall.Common()) {
				case "fmt.Print", "fmt.Println", "fmt.Printf":
					continue
				}
				isRecover := false
				if builtin, ok := ssacall.Common().Value.(*ssa.Builtin); ok {
					isRecover = ok && builtin.Name() == "recover"
				}

				switch ins := ins.(type) {
				case ssa.Value:
					refs := ins.Referrers()
					if refs == nil || len(lint.FilterDebug(*refs)) != 0 {
						continue
					}
				case ssa.Instruction:
					// will be a 'go' or 'defer', neither of which has usable return values
				default:
					// shouldn't happen
					continue
				}

				if ssacall.Common().IsInvoke() {
					if sc, ok := ssacall.Common().Value.(*ssa.Call); ok {
						// TODO(dh): support multiple levels of
						// interfaces, not just one
						ssafn := sc.Common().StaticCallee()
						if ssafn != nil {
							ct := c.funcDescs.Get(ssafn).ConcreteReturnTypes
							// TODO(dh): support >1 concrete types
							if ct != nil && len(ct) == 1 {
								// TODO(dh): do we have access to a
								// cached method set somewhere?
								ms := types.NewMethodSet(ct[0].At(ct[0].Len() - 1).Type())
								// TODO(dh): where can we get the pkg
								// for Lookup? Passing nil works fine
								// for exported methods, but will fail
								// on unexported ones
								// TODO(dh): holy nesting and poor
								// variable names, clean this up
								fn, _ := ms.Lookup(nil, ssacall.Common().Method.Name()).Obj().(*types.Func)
								if fn != nil {
									ssafn := j.Program.SSA.FuncValue(fn)
									if ssafn != nil {
										if c.funcDescs.Get(ssafn).NilError {
											continue
										}
									}
								}
							}
						}
					}
				} else {
					ssafn := ssacall.Common().StaticCallee()
					if ssafn != nil {
						if c.funcDescs.Get(ssafn).NilError {
							// Don't complain when the error is known to be nil
							continue
						}
					}
				}
				switch lint.CallName(ssacall.Common()) {
				case "(*os.File).Close":
					recv := ssacall.Common().Args[0]
					if isReadOnlyFile(recv, nil) {
						continue
					}
				}

				res := ssacall.Common().Signature().Results()
				if res.Len() == 0 {
					continue
				}
				if !isRecover {
					last := res.At(res.Len() - 1)
					if types.TypeString(last.Type(), nil) != "error" {
						continue
					}
				}
				j.Errorf(ins, "unchecked error")
			}
		}
	}
}

func isReadOnlyFile(val ssa.Value, seen map[ssa.Value]bool) bool {
	if seen == nil {
		seen = map[ssa.Value]bool{}
	}
	if seen[val] {
		return true
	}
	seen[val] = true
	switch val := val.(type) {
	case *ssa.Phi:
		for _, edge := range val.Edges {
			if !isReadOnlyFile(edge, seen) {
				return false
			}
		}
		return true
	case *ssa.Extract:
		call, ok := val.Tuple.(*ssa.Call)
		if !ok {
			return false
		}
		switch lint.CallName(call.Common()) {
		case "os.Open":
			return true
		case "os.OpenFile":
			flags, ok := call.Common().Args[1].(*ssa.Const)
			return ok && flags.Uint64() == 0
		}
		return false
	}
	return false
}
<|endoftext|>


<commit_before>package router

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"golang.org/x/net/websocket"
)

type Result interface {
	SetRequest(*http.Request)
	Execute(http.ResponseWriter)
	String() string
}

type Rendered struct {
	Content io.Reader
	Status  int
}

func (Rendered) SetRequest(*http.Request) {
}

func (r Rendered) Execute(w http.ResponseWriter) {
	if r.Status != 0 {
		w.WriteHeader(r.Status)
	}
	io.Copy(w, r.Content)
}

func (r Rendered) String() string {
	return "Rendered Data"
}

func JSON(data interface{}) Result {
	return JSONData{Data: data}
}

type JSONData struct {
	Data   interface{}
	Status int
}

func (JSONData) SetRequest(*http.Request) {
}

func (r JSONData) Execute(w http.ResponseWriter) {
	if r.Status != 0 {
		w.WriteHeader(r.Status)
	}
	json.NewEncoder(w).Encode(r.Data)
}

func (r JSONData) String() string {
	return "JSON Data"
}

type String struct {
	Content string
	Status  int
}

func (String) SetRequest(*http.Request) {
}
func (r String) Execute(w http.ResponseWriter) {
	io.WriteString(w, r.Content)
}

func (r String) String() string {
	return "String Data"
}

func RedirectTo(location string) Result {
	return &Redirect{URL: location}
}

type Redirect struct {
	Request *http.Request
	URL     string
	Status  int
}

func (r *Redirect) SetRequest(req *http.Request) {
	r.Request = req
}
func (r Redirect) Execute(w http.ResponseWriter) {
	if r.Status == 0 {
		r.Status = 303
	}
	http.Redirect(w, r.Request, r.URL, r.Status)
}

func (r Redirect) String() string {
	return fmt.Sprintf("Redirect To %s", r.URL)
}

func Disallow(location string) Result {
	return &NotAllowed{Fallback: location}
}

type NotAllowed struct {
	Request  *http.Request
	Content  io.Reader
	Fallback string
	Status   int
}

func (na *NotAllowed) SetRequest(req *http.Request) {
	na.Request = req
}
func (na NotAllowed) Execute(w http.ResponseWriter) {
	if na.Fallback != "" {
		if na.Status == 0 {
			na.Status = 302
		}
		http.Redirect(w, na.Request, na.Fallback, na.Status)
	} else if na.Content != nil {
		if na.Status != 0 {
			w.WriteHeader(na.Status)
		}
		io.Copy(w, na.Content)
	} else if na.Status != 0 {
		w.WriteHeader(na.Status)
	} else {
		w.WriteHeader(403)
	}
}

func (na NotAllowed) String() string {
	if na.Fallback != "" {
		return fmt.Sprintf("Not Allowed, Redirecting To %s", na.Fallback)
	} else {
		return fmt.Sprintf("Not Allowed, Rendered a Response")
	}
}

type InternalError struct {
	Error error
}

func (InternalError) SetRequest(*http.Request) {
}
func (ie InternalError) Execute(w http.ResponseWriter) {
	io.WriteString(w, "
Internal Server Error
")
}

func (ie InternalError) String() string {
	return fmt.Sprintf("Error: %s", ie.Error.Error())
}

type NothingResult struct{}

func (NothingResult) SetRequest(*http.Request) {
}
func (NothingResult) Execute(http.ResponseWriter) {
}

func (NothingResult) String() string {
	return "Being Handled Elsewhere"
}

type NotFound struct{}

func (NotFound) SetRequest(*http.Request) {
}
func (NotFound) Execute(http.ResponseWriter) {
}

func (NotFound) String() string {
	return "NotFound/NotApplicable"
}

type WSResult struct {
	Handler websocket.Handler
	request *http.Request
}

func (ws *WSResult) SetRequest(r *http.Request) {
	ws.request = r
}
func (ws WSResult) Execute(w http.ResponseWriter) {
	ws.Handler.ServeHTTP(w, ws.request)
}

func (WSResult) String() string {
	return "Websocket Connection"
}

type UniqueHandler struct {
	Handler http.Handler
	request *http.Request
}

func (uh *UniqueHandler) SetRequest(r *http.Request) {
	uh.request = r
}

func (uh UniqueHandler) Execute(w http.ResponseWriter) {
	go uh.Handler.ServeHTTP(w, uh.request)
}

func (UniqueHandler) String() string {
	return "One-off Handler"
}
<commit_msg>Add JSONP result<commit_after>package router

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"golang.org/x/net/websocket"
)

type Result interface {
	SetRequest(*http.Request)
	Execute(http.ResponseWriter)
	String() string
}

type Rendered struct {
	Content io.Reader
	Status  int
}

func (Rendered) SetRequest(*http.Request) {
}

func (r Rendered) Execute(w http.ResponseWriter) {
	if r.Status != 0 {
		w.WriteHeader(r.Status)
	}
	io.Copy(w, r.Content)
}

func (r Rendered) String() string {
	return "Rendered Data"
}

func JSON(data interface{}) Result {
	return JSONData{Data: data}
}

type JSONData struct {
	Data   interface{}
	Status int
}

func (JSONData) SetRequest(*http.Request) {
}

func (r JSONData) Execute(w http.ResponseWriter) {
	if r.Status != 0 {
		w.WriteHeader(r.Status)
	}
	json.NewEncoder(w).Encode(r.Data)
}

func (r JSONData) String() string {
	return "JSON Data"
}

func JSONP(data interface{}) Result {
	return &JSONPData{Data: data}
}

type JSONPData struct {
	Data    interface{}
	Status  int
	Request *http.Request
}

func (r *JSONPData) SetRequest(req *http.Request) {
	r.Request = req
}

func (r JSONPData) Execute(w http.ResponseWriter) {
	if r.Status != 0 {
		w.WriteHeader(r.Status)
	}
	io.WriteString(w, r.Request.URL.Query().Get("callback")+"(")
	json.NewEncoder(w).Encode(r.Data)
	io.WriteString(w, ")")
}

func (r JSONPData) String() string {
	return "JSONP Data"
}

type String struct {
	Content string
	Status  int
}

func (String) SetRequest(*http.Request) {
}
func (r String) Execute(w http.ResponseWriter) {
	io.WriteString(w, r.Content)
}

func (r String) String() string {
	return "String Data"
}

func RedirectTo(location string) Result {
	return &Redirect{URL: location}
}

type Redirect struct {
	Request *http.Request
	URL     string
	Status  int
}

func (r *Redirect) SetRequest(req *http.Request) {
	r.Request = req
}
func (r Redirect) Execute(w http.ResponseWriter) {
	if r.Status == 0 {
		r.Status = 303
	}
	http.Redirect(w, r.Request, r.URL, r.Status)
}

func (r Redirect) String() string {
	return fmt.Sprintf("Redirect To %s", r.URL)
}

func Disallow(location string) Result {
	return &NotAllowed{Fallback: location}
}

type NotAllowed struct {
	Request  *http.Request
	Content  io.Reader
	Fallback string
	Status   int
}

func (na *NotAllowed) SetRequest(req *http.Request) {
	na.Request = req
}
func (na NotAllowed) Execute(w http.ResponseWriter) {
	if na.Fallback != "" {
		if na.Status == 0 {
			na.Status = 302
		}
		http.Redirect(w, na.Request, na.Fallback, na.Status)
	} else if na.Content != nil {
		if na.Status != 0 {
			w.WriteHeader(na.Status)
		}
		io.Copy(w, na.Content)
	} else if na.Status != 0 {
		w.WriteHeader(na.Status)
	} else {
		w.WriteHeader(403)
	}
}

func (na NotAllowed) String() string {
	if na.Fallback != "" {
		return fmt.Sprintf("Not Allowed, Redirecting To %s", na.Fallback)
	} else {
		return fmt.Sprintf("Not Allowed, Rendered a Response")
	}
}

type InternalError struct {
	Error error
}

func (InternalError) SetRequest(*http.Request) {
}
func (ie InternalError) Execute(w http.ResponseWriter) {
	io.WriteString(w, "
Internal Server Error
")
}

func (ie InternalError) String() string {
	return fmt.Sprintf("Error: %s", ie.Error.Error())
}

type NothingResult struct{}

func (NothingResult) SetRequest(*http.Request) {
}
func (NothingResult) Execute(http.ResponseWriter) {
}

func (NothingResult) String() string {
	return "Being Handled Elsewhere"
}

type NotFound struct{}

func (NotFound) SetRequest(*http.Request) {
}
func (NotFound) Execute(http.ResponseWriter) {
}

func (NotFound) String() string {
	return "NotFound/NotApplicable"
}

type WSResult struct {
	Handler websocket.Handler
	request *http.Request
}

func (ws *WSResult) SetRequest(r *http.Request) {
	ws.request = r
}
func (ws WSResult) Execute(w http.ResponseWriter) {
	ws.Handler.ServeHTTP(w, ws.request)
}

func (WSResult) String() string {
	return "Websocket Connection"
}

type UniqueHandler struct {
	Handler http.Handler
	request *http.Request
}

func (uh *UniqueHandler) SetRequest(r *http.Request) {
	uh.request = r
}

func (uh UniqueHandler) Execute(w http.ResponseWriter) {
	go uh.Handler.ServeHTTP(w, uh.request)
}

func (UniqueHandler) String() string {
	return "One-off Handler"
}
<|endoftext|>


<commit_before>package admin

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path"
	"reflect"
	"strings"
	"text/template"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

type Context struct {
	*qor.Context
	*Searcher
	Resource    *Resource
	Admin       *Admin
	CurrentUser qor.CurrentUser
	Result      interface{}
	Content     string
}

// Resource
func (context *Context) ResourcePath() string {
	if context.Resource == nil {
		return ""
	}
	return context.Resource.ToParam()
}

func (context *Context) SetResource(res *Resource) *Context {
	context.Resource = res
	context.Searcher = &Searcher{Context: context}
	return context
}

func (context *Context) NewResource(name ...string) *Context {
	clone := &Context{Context: context.Context, Admin: context.Admin, Result: context.Result}
	if len(name) > 0 {
		clone.SetResource(context.Admin.GetResource(name[0]))
	} else {
		clone.SetResource(context.Resource)
	}
	return clone
}

// Template
func (context *Context) getViewPaths() (paths []string) {
	dirs := []string{context.ResourcePath(), path.Join("themes", "default"), "."}
	if context.Resource != nil && context.Resource.Config != nil && context.Resource.Config.Theme != "" {
		themePath := path.Join("themes", context.Resource.Config.Theme)
		dirs = append([]string{path.Join(themePath, context.ResourcePath()), themePath}, dirs...)
	}

	for _, p := range dirs {
		for _, d := range viewPaths {
			if isExistingDir(path.Join(d, p)) {
				paths = append(paths, path.Join(d, p))
			}
		}
	}
	return paths
}

func (context *Context) findFile(layout string) (string, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			return path.Join(p, layout), nil
		}
	}
	return "", errors.New("file not found")
}

func (context *Context) findTemplate(tmpl *template.Template, layout string) (*template.Template, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			if tmpl, err = tmpl.ParseFiles(path.Join(p, layout)); err != nil {
				fmt.Println(err)
			} else {
				return tmpl, nil
			}
		}
	}
	return tmpl, errors.New("template not found")
}

func (context *Context) Render(name string, results ...interface{}) string {
	var err error
	names := strings.Split(name, "/")
	tmpl := template.New(names[len(names)-1] + ".tmpl").Funcs(context.funcMap())
	if len(results) > 0 {
		context.Result = results[0]
	}

	if tmpl, err = context.findTemplate(tmpl, name+".tmpl"); err == nil {
		var result = bytes.NewBufferString("")
		if err := tmpl.Execute(result, context); err != nil {
			fmt.Println(err)
		}
		return result.String()
	}

	return ""
}

func (context *Context) Execute(name string, result interface{}) {
	var tmpl *template.Template
	var cacheKey string

	if context.Resource != nil {
		cacheKey = path.Join(context.ResourcePath(), name)
	} else {
		cacheKey = name
	}

	if t, ok := templates[cacheKey]; !ok || true {
		var err error
		tmpl = template.New("layout.tmpl").Funcs(context.funcMap())
		if tmpl, err = context.findTemplate(tmpl, "layout.tmpl"); err == nil {
			for _, name := range []string{"header", "footer"} {
				if tmpl.Lookup(name) == nil {
					tmpl, _ = context.findTemplate(tmpl, name+".tmpl")
				}
			}
		}
	} else {
		tmpl = t
	}

	context.Content = context.Render(name, result)
	if err := tmpl.Execute(context.Writer, context); err != nil {
		fmt.Println(err)
	}
}

// Function Maps
func (context *Context) PrimaryKeyOf(value interface{}) interface{} {
	return context.GetDB().NewScope(value).PrimaryKeyValue()
}

func (context *Context) NewRecord(value interface{}) interface{} {
	return context.GetDB().NewRecord(value)
}

func (context *Context) ValueOf(value interface{}, meta *Meta) interface{} {
	return meta.Valuer(value, context.Context)
}

func (context *Context) NewResourcePath(value interface{}) string {
	if res, ok := value.(*Resource); ok {
		return path.Join(context.Admin.router.Prefix, res.ToParam(), "new")
	} else {
		return path.Join(context.Admin.router.Prefix, context.Resource.ToParam(), "new")
	}
}

func (context *Context) UrlFor(value interface{}, resources ...*Resource) string {
	var url string
	if admin, ok := value.(*Admin); ok {
		url = admin.router.Prefix
	} else if res, ok := value.(*Resource); ok {
		url = path.Join(context.Admin.router.Prefix, res.ToParam())
	} else {
		primaryKey := context.GetDB().NewScope(value).PrimaryKeyValue()
		name := context.Admin.NewResource(value, nil).ToParam()
		url = path.Join(context.Admin.router.Prefix, name, fmt.Sprintf("%v", primaryKey))
	}
	return url
}

func (context *Context) LinkTo(text interface{}, link interface{}) string {
	text = reflect.Indirect(reflect.ValueOf(text)).Interface()
	if linkStr, ok := link.(string); ok {
		return fmt.Sprintf(`<a href="%v">%v</a>`, linkStr, text)
	}
	return fmt.Sprintf(`<a href="%v">%v</a>`, context.UrlFor(link), text)
}

func (context *Context) RenderForm(value interface{}, metas []*Meta) string {
	var result = bytes.NewBufferString("")
	context.renderForm(result, value, metas, []string{"QorResource"})
	return result.String()
}

func (context *Context) renderForm(result *bytes.Buffer, value interface{}, metas []*Meta, prefix []string) {
	for _, meta := range metas {
		context.RenderMeta(result, meta, value, prefix)
	}
}

func (context *Context) RenderMeta(writer *bytes.Buffer, meta *Meta, value interface{}, prefix []string) {
	prefix = append(prefix, meta.Name)

	funcsMap := context.funcMap()
	funcsMap["render_form"] = func(value interface{}, metas []*Meta, index ...int) string {
		var result = bytes.NewBufferString("")
		newPrefix := append([]string{}, prefix...)

		if len(index) > 0 {
			last := newPrefix[len(newPrefix)-1]
			newPrefix = append(newPrefix[:len(newPrefix)-1], fmt.Sprintf("%v[%v]", last, index[0]))
		}

		context.renderForm(result, value, metas, newPrefix)
		return result.String()
	}

	var tmpl = template.New(meta.Type + ".tmpl").Funcs(funcsMap)

	if tmpl, err := context.findTemplate(tmpl, fmt.Sprintf("forms/%v.tmpl", meta.Type)); err == nil {
		data := map[string]interface{}{}
		data["InputId"] = strings.Join(prefix, "")
		data["Label"] = meta.Label
		data["InputName"] = strings.Join(prefix, ".")
		data["Value"] = meta.Valuer(value, context.Context)
		if meta.GetCollection != nil {
			data["CollectionValue"] = meta.GetCollection(value, context.Context)
		}
		data["Meta"] = meta

		if err := tmpl.Execute(writer, data); err != nil {
			fmt.Println(err)
		}
	} else {
		fmt.Printf("%v: form type %v not supported\n", meta.Name, meta.Type)
	}
}

func (context *Context) HasPrimaryKey(value interface{}, primaryKey interface{}) bool {
	primaryKeys := []interface{}{}
	reflectValue := reflect.ValueOf(value)
	if reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	if reflectValue.Kind() == reflect.Slice {
		for i := 0; i < reflectValue.Len(); i++ {
			scope := &gorm.Scope{Value: reflectValue.Index(i).Interface()}
			primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
		}
	} else if reflectValue.Kind() == reflect.Struct {
		scope := &gorm.Scope{Value: value}
		primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
	}

	for _, key := range primaryKeys {
		if fmt.Sprintf("%v", primaryKey) == fmt.Sprintf("%v", key) {
			return true
		}
	}
	return false
}

func (context *Context) getResource(resources ...*Resource) *Resource {
	for _, res := range resources {
		return res
	}
	return context.Resource
}

func (context *Context) AllMetas(resources ...*Resource) []*Meta {
	return context.getResource(resources...).AllMetas()
}

func (context *Context) IndexMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.IndexMetas(), context, roles.Read)
}

func (context *Context) EditMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.EditMetas(), context, roles.Update)
}

func (context *Context) ShowMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.ShowMetas(), context, roles.Read)
}

func (context *Context) NewMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.NewMetas(), context, roles.Create)
}

func (context *Context) JavaScriptTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "javascripts", name+".js")
	return fmt.Sprintf(`<script src="%s"></script>`, name)
}

func (context *Context) StyleSheetTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "stylesheets", name+".css")
	return fmt.Sprintf(`<link type="text/css" rel="stylesheet" href="%s">`, name)
}

type Page struct {
	Page       int
	Current    bool
	IsPrevious bool
	IsNext     bool
}

func (context *Context) Pagination() []Page {
	pagination := context.Searcher.Pagination
	start := pagination.CurrentPage
	fmt.Println("-----------------------")
	fmt.Println(pagination.CurrentPage)
	if start-5 < 1 {
		start = 1
	}
	fmt.Println(start)
	fmt.Println(start - 5)
	fmt.Println(start-5 < 1)

	end := start + 9
	if end > pagination.Pages {
		end = pagination.Pages
	}

	var pages []Page
	if start > 1 {
		pages = append(pages, Page{Page: start - 1, IsPrevious: true})
	}

	for i := start; i <= end; i++ {
		pages = append(pages, Page{Page: i, Current: pagination.CurrentPage == i})
	}

	if end < pagination.Pages {
		pages = append(pages, Page{Page: end + 1, IsNext: true})
	}

	return pages
}

func Equal(a, b interface{}) bool {
	return reflect.DeepEqual(a, b)
}

func (context *Context) funcMap() template.FuncMap {
	funcMap := template.FuncMap{
		"menus":             context.Admin.GetMenus,
		"current_user":      func() qor.CurrentUser { return context.CurrentUser },
		"render":            context.Render,
		"render_form":       context.RenderForm,
		"url_for":           context.UrlFor,
		"link_to":           context.LinkTo,
		"new_resource_path": context.NewResourcePath,
		"new_resource":      context.NewResource,
		"is_new_record":     context.NewRecord,
		"value_of":          context.ValueOf,
		"primary_key_of":    context.PrimaryKeyOf,
		"has_primary_key":   context.HasPrimaryKey,
		"all_metas":         context.AllMetas,
		"index_metas":       context.IndexMetas,
		"edit_metas":        context.EditMetas,
		"show_metas":        context.ShowMetas,
		"new_metas":         context.NewMetas,
		"pagination":        context.Pagination,
		"javascript_tag":    context.JavaScriptTag,
		"stylesheet_tag":    context.StyleSheetTag,
		"equal":             Equal,
	}

	for key, value := range context.Admin.funcMaps {
		funcMap[key] = value
	}
	return funcMap
}
<commit_msg>Remove Debug Code<commit_after>package admin

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path"
	"reflect"
	"strings"
	"text/template"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/roles"
)

type Context struct {
	*qor.Context
	*Searcher
	Resource    *Resource
	Admin       *Admin
	CurrentUser qor.CurrentUser
	Result      interface{}
	Content     string
}

// Resource
func (context *Context) ResourcePath() string {
	if context.Resource == nil {
		return ""
	}
	return context.Resource.ToParam()
}

func (context *Context) SetResource(res *Resource) *Context {
	context.Resource = res
	context.Searcher = &Searcher{Context: context}
	return context
}

func (context *Context) NewResource(name ...string) *Context {
	clone := &Context{Context: context.Context, Admin: context.Admin, Result: context.Result}
	if len(name) > 0 {
		clone.SetResource(context.Admin.GetResource(name[0]))
	} else {
		clone.SetResource(context.Resource)
	}
	return clone
}

// Template
func (context *Context) getViewPaths() (paths []string) {
	dirs := []string{context.ResourcePath(), path.Join("themes", "default"), "."}
	if context.Resource != nil && context.Resource.Config != nil && context.Resource.Config.Theme != "" {
		themePath := path.Join("themes", context.Resource.Config.Theme)
		dirs = append([]string{path.Join(themePath, context.ResourcePath()), themePath}, dirs...)
	}

	for _, p := range dirs {
		for _, d := range viewPaths {
			if isExistingDir(path.Join(d, p)) {
				paths = append(paths, path.Join(d, p))
			}
		}
	}
	return paths
}

func (context *Context) findFile(layout string) (string, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			return path.Join(p, layout), nil
		}
	}
	return "", errors.New("file not found")
}

func (context *Context) findTemplate(tmpl *template.Template, layout string) (*template.Template, error) {
	for _, p := range context.getViewPaths() {
		if _, err := os.Stat(path.Join(p, layout)); !os.IsNotExist(err) {
			if tmpl, err = tmpl.ParseFiles(path.Join(p, layout)); err != nil {
				fmt.Println(err)
			} else {
				return tmpl, nil
			}
		}
	}
	return tmpl, errors.New("template not found")
}

func (context *Context) Render(name string, results ...interface{}) string {
	var err error
	names := strings.Split(name, "/")
	tmpl := template.New(names[len(names)-1] + ".tmpl").Funcs(context.funcMap())
	if len(results) > 0 {
		context.Result = results[0]
	}

	if tmpl, err = context.findTemplate(tmpl, name+".tmpl"); err == nil {
		var result = bytes.NewBufferString("")
		if err := tmpl.Execute(result, context); err != nil {
			fmt.Println(err)
		}
		return result.String()
	}

	return ""
}

func (context *Context) Execute(name string, result interface{}) {
	var tmpl *template.Template
	var cacheKey string

	if context.Resource != nil {
		cacheKey = path.Join(context.ResourcePath(), name)
	} else {
		cacheKey = name
	}

	if t, ok := templates[cacheKey]; !ok || true {
		var err error
		tmpl = template.New("layout.tmpl").Funcs(context.funcMap())
		if tmpl, err = context.findTemplate(tmpl, "layout.tmpl"); err == nil {
			for _, name := range []string{"header", "footer"} {
				if tmpl.Lookup(name) == nil {
					tmpl, _ = context.findTemplate(tmpl, name+".tmpl")
				}
			}
		}
	} else {
		tmpl = t
	}

	context.Content = context.Render(name, result)
	if err := tmpl.Execute(context.Writer, context); err != nil {
		fmt.Println(err)
	}
}

// Function Maps
func (context *Context) PrimaryKeyOf(value interface{}) interface{} {
	return context.GetDB().NewScope(value).PrimaryKeyValue()
}

func (context *Context) NewRecord(value interface{}) interface{} {
	return context.GetDB().NewRecord(value)
}

func (context *Context) ValueOf(value interface{}, meta *Meta) interface{} {
	return meta.Valuer(value, context.Context)
}

func (context *Context) NewResourcePath(value interface{}) string {
	if res, ok := value.(*Resource); ok {
		return path.Join(context.Admin.router.Prefix, res.ToParam(), "new")
	} else {
		return path.Join(context.Admin.router.Prefix, context.Resource.ToParam(), "new")
	}
}

func (context *Context) UrlFor(value interface{}, resources ...*Resource) string {
	var url string
	if admin, ok := value.(*Admin); ok {
		url = admin.router.Prefix
	} else if res, ok := value.(*Resource); ok {
		url = path.Join(context.Admin.router.Prefix, res.ToParam())
	} else {
		primaryKey := context.GetDB().NewScope(value).PrimaryKeyValue()
		name := context.Admin.NewResource(value, nil).ToParam()
		url = path.Join(context.Admin.router.Prefix, name, fmt.Sprintf("%v", primaryKey))
	}
	return url
}

func (context *Context) LinkTo(text interface{}, link interface{}) string {
	text = reflect.Indirect(reflect.ValueOf(text)).Interface()
	if linkStr, ok := link.(string); ok {
		return fmt.Sprintf(`<a href="%v">%v</a>`, linkStr, text)
	}
	return fmt.Sprintf(`<a href="%v">%v</a>`, context.UrlFor(link), text)
}

func (context *Context) RenderForm(value interface{}, metas []*Meta) string {
	var result = bytes.NewBufferString("")
	context.renderForm(result, value, metas, []string{"QorResource"})
	return result.String()
}

func (context *Context) renderForm(result *bytes.Buffer, value interface{}, metas []*Meta, prefix []string) {
	for _, meta := range metas {
		context.RenderMeta(result, meta, value, prefix)
	}
}

func (context *Context) RenderMeta(writer *bytes.Buffer, meta *Meta, value interface{}, prefix []string) {
	prefix = append(prefix, meta.Name)

	funcsMap := context.funcMap()
	funcsMap["render_form"] = func(value interface{}, metas []*Meta, index ...int) string {
		var result = bytes.NewBufferString("")
		newPrefix := append([]string{}, prefix...)

		if len(index) > 0 {
			last := newPrefix[len(newPrefix)-1]
			newPrefix = append(newPrefix[:len(newPrefix)-1], fmt.Sprintf("%v[%v]", last, index[0]))
		}

		context.renderForm(result, value, metas, newPrefix)
		return result.String()
	}

	var tmpl = template.New(meta.Type + ".tmpl").Funcs(funcsMap)

	if tmpl, err := context.findTemplate(tmpl, fmt.Sprintf("forms/%v.tmpl", meta.Type)); err == nil {
		data := map[string]interface{}{}
		data["InputId"] = strings.Join(prefix, "")
		data["Label"] = meta.Label
		data["InputName"] = strings.Join(prefix, ".")
		data["Value"] = meta.Valuer(value, context.Context)
		if meta.GetCollection != nil {
			data["CollectionValue"] = meta.GetCollection(value, context.Context)
		}
		data["Meta"] = meta

		if err := tmpl.Execute(writer, data); err != nil {
			fmt.Println(err)
		}
	} else {
		fmt.Printf("%v: form type %v not supported\n", meta.Name, meta.Type)
	}
}

func (context *Context) HasPrimaryKey(value interface{}, primaryKey interface{}) bool {
	primaryKeys := []interface{}{}
	reflectValue := reflect.ValueOf(value)
	if reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	if reflectValue.Kind() == reflect.Slice {
		for i := 0; i < reflectValue.Len(); i++ {
			scope := &gorm.Scope{Value: reflectValue.Index(i).Interface()}
			primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
		}
	} else if reflectValue.Kind() == reflect.Struct {
		scope := &gorm.Scope{Value: value}
		primaryKeys = append(primaryKeys, scope.PrimaryKeyValue())
	}

	for _, key := range primaryKeys {
		if fmt.Sprintf("%v", primaryKey) == fmt.Sprintf("%v", key) {
			return true
		}
	}
	return false
}

func (context *Context) getResource(resources ...*Resource) *Resource {
	for _, res := range resources {
		return res
	}
	return context.Resource
}

func (context *Context) AllMetas(resources ...*Resource) []*Meta {
	return context.getResource(resources...).AllMetas()
}

func (context *Context) IndexMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.IndexMetas(), context, roles.Read)
}

func (context *Context) EditMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.EditMetas(), context, roles.Update)
}

func (context *Context) ShowMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.ShowMetas(), context, roles.Read)
}

func (context *Context) NewMetas(resources ...*Resource) []*Meta {
	res := context.getResource(resources...)
	return res.AllowedMetas(res.NewMetas(), context, roles.Create)
}

func (context *Context) JavaScriptTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "javascripts", name+".js")
	return fmt.Sprintf(`<script src="%s"></script>`, name)
}

func (context *Context) StyleSheetTag(name string) string {
	name = path.Join(context.Admin.GetRouter().Prefix, "assets", "stylesheets", name+".css")
	return fmt.Sprintf(`<link type="text/css" rel="stylesheet" href="%s">`, name)
}

type Page struct {
	Page       int
	Current    bool
	IsPrevious bool
	IsNext     bool
}

func (context *Context) Pagination() []Page {
	pagination := context.Searcher.Pagination
	start := pagination.CurrentPage
	if start-5 < 1 {
		start = 1
	}

	end := start + 9
	if end > pagination.Pages {
		end = pagination.Pages
	}

	var pages []Page
	if start > 1 {
		pages = append(pages, Page{Page: start - 1, IsPrevious: true})
	}

	for i := start; i <= end; i++ {
		pages = append(pages, Page{Page: i, Current: pagination.CurrentPage == i})
	}

	if end < pagination.Pages {
		pages = append(pages, Page{Page: end + 1, IsNext: true})
	}

	return pages
}

func Equal(a, b interface{}) bool {
	return reflect.DeepEqual(a, b)
}

func (context *Context) funcMap() template.FuncMap {
	funcMap := template.FuncMap{
		"menus":             context.Admin.GetMenus,
		"current_user":      func() qor.CurrentUser { return context.CurrentUser },
		"render":            context.Render,
		"render_form":       context.RenderForm,
		"url_for":           context.UrlFor,
		"link_to":           context.LinkTo,
		"new_resource_path": context.NewResourcePath,
		"new_resource":      context.NewResource,
		"is_new_record":     context.NewRecord,
		"value_of":          context.ValueOf,
		"primary_key_of":    context.PrimaryKeyOf,
		"has_primary_key":   context.HasPrimaryKey,
		"all_metas":         context.AllMetas,
		"index_metas":       context.IndexMetas,
		"edit_metas":        context.EditMetas,
		"show_metas":        context.ShowMetas,
		"new_metas":         context.NewMetas,
		"pagination":        context.Pagination,
		"javascript_tag":    context.JavaScriptTag,
		"stylesheet_tag":    context.StyleSheetTag,
		"equal":             Equal,
	}

	for key, value := range context.Admin.funcMaps {
		funcMap[key] = value
	}
	return funcMap
}
<|endoftext|>


<commit_before>package routers

import (
	"github.com/astaxie/beego"
	"github.com/dockercn/docker-bucket/controllers"
)

func init() {
	//Web Interface
	beego.Router("/", &controllers.MainController{})
	beego.Router("/auth", &controllers.AuthController{}, "get:Get")
	beego.Router("/signout", &controllers.AuthWebController{}, "get:Signout")
	beego.Router("/setting", &controllers.DashboardController{}, "get:GetSetting")
	beego.Router("/dashboard", &controllers.DashboardController{}, "get:GetDashboard")
	beego.Router("/admin", &controllers.AdminController{}, "get:GetAdmin")

	//Static File
	beego.Router("/favicon.ico", &controllers.StaticController{}, "get:GetFavicon")
	//TODO sitemap/rss/robots.txt

	web := beego.NewNamespace("/w1",
		beego.NSRouter("/signin", &controllers.AuthWebController{}, "post:Signin"),
		beego.NSRouter("/reset", &controllers.AuthWebController{}, "post:ResetPasswd"),
		beego.NSRouter("/signup", &controllers.AuthWebController{}, "post:Signup"),
		beego.NSRouter("/profile", &controllers.UsersWebController{}, "get:GetProfile"),
		beego.NSRouter("/profile", &controllers.UsersWebController{}, "put:PutProfile"),
		beego.NSRouter("/gravatar", &controllers.UsersWebController{}, "post:PostGravatar"),
	)

	//CI Service API
	drone := beego.NewNamespace("/d1",
		beego.NSRouter("/yaml", &controllers.DroneAPIController{}, "post:PostYAML"),
	)

	//Docker Registry API V1 remain
	beego.Router("/_ping", &controllers.PingAPIController{}, "get:GetPing")
	beego.Router("/_status", &controllers.StatusAPIController{})

	//Docker Registry API V1
	api := beego.NewNamespace("/v1",
		beego.NSRouter("/_ping", &controllers.PingAPIController{}, "get:GetPing"),
		beego.NSRouter("/_status", &controllers.StatusAPIController{}),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "get:GetUsers"),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "post:PostUsers"),

		beego.NSNamespace("/repositories",
			beego.NSRouter("/:namespace/:repo_name/tags/:tag", &controllers.RepositoryAPIController{}, "put:PutTag"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "put:PutRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "get:GetRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/tags", &controllers.RepositoryAPIController{}, "get:GetRepositoryTags"),
			beego.NSRouter("/:namespace/:repo_name", &controllers.RepositoryAPIController{}, "put:PutRepository"),
		),

		beego.NSNamespace("/images",
			beego.NSRouter("/:image_id/ancestry", &controllers.ImageAPIController{}, "get:GetImageAncestry"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "get:GetImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "get:GetImageLayer"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "put:PutImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "put:PutImageLayer"),
			beego.NSRouter("/:image_id/checksum", &controllers.ImageAPIController{}, "put:PutChecksum"),
		),
	)

	beego.AddNamespace(web)
	beego.AddNamespace(drone)
	beego.AddNamespace(api)
}
<commit_msg>增加修改帐户的路由<commit_after>package routers

import (
	"github.com/astaxie/beego"
	"github.com/dockercn/docker-bucket/controllers"
)

func init() {
	//Web Interface
	beego.Router("/", &controllers.MainController{})
	beego.Router("/auth", &controllers.AuthController{}, "get:Get")
	beego.Router("/signout", &controllers.AuthWebController{}, "get:Signout")
	beego.Router("/setting", &controllers.DashboardController{}, "get:GetSetting")
	beego.Router("/dashboard", &controllers.DashboardController{}, "get:GetDashboard")
	beego.Router("/admin", &controllers.AdminController{}, "get:GetAdmin")

	//Static File
	beego.Router("/favicon.ico", &controllers.StaticController{}, "get:GetFavicon")
	//TODO sitemap/rss/robots.txt

	web := beego.NewNamespace("/w1",
		beego.NSRouter("/signin", &controllers.AuthWebController{}, "post:Signin"),
		beego.NSRouter("/reset", &controllers.AuthWebController{}, "post:ResetPasswd"),
		beego.NSRouter("/signup", &controllers.AuthWebController{}, "post:Signup"),
		beego.NSRouter("/profile", &controllers.UsersWebController{}, "get:GetProfile"),
		beego.NSRouter("/profile", &controllers.UsersWebController{}, "put:PutProfile"),
		beego.NSRouter("/account", &controllers.UsersWebController{}, "put:PutAccount"),
		beego.NSRouter("/gravatar", &controllers.UsersWebController{}, "post:PostGravatar"),
	)

	//CI Service API
	drone := beego.NewNamespace("/d1",
		beego.NSRouter("/yaml", &controllers.DroneAPIController{}, "post:PostYAML"),
	)

	//Docker Registry API V1 remain
	beego.Router("/_ping", &controllers.PingAPIController{}, "get:GetPing")
	beego.Router("/_status", &controllers.StatusAPIController{})

	//Docker Registry API V1
	api := beego.NewNamespace("/v1",
		beego.NSRouter("/_ping", &controllers.PingAPIController{}, "get:GetPing"),
		beego.NSRouter("/_status", &controllers.StatusAPIController{}),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "get:GetUsers"),
		beego.NSRouter("/users", &controllers.UsersAPIController{}, "post:PostUsers"),

		beego.NSNamespace("/repositories",
			beego.NSRouter("/:namespace/:repo_name/tags/:tag", &controllers.RepositoryAPIController{}, "put:PutTag"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "put:PutRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/images", &controllers.RepositoryAPIController{}, "get:GetRepositoryImages"),
			beego.NSRouter("/:namespace/:repo_name/tags", &controllers.RepositoryAPIController{}, "get:GetRepositoryTags"),
			beego.NSRouter("/:namespace/:repo_name", &controllers.RepositoryAPIController{}, "put:PutRepository"),
		),

		beego.NSNamespace("/images",
			beego.NSRouter("/:image_id/ancestry", &controllers.ImageAPIController{}, "get:GetImageAncestry"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "get:GetImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "get:GetImageLayer"),
			beego.NSRouter("/:image_id/json", &controllers.ImageAPIController{}, "put:PutImageJSON"),
			beego.NSRouter("/:image_id/layer", &controllers.ImageAPIController{}, "put:PutImageLayer"),
			beego.NSRouter("/:image_id/checksum", &controllers.ImageAPIController{}, "put:PutChecksum"),
		),
	)

	beego.AddNamespace(web)
	beego.AddNamespace(drone)
	beego.AddNamespace(api)
}
<|endoftext|>


<commit_before>// Package md5 computes MD5 checksum for large files
package checksum

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"hash"
	"io"
	"os"
)

const bufferSize = 65536

// MD5sum returns MD5 checksum of filename
func MD5sum(filename string) (string, error) {
	if info, err := os.Stat(filename); err != nil || info.IsDir() {
		return "", err
	}

	file, err := os.Open(filename)
	if err != nil {
		return "", err
	}
	defer func() { _ = file.Close() }()

	hasher := md5.New()
	buf := make([]byte, bufferSize)
	reader := bufio.NewReader(file)
here:
	for {
		switch n, err := reader.Read(buf); err {
		case nil:
			hasher.Write(buf[:n])
		case io.EOF:
			break here
		default:
			return "", err
		}
	}
	return fmt.Sprintf("%x", hasher.Sum(nil)), nil
}

// Sum calculates the hash based on a provided hash provider
func Sum(hashAlgorithm hash.Hash, filename string) (string, error) {
	if info, err := os.Stat(filename); err != nil || info.IsDir() {
		return "", err
	}

	file, err := os.Open(filename)
	if err != nil {
		return "", err
	}
	defer func() { _ = file.Close() }()

	buf := make([]byte, bufferSize)
	reader := bufio.NewReader(file)
here:
	for {
		switch n, err := reader.Read(buf); err {
		case nil:
			hashAlgorithm.Write(buf[:n])
		case io.EOF:
			break here
		default:
			return "", err
		}
	}
	return fmt.Sprintf("%x", hashAlgorithm.Sum(nil)), nil
}
<commit_msg>feat: transform MD5sum into convenience function<commit_after>// Package md5 computes MD5 checksum for large files
package checksum

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"hash"
	"io"
	"os"
)

const bufferSize = 65536

// MD5sum returns MD5 checksum of filename
func MD5sum(filename string) (string, error) {
	return Sum(md5.New(), filename)
}

// Sum calculates the hash based on a provided hash provider
func Sum(hashAlgorithm hash.Hash, filename string) (string, error) {
	if info, err := os.Stat(filename); err != nil || info.IsDir() {
		return "", err
	}

	file, err := os.Open(filename)
	if err != nil {
		return "", err
	}
	defer func() { _ = file.Close() }()

	buf := make([]byte, bufferSize)
	reader := bufio.NewReader(file)
here:
	for {
		switch n, err := reader.Read(buf); err {
		case nil:
			hashAlgorithm.Write(buf[:n])
		case io.EOF:
			break here
		default:
			return "", err
		}
	}
	return fmt.Sprintf("%x", hashAlgorithm.Sum(nil)), nil
}
<|endoftext|>


<commit_before>package fileutils

import (
	"fmt"
	"io"
	"os"
	"syscall"
)

// CopyFile copies the file at source to dest
func CopyFile(source string, dest string) error {
	si, err := os.Lstat(source)
	if err != nil {
		return err
	}

	// Handle symlinks
	if si.Mode()&os.ModeSymlink != 0 {
		target, err := os.Readlink(source)
		if err != nil {
			return err
		}
		if err := os.Symlink(target, dest); err != nil {
			return err
		}
		return nil
	}

	// Handle device files
	st, ok := si.Sys().(*syscall.Stat_t)
	if !ok {
		return fmt.Errorf("could not convert to syscall.Stat_t")
	}

	if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
		devMajor := int64(major(uint64(st.Rdev)))
		devMinor := int64(minor(uint64(st.Rdev)))
		mode := uint32(si.Mode() & 07777)
		if st.Mode&syscall.S_IFMT == syscall.S_IFBLK {
			mode |= syscall.S_IFBLK
		}
		if st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
			mode |= syscall.S_IFCHR
		}
		if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil {
			return err
		}
		return nil
	}

	// Handle regular files
	if si.Mode().IsRegular() {
		sf, err := os.Open(source)
		if err != nil {
			return err
		}
		defer sf.Close()

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

		_, err = io.Copy(df, sf)
		if err != nil {
			return err
		}
	}

	return nil
}

func major(device uint64) uint64 {
	return (device >> 8) & 0xfff
}

func minor(device uint64) uint64 {
	return (device & 0xff) | ((device >> 12) & 0xfff00)
}

func mkdev(major int64, minor int64) uint32 {
	return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
}
<commit_msg>Chown the file to same owner as source<commit_after>package fileutils

import (
	"fmt"
	"io"
	"os"
	"syscall"
)

// CopyFile copies the file at source to dest
func CopyFile(source string, dest string) error {
	si, err := os.Lstat(source)
	if err != nil {
		return err
	}

	st, ok := si.Sys().(*syscall.Stat_t)
	if !ok {
		return fmt.Errorf("could not convert to syscall.Stat_t")
	}

	uid := int(st.Uid)
	gid := int(st.Gid)

	// Handle symlinks
	if si.Mode()&os.ModeSymlink != 0 {
		target, err := os.Readlink(source)
		if err != nil {
			return err
		}
		if err := os.Symlink(target, dest); err != nil {
			return err
		}
	}

	// Handle device files
	if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
		devMajor := int64(major(uint64(st.Rdev)))
		devMinor := int64(minor(uint64(st.Rdev)))
		mode := uint32(si.Mode() & 07777)
		if st.Mode&syscall.S_IFMT == syscall.S_IFBLK {
			mode |= syscall.S_IFBLK
		}
		if st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
			mode |= syscall.S_IFCHR
		}
		if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil {
			return err
		}
	}

	// Handle regular files
	if si.Mode().IsRegular() {
		sf, err := os.Open(source)
		if err != nil {
			return err
		}
		defer sf.Close()

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

		_, err = io.Copy(df, sf)
		if err != nil {
			return err
		}
	}

	// Chown the file
	if err := os.Lchown(dest, uid, gid); err != nil {
		return err
	}

	return nil
}

func major(device uint64) uint64 {
	return (device >> 8) & 0xfff
}

func minor(device uint64) uint64 {
	return (device & 0xff) | ((device >> 12) & 0xfff00)
}

func mkdev(major int64, minor int64) uint32 {
	return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
}
<|endoftext|>


<commit_before>package swp

import (
	"fmt"
	"time"

	cv "github.com/glycerine/goconvey/convey"
	"testing"
)

func Test008ProvidesFlowControlToThrottleOverSending(t *testing.T) {

	// Given a consumer able to read at 1k messages/sec,
	// and a producer able to produce at 5k messages/sec,
	// we should see bandwidth across the network at the
	// rate at which the consumer allows via flow-control.
	// i.e.
	// consumer reads at a fixed 20% of the rate at which the
	// producer can produce, then we should see the producer
	// only sending at that 20% rate.
	//
	// implications:
	// and so we should see the internal buffers staying
	// within range. we should never get an error from
	// nats saying that the buffers have overflowed and
	// messages have been dropped.

	// ===============================
	// begin generic nats setup
	// ===============================

	origdir, tempdir := MakeAndMoveToTempDir() // cd to tempdir
	p("origdir = '%s'", origdir)
	p("tempdir = '%s'", tempdir)
	defer TempDirCleanup(origdir, tempdir)

	host := "127.0.0.1"
	port := GetAvailPort()
	gnats := StartGnatsd(host, port)
	defer func() {
		p("calling gnats.Shutdown()")
		gnats.Shutdown() // when done
	}()

	subC := NewNatsClientConfig(host, port, "B", "B", true, true)
	sub := NewNatsClient(subC)
	err := sub.Start()
	panicOn(err)
	defer sub.Close()

	pubC := NewNatsClientConfig(host, port, "A", "A", true, true)
	pub := NewNatsClient(pubC)
	err = pub.Start()
	panicOn(err)
	defer pub.Close()

	anet := NewNatsNet(pub)
	bnet := NewNatsNet(sub)

	q("sub = %#v", sub)
	q("pub = %#v", pub)

	//lossProb := float64(0)
	lat := 1 * time.Millisecond

	rtt := 3 * lat

	A, err := NewSession(anet, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(bnet, "B", "A", 3, rtt)
	B.Swp.Sender.LastFrameSent = 999
	panicOn(err)

	n := 100
	seq := make([]*Packet, n)
	for i := range seq {
		pack := &Packet{
			From: "A",
			Dest: "B",
			Data: []byte(fmt.Sprintf("%v", i)),
		}
		seq[i] = pack
	}

	for i := range seq {
		A.Push(seq[i])
	}

	time.Sleep(1000 * time.Millisecond)

	A.Stop()
	B.Stop()

	// NOT DONE, WORK IN PROGRESS
	cv.Convey("Given a faster sender A and a slower receiver B, flow-control in the SWP should throttle back the sender so it doesn't overwhelm the downstream receiver's buffers", t, func() {
		//cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 100)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 100)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}
<commit_msg>atg. more work on flow control test<commit_after>package swp

import (
	"fmt"
	"time"

	cv "github.com/glycerine/goconvey/convey"
	"testing"
)

func Test008ProvidesFlowControlToThrottleOverSending(t *testing.T) {

	// Given a consumer able to read at 1k messages/sec,
	// and a producer able to produce at 5k messages/sec,
	// we should see bandwidth across the network at the
	// rate at which the consumer allows via flow-control.
	// i.e.
	// consumer reads at a fixed 20% of the rate at which the
	// producer can produce, then we should see the producer
	// only sending at that 20% rate.
	//
	// implications:
	//
	// We should see the internal buffers
	// (in the receiving nats client library) staying
	// within range. We should never get an error from
	// nats saying that the buffers have overflowed and
	// messages have been dropped.

	// ===============================
	// begin generic nats setup
	// ===============================

	origdir, tempdir := MakeAndMoveToTempDir() // cd to tempdir
	p("origdir = '%s'", origdir)
	p("tempdir = '%s'", tempdir)
	defer TempDirCleanup(origdir, tempdir)

	host := "127.0.0.1"
	port := GetAvailPort()
	gnats := StartGnatsd(host, port)
	defer func() {
		p("calling gnats.Shutdown()")
		gnats.Shutdown() // when done
	}()

	// ===============================
	// setup nats clients for a publisher and a subscriber
	// ===============================

	subC := NewNatsClientConfig(host, port, "B", "B", true, true)
	sub := NewNatsClient(subC)
	err := sub.Start()
	panicOn(err)
	defer sub.Close()

	pubC := NewNatsClientConfig(host, port, "A", "A", true, true)
	pub := NewNatsClient(pubC)
	err = pub.Start()
	panicOn(err)
	defer pub.Close()

	// ===============================
	// make a session for each
	// ===============================

	anet := NewNatsNet(pub)
	bnet := NewNatsNet(sub)

	q("sub = %#v", sub)
	q("pub = %#v", pub)

	//lossProb := float64(0)
	lat := 1 * time.Millisecond

	rtt := 3 * lat

	A, err := NewSession(anet, "A", "B", 3, rtt)
	panicOn(err)
	B, err := NewSession(bnet, "B", "A", 3, rtt)
	B.Swp.Sender.LastFrameSent = 999
	panicOn(err)

	// ===============================
	// setup subscriber to consume at 1k/sec
	// ===============================

	// ===============================
	// setup publisher to produce at 5k/sec
	// ===============================

	n := 100
	seq := make([]*Packet, n)
	for i := range seq {
		pack := &Packet{
			From: "A",
			Dest: "B",
			Data: []byte(fmt.Sprintf("%v", i)),
		}
		seq[i] = pack
	}

	for i := range seq {
		A.Push(seq[i])
	}

	time.Sleep(1000 * time.Millisecond)

	A.Stop()
	B.Stop()

	// NOT DONE, WORK IN PROGRESS
	cv.Convey("Given a faster sender A and a slower receiver B, flow-control in the SWP should throttle back the sender so it doesn't overwhelm the downstream receiver's buffers", t, func() {
		//cv.So(A.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		//cv.So(B.Swp.Recver.DiscardCount, cv.ShouldEqual, 0)
		cv.So(len(A.Swp.Sender.SendHistory), cv.ShouldEqual, 100)
		cv.So(len(B.Swp.Recver.RecvHistory), cv.ShouldEqual, 100)
		cv.So(HistoryEqual(A.Swp.Sender.SendHistory, B.Swp.Recver.RecvHistory), cv.ShouldBeTrue)
	})
}
<|endoftext|>


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

package etcdserver

import (
	"fmt"
	"path"
	"sort"
	"strings"
	"time"

	"github.com/coreos/etcd/pkg/netutil"
	"github.com/coreos/etcd/pkg/transport"
	"github.com/coreos/etcd/pkg/types"
)

// ServerConfig holds the configuration of etcd as taken from the command line or discovery.
type ServerConfig struct {
	Name           string
	DiscoveryURL   string
	DiscoveryProxy string
	ClientURLs     types.URLs
	PeerURLs       types.URLs
	DataDir        string
	// DedicatedWALDir config will make the etcd to write the WAL to the WALDir
	// rather than the dataDir/member/wal.
	DedicatedWALDir     string
	SnapCount           uint64
	MaxSnapFiles        uint
	MaxWALFiles         uint
	InitialPeerURLsMap  types.URLsMap
	InitialClusterToken string
	NewCluster          bool
	ForceNewCluster     bool
	PeerTLSInfo         transport.TLSInfo

	TickMs           uint
	ElectionTicks    int
	BootstrapTimeout time.Duration

	AutoCompactionRetention int
	QuotaBackendBytes       int64

	StrictReconfigCheck bool

	EnablePprof bool
}

// VerifyBootstrap sanity-checks the initial config for bootstrap case
// and returns an error for things that should never happen.
func (c *ServerConfig) VerifyBootstrap() error {
	if err := c.verifyLocalMember(true); err != nil {
		return err
	}
	if checkDuplicateURL(c.InitialPeerURLsMap) {
		return fmt.Errorf("initial cluster %s has duplicate url", c.InitialPeerURLsMap)
	}
	if c.InitialPeerURLsMap.String() == "" && c.DiscoveryURL == "" {
		return fmt.Errorf("initial cluster unset and no discovery URL found")
	}
	return nil
}

// VerifyJoinExisting sanity-checks the initial config for join existing cluster
// case and returns an error for things that should never happen.
func (c *ServerConfig) VerifyJoinExisting() error {
	// no need for strict checking since the member have announced its
	// peer urls to the cluster before starting and do not have to set
	// it in the configuration again.
	if err := c.verifyLocalMember(false); err != nil {
		return err
	}
	if checkDuplicateURL(c.InitialPeerURLsMap) {
		return fmt.Errorf("initial cluster %s has duplicate url", c.InitialPeerURLsMap)
	}
	if c.DiscoveryURL != "" {
		return fmt.Errorf("discovery URL should not be set when joining existing initial cluster")
	}
	return nil
}

// verifyLocalMember verifies the configured member is in configured
// cluster. If strict is set, it also verifies the configured member
// has the same peer urls as configured advertised peer urls.
func (c *ServerConfig) verifyLocalMember(strict bool) error {
	urls := c.InitialPeerURLsMap[c.Name]
	// Make sure the cluster at least contains the local server.
	if urls == nil {
		return fmt.Errorf("couldn't find local name %q in the initial cluster configuration", c.Name)
	}

	// Advertised peer URLs must match those in the cluster peer list
	apurls := c.PeerURLs.StringSlice()
	sort.Strings(apurls)
	urls.Sort()
	if strict {
		if !netutil.URLStringsEqual(apurls, urls.StringSlice()) {
			umap := map[string]types.URLs{c.Name: c.PeerURLs}
			return fmt.Errorf("--initial-cluster must include %s given --initial-advertise-peer-urls=%s", types.URLsMap(umap).String(), strings.Join(apurls, ","))
		}
	}
	return nil
}

func (c *ServerConfig) MemberDir() string { return path.Join(c.DataDir, "member") }

func (c *ServerConfig) WALDir() string {
	if c.DedicatedWALDir != "" {
		return c.DedicatedWALDir
	}
	return path.Join(c.MemberDir(), "wal")
}

func (c *ServerConfig) SnapDir() string { return path.Join(c.MemberDir(), "snap") }

func (c *ServerConfig) ShouldDiscover() bool { return c.DiscoveryURL != "" }

// ReqTimeout returns timeout for request to finish.
func (c *ServerConfig) ReqTimeout() time.Duration {
	// 5s for queue waiting, computation and disk IO delay
	// + 2 * election timeout for possible leader election
	return 5*time.Second + 2*time.Duration(c.ElectionTicks)*time.Duration(c.TickMs)*time.Millisecond
}

func (c *ServerConfig) electionTimeout() time.Duration {
	return time.Duration(c.ElectionTicks) * time.Duration(c.TickMs) * time.Millisecond
}

func (c *ServerConfig) peerDialTimeout() time.Duration {
	// 1s for queue wait and system delay
	// + one RTT, which is smaller than 1/5 election timeout
	return time.Second + time.Duration(c.ElectionTicks)*time.Duration(c.TickMs)*time.Millisecond/5
}

func (c *ServerConfig) PrintWithInitial() { c.print(true) }

func (c *ServerConfig) Print() { c.print(false) }

func (c *ServerConfig) print(initial bool) {
	plog.Infof("name = %s", c.Name)
	if c.ForceNewCluster {
		plog.Infof("force new cluster")
	}
	plog.Infof("data dir = %s", c.DataDir)
	plog.Infof("member dir = %s", c.MemberDir())
	if c.DedicatedWALDir != "" {
		plog.Infof("dedicated WAL dir = %s", c.DedicatedWALDir)
	}
	plog.Infof("heartbeat = %dms", c.TickMs)
	plog.Infof("election = %dms", c.ElectionTicks*int(c.TickMs))
	plog.Infof("snapshot count = %d", c.SnapCount)
	if len(c.DiscoveryURL) != 0 {
		plog.Infof("discovery URL= %s", c.DiscoveryURL)
		if len(c.DiscoveryProxy) != 0 {
			plog.Infof("discovery proxy = %s", c.DiscoveryProxy)
		}
	}
	plog.Infof("advertise client URLs = %s", c.ClientURLs)
	if initial {
		plog.Infof("initial advertise peer URLs = %s", c.PeerURLs)
		plog.Infof("initial cluster = %s", c.InitialPeerURLsMap)
	}
}

func checkDuplicateURL(urlsmap types.URLsMap) bool {
	um := make(map[string]bool)
	for _, urls := range urlsmap {
		for _, url := range urls {
			u := url.String()
			if um[u] {
				return true
			}
			um[u] = true
		}
	}
	return false
}

func (c *ServerConfig) bootstrapTimeout() time.Duration {
	if c.BootstrapTimeout != 0 {
		return c.BootstrapTimeout
	}
	return time.Second
}
<commit_msg>etcdserver: add 'ClientCertAuthEnabled' option<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package etcdserver

import (
	"fmt"
	"path"
	"sort"
	"strings"
	"time"

	"github.com/coreos/etcd/pkg/netutil"
	"github.com/coreos/etcd/pkg/transport"
	"github.com/coreos/etcd/pkg/types"
)

// ServerConfig holds the configuration of etcd as taken from the command line or discovery.
type ServerConfig struct {
	Name           string
	DiscoveryURL   string
	DiscoveryProxy string
	ClientURLs     types.URLs
	PeerURLs       types.URLs
	DataDir        string
	// DedicatedWALDir config will make the etcd to write the WAL to the WALDir
	// rather than the dataDir/member/wal.
	DedicatedWALDir     string
	SnapCount           uint64
	MaxSnapFiles        uint
	MaxWALFiles         uint
	InitialPeerURLsMap  types.URLsMap
	InitialClusterToken string
	NewCluster          bool
	ForceNewCluster     bool
	PeerTLSInfo         transport.TLSInfo

	TickMs           uint
	ElectionTicks    int
	BootstrapTimeout time.Duration

	AutoCompactionRetention int
	QuotaBackendBytes       int64

	StrictReconfigCheck bool

	EnablePprof bool

	// ClientCertAuthEnabled is true when cert has been signed by the client CA.
	ClientCertAuthEnabled bool
}

// VerifyBootstrap sanity-checks the initial config for bootstrap case
// and returns an error for things that should never happen.
func (c *ServerConfig) VerifyBootstrap() error {
	if err := c.verifyLocalMember(true); err != nil {
		return err
	}
	if checkDuplicateURL(c.InitialPeerURLsMap) {
		return fmt.Errorf("initial cluster %s has duplicate url", c.InitialPeerURLsMap)
	}
	if c.InitialPeerURLsMap.String() == "" && c.DiscoveryURL == "" {
		return fmt.Errorf("initial cluster unset and no discovery URL found")
	}
	return nil
}

// VerifyJoinExisting sanity-checks the initial config for join existing cluster
// case and returns an error for things that should never happen.
func (c *ServerConfig) VerifyJoinExisting() error {
	// no need for strict checking since the member have announced its
	// peer urls to the cluster before starting and do not have to set
	// it in the configuration again.
	if err := c.verifyLocalMember(false); err != nil {
		return err
	}
	if checkDuplicateURL(c.InitialPeerURLsMap) {
		return fmt.Errorf("initial cluster %s has duplicate url", c.InitialPeerURLsMap)
	}
	if c.DiscoveryURL != "" {
		return fmt.Errorf("discovery URL should not be set when joining existing initial cluster")
	}
	return nil
}

// verifyLocalMember verifies the configured member is in configured
// cluster. If strict is set, it also verifies the configured member
// has the same peer urls as configured advertised peer urls.
func (c *ServerConfig) verifyLocalMember(strict bool) error {
	urls := c.InitialPeerURLsMap[c.Name]
	// Make sure the cluster at least contains the local server.
	if urls == nil {
		return fmt.Errorf("couldn't find local name %q in the initial cluster configuration", c.Name)
	}

	// Advertised peer URLs must match those in the cluster peer list
	apurls := c.PeerURLs.StringSlice()
	sort.Strings(apurls)
	urls.Sort()
	if strict {
		if !netutil.URLStringsEqual(apurls, urls.StringSlice()) {
			umap := map[string]types.URLs{c.Name: c.PeerURLs}
			return fmt.Errorf("--initial-cluster must include %s given --initial-advertise-peer-urls=%s", types.URLsMap(umap).String(), strings.Join(apurls, ","))
		}
	}
	return nil
}

func (c *ServerConfig) MemberDir() string { return path.Join(c.DataDir, "member") }

func (c *ServerConfig) WALDir() string {
	if c.DedicatedWALDir != "" {
		return c.DedicatedWALDir
	}
	return path.Join(c.MemberDir(), "wal")
}

func (c *ServerConfig) SnapDir() string { return path.Join(c.MemberDir(), "snap") }

func (c *ServerConfig) ShouldDiscover() bool { return c.DiscoveryURL != "" }

// ReqTimeout returns timeout for request to finish.
func (c *ServerConfig) ReqTimeout() time.Duration {
	// 5s for queue waiting, computation and disk IO delay
	// + 2 * election timeout for possible leader election
	return 5*time.Second + 2*time.Duration(c.ElectionTicks)*time.Duration(c.TickMs)*time.Millisecond
}

func (c *ServerConfig) electionTimeout() time.Duration {
	return time.Duration(c.ElectionTicks) * time.Duration(c.TickMs) * time.Millisecond
}

func (c *ServerConfig) peerDialTimeout() time.Duration {
	// 1s for queue wait and system delay
	// + one RTT, which is smaller than 1/5 election timeout
	return time.Second + time.Duration(c.ElectionTicks)*time.Duration(c.TickMs)*time.Millisecond/5
}

func (c *ServerConfig) PrintWithInitial() { c.print(true) }

func (c *ServerConfig) Print() { c.print(false) }

func (c *ServerConfig) print(initial bool) {
	plog.Infof("name = %s", c.Name)
	if c.ForceNewCluster {
		plog.Infof("force new cluster")
	}
	plog.Infof("data dir = %s", c.DataDir)
	plog.Infof("member dir = %s", c.MemberDir())
	if c.DedicatedWALDir != "" {
		plog.Infof("dedicated WAL dir = %s", c.DedicatedWALDir)
	}
	plog.Infof("heartbeat = %dms", c.TickMs)
	plog.Infof("election = %dms", c.ElectionTicks*int(c.TickMs))
	plog.Infof("snapshot count = %d", c.SnapCount)
	if len(c.DiscoveryURL) != 0 {
		plog.Infof("discovery URL= %s", c.DiscoveryURL)
		if len(c.DiscoveryProxy) != 0 {
			plog.Infof("discovery proxy = %s", c.DiscoveryProxy)
		}
	}
	plog.Infof("advertise client URLs = %s", c.ClientURLs)
	if initial {
		plog.Infof("initial advertise peer URLs = %s", c.PeerURLs)
		plog.Infof("initial cluster = %s", c.InitialPeerURLsMap)
	}
}

func checkDuplicateURL(urlsmap types.URLsMap) bool {
	um := make(map[string]bool)
	for _, urls := range urlsmap {
		for _, url := range urls {
			u := url.String()
			if um[u] {
				return true
			}
			um[u] = true
		}
	}
	return false
}

func (c *ServerConfig) bootstrapTimeout() time.Duration {
	if c.BootstrapTimeout != 0 {
		return c.BootstrapTimeout
	}
	return time.Second
}
<|endoftext|>