<commit_before>package restful

// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

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

// Added by apoorva moghey to generate custom response format
type Rejoinder struct {
    Success     bool   `json:"success"`
    ErrorCode   int    `json:"error_code,omitempty"`
    Message     string `json:"message"`
    TotalPage   int    `json:"total_page,omitempty"`
    CurrentPage int    `json:"current_page,omitempty"`
    Total       int    `json:"total,omitempty"`
}

// DEPRECATED, use DefaultResponseContentType(mime)
var DefaultResponseMimeType string

//PrettyPrintResponses controls the indentation feature of XML and JSON
//serialization in the response methods WriteEntity, WriteAsJson, and
//WriteAsXml.
var PrettyPrintResponses = true

// Response is a wrapper on the actual http ResponseWriter
// It provides several convenience methods to prepare and write response content.
type Response struct {
    http.ResponseWriter
    requestAccept string   // mime-type what the Http Request says it wants to receive
    routeProduces []string // mime-types what the Route says it can produce
    statusCode    int      // HTTP status code that has been written explicity (if zero then net/http has written 200)
    contentLength int      // number of bytes written for the response body
    prettyPrint   bool     // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses.
    Data          interface{}
    Source        string
}

// Creates a new response based on a http ResponseWriter.
func NewResponse(httpWriter http.ResponseWriter) *Response {
    return &Response{
        httpWriter,
        "",
        []string{},
        http.StatusOK,
        0,
        PrettyPrintResponses, nil, ""} // empty content-types
}

// If Accept header matching fails, fall back to this type, otherwise
// a "406: Not Acceptable" response is returned.
// Valid values are restful.MIME_JSON and restful.MIME_XML
// Example:
// 	restful.DefaultResponseContentType(restful.MIME_JSON)
func DefaultResponseContentType(mime string) {
    DefaultResponseMimeType = mime
}

// InternalServerError writes the StatusInternalServerError header.
// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason)
func (r Response) InternalServerError() Response {
    r.WriteHeader(http.StatusInternalServerError)
    return r
}

// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output.
func (r *Response) PrettyPrint(bePretty bool) {
    r.prettyPrint = bePretty
}

// AddHeader is a shortcut for .Header().Add(header,value)
func (r Response) AddHeader(header string, value string) Response {
    r.Header().Add(header, value)
    return r
}

// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing.
func (r *Response) SetRequestAccepts(mime string) {
    r.requestAccept = mime
}

// WriteEntity marshals the value using the representation denoted by the Accept Header (XML or JSON)
// If no Accept header is specified (or */*) then return the Content-Type as specified by the first in the Route.Produces.
// If an Accept header is specified then return the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
// If the value is nil then nothing is written. You may want to call WriteHeader(http.StatusNotFound) instead.
// Current implementation ignores any q-parameters in the Accept Header.
func (r *Response) WriteEntity(value interface{}) error {
    if r.Source == "external" {
        r.Data = value
        r.Source = ""
        return nil
    }

    if value == nil { // do not write a nil representation
        return nil
    }
    for _, qualifiedMime := range strings.Split(r.requestAccept, ",") {
        mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ")
        if 0 == len(mime) || mime == "*/*" {
            for _, each := range r.routeProduces {
                if MIME_JSON == each {
                    return r.WriteAsJson(value)
                }
                if MIME_XML == each {
                    return r.WriteAsXml(value)
                }
            }
        } else { // mime is not blank; see if we have a match in Produces
            for _, each := range r.routeProduces {
                if mime == each {
                    if MIME_JSON == each {
                        return r.WriteAsJson(value)
                    }
                    if MIME_XML == each {
                        return r.WriteAsXml(value)
                    }
                }
            }
        }
    }
    if DefaultResponseMimeType == MIME_JSON {
        return r.WriteAsJson(value)
    } else if DefaultResponseMimeType == MIME_XML {
        return r.WriteAsXml(value)
    } else {
        if trace {
            traceLogger.Printf("mismatch in mime-types and no defaults; (http)Accept=%v,(route)Produces=%v\n", r.requestAccept, r.routeProduces)
        }
        r.WriteHeader(http.StatusNotAcceptable) // for recording only
        r.ResponseWriter.WriteHeader(http.StatusNotAcceptable)
        if _, err := r.Write([]byte("406: Not Acceptable")); err != nil {
            return err
        }
    }
    return nil
}

// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
func (r *Response) WriteAsXml(value interface{}) error {
    var output []byte
    var err error

    if value == nil { // do not write a nil representation
        return nil
    }
    if r.prettyPrint {
        output, err = xml.MarshalIndent(value, " ", " ")
    } else {
        output, err = xml.Marshal(value)
    }

    if err != nil {
        return r.WriteError(http.StatusInternalServerError, err)
    }
    r.Header().Set(HEADER_ContentType, MIME_XML)
    if r.statusCode > 0 { // a WriteHeader was intercepted
        r.ResponseWriter.WriteHeader(r.statusCode)
    }
    _, err = r.Write([]byte(xml.Header))
    if err != nil {
        return err
    }
    if _, err = r.Write(output); err != nil {
        return err
    }
    return nil
}

// WriteAsJson is a convenience method for writing a value in json
func (r *Response) WriteAsJson(value interface{}) error {
    var output []byte
    var err error

    if value == nil { // do not write a nil representation
        return nil
    }
    if r.prettyPrint {
        output, err = json.MarshalIndent(value, " ", " ")
    } else {
        output, err = json.Marshal(value)
    }

    if err != nil {
        return r.WriteErrorString(http.StatusInternalServerError, err.Error())
    }
    r.Header().Set(HEADER_ContentType, MIME_JSON)
    if r.statusCode > 0 { // a WriteHeader was intercepted
        r.ResponseWriter.WriteHeader(r.statusCode)
    }
    if _, err = r.Write(output); err != nil {
        return err
    }
    return nil
}

// WriteError write the http status and the error string on the response.
func (r *Response) WriteError(httpStatus int, err error) error {
    return r.WriteErrorString(httpStatus, err.Error())
}

// WriteServiceError is a convenience method for a responding with a ServiceError and a status
func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
    r.WriteHeader(httpStatus) // for recording only
    return r.WriteEntity(err)
}

// WriteErrorString is a convenience method for an error status with the actual error
func (r *Response) WriteErrorString(status int, errorReason string) error {
    r.statusCode = status // for recording only
    r.ResponseWriter.WriteHeader(status)
    if _, err := r.Write([]byte(errorReason)); err != nil {
        return err
    }
    return nil
}

// WriteHeader is overridden to remember the Status Code that has been written.
// Note that using this method, the status value is only written when
// - calling WriteEntity,
// - or directly calling WriteAsXml or WriteAsJson,
// - or if the status is one for which no response is allowed (i.e.,
//   204 (http.StatusNoContent) or 304 (http.StatusNotModified))
func (r *Response) WriteHeader(httpStatus int) {
    r.statusCode = httpStatus
    // if 204 then WriteEntity will not be called so we need to pass this code
    if http.StatusNoContent == httpStatus ||
        http.StatusNotModified == httpStatus {
        r.ResponseWriter.WriteHeader(httpStatus)
    }
}

// StatusCode returns the code that has been written using WriteHeader.
func (r Response) StatusCode() int {
    if 0 == r.statusCode {
        // no status code has been written yet; assume OK
        return http.StatusOK
    }
    return r.statusCode
}

// Write writes the data to the connection as part of an HTTP reply.
// Write is part of http.ResponseWriter interface.
func (r *Response) Write(bytes []byte) (int, error) {
    written, err := r.ResponseWriter.Write(bytes)
    r.contentLength += written
    return written, err
}

// ContentLength returns the number of bytes written for the response content.
// Note that this value is only correct if all data is written through the Response using its Write* methods.
// Data written directly using the underlying http.ResponseWriter is not accounted for.
func (r Response) ContentLength() int {
    return r.contentLength
}

// CloseNotify is part of http.CloseNotifier interface
func (r Response) CloseNotify() <-chan bool {
    return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
}
<commit_msg>add fallacy struct<commit_after>package restful

// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

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

// Added by apoorva moghey to generate custom response format
type Rejoinder struct {
    Success     bool   `json:"success"`
    ErrorCode   int    `json:"error_code,omitempty"`
    Message     string `json:"message"`
    TotalPage   int    `json:"total_page,omitempty"`
    CurrentPage int    `json:"current_page,omitempty"`
    Total       int    `json:"total,omitempty"`
}

// Added by apoorva moghey to generate custom response format
type Fallacy struct {
    Success   bool   `json:"success"`
    ErrorCode int    `json:"error_code,omitempty"`
    Message   string `json:"message"`
}

// DEPRECATED, use DefaultResponseContentType(mime)
var DefaultResponseMimeType string

//PrettyPrintResponses controls the indentation feature of XML and JSON
//serialization in the response methods WriteEntity, WriteAsJson, and
//WriteAsXml.
var PrettyPrintResponses = true

// Response is a wrapper on the actual http ResponseWriter
// It provides several convenience methods to prepare and write response content.
type Response struct {
    http.ResponseWriter
    requestAccept string   // mime-type what the Http Request says it wants to receive
    routeProduces []string // mime-types what the Route says it can produce
    statusCode    int      // HTTP status code that has been written explicity (if zero then net/http has written 200)
    contentLength int      // number of bytes written for the response body
    prettyPrint   bool     // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses.
    Data          interface{}
    Source        string
}

// Creates a new response based on a http ResponseWriter.
func NewResponse(httpWriter http.ResponseWriter) *Response {
    return &Response{
        httpWriter,
        "",
        []string{},
        http.StatusOK,
        0,
        PrettyPrintResponses, nil, ""} // empty content-types
}

// If Accept header matching fails, fall back to this type, otherwise
// a "406: Not Acceptable" response is returned.
// Valid values are restful.MIME_JSON and restful.MIME_XML
// Example:
// 	restful.DefaultResponseContentType(restful.MIME_JSON)
func DefaultResponseContentType(mime string) {
    DefaultResponseMimeType = mime
}

// InternalServerError writes the StatusInternalServerError header.
// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason)
func (r Response) InternalServerError() Response {
    r.WriteHeader(http.StatusInternalServerError)
    return r
}

// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output.
func (r *Response) PrettyPrint(bePretty bool) {
    r.prettyPrint = bePretty
}

// AddHeader is a shortcut for .Header().Add(header,value)
func (r Response) AddHeader(header string, value string) Response {
    r.Header().Add(header, value)
    return r
}

// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing.
func (r *Response) SetRequestAccepts(mime string) {
    r.requestAccept = mime
}

// WriteEntity marshals the value using the representation denoted by the Accept Header (XML or JSON)
// If no Accept header is specified (or */*) then return the Content-Type as specified by the first in the Route.Produces.
// If an Accept header is specified then return the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
// If the value is nil then nothing is written. You may want to call WriteHeader(http.StatusNotFound) instead.
// Current implementation ignores any q-parameters in the Accept Header.
func (r *Response) WriteEntity(value interface{}) error {
    if r.Source == "external" {
        r.Data = value
        r.Source = ""
        return nil
    }

    if value == nil { // do not write a nil representation
        return nil
    }
    for _, qualifiedMime := range strings.Split(r.requestAccept, ",") {
        mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ")
        if 0 == len(mime) || mime == "*/*" {
            for _, each := range r.routeProduces {
                if MIME_JSON == each {
                    return r.WriteAsJson(value)
                }
                if MIME_XML == each {
                    return r.WriteAsXml(value)
                }
            }
        } else { // mime is not blank; see if we have a match in Produces
            for _, each := range r.routeProduces {
                if mime == each {
                    if MIME_JSON == each {
                        return r.WriteAsJson(value)
                    }
                    if MIME_XML == each {
                        return r.WriteAsXml(value)
                    }
                }
            }
        }
    }
    if DefaultResponseMimeType == MIME_JSON {
        return r.WriteAsJson(value)
    } else if DefaultResponseMimeType == MIME_XML {
        return r.WriteAsXml(value)
    } else {
        if trace {
            traceLogger.Printf("mismatch in mime-types and no defaults; (http)Accept=%v,(route)Produces=%v\n", r.requestAccept, r.routeProduces)
        }
        r.WriteHeader(http.StatusNotAcceptable) // for recording only
        r.ResponseWriter.WriteHeader(http.StatusNotAcceptable)
        if _, err := r.Write([]byte("406: Not Acceptable")); err != nil {
            return err
        }
    }
    return nil
}

// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
func (r *Response) WriteAsXml(value interface{}) error {
    var output []byte
    var err error

    if value == nil { // do not write a nil representation
        return nil
    }
    if r.prettyPrint {
        output, err = xml.MarshalIndent(value, " ", " ")
    } else {
        output, err = xml.Marshal(value)
    }

    if err != nil {
        return r.WriteError(http.StatusInternalServerError, err)
    }
    r.Header().Set(HEADER_ContentType, MIME_XML)
    if r.statusCode > 0 { // a WriteHeader was intercepted
        r.ResponseWriter.WriteHeader(r.statusCode)
    }
    _, err = r.Write([]byte(xml.Header))
    if err != nil {
        return err
    }
    if _, err = r.Write(output); err != nil {
        return err
    }
    return nil
}

// WriteAsJson is a convenience method for writing a value in json
func (r *Response) WriteAsJson(value interface{}) error {
    var output []byte
    var err error

    if value == nil { // do not write a nil representation
        return nil
    }
    if r.prettyPrint {
        output, err = json.MarshalIndent(value, " ", " ")
    } else {
        output, err = json.Marshal(value)
    }

    if err != nil {
        return r.WriteErrorString(http.StatusInternalServerError, err.Error())
    }
    r.Header().Set(HEADER_ContentType, MIME_JSON)
    if r.statusCode > 0 { // a WriteHeader was intercepted
        r.ResponseWriter.WriteHeader(r.statusCode)
    }
    if _, err = r.Write(output); err != nil {
        return err
    }
    return nil
}

// WriteError write the http status and the error string on the response.
func (r *Response) WriteError(httpStatus int, err error) error {
    return r.WriteErrorString(httpStatus, err.Error())
}

// WriteServiceError is a convenience method for a responding with a ServiceError and a status
func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
    r.WriteHeader(httpStatus) // for recording only
    return r.WriteEntity(err)
}

// WriteErrorString is a convenience method for an error status with the actual error
func (r *Response) WriteErrorString(status int, errorReason string) error {
    r.statusCode = status // for recording only
    r.ResponseWriter.WriteHeader(status)
    if _, err := r.Write([]byte(errorReason)); err != nil {
        return err
    }
    return nil
}

// WriteHeader is overridden to remember the Status Code that has been written.
// Note that using this method, the status value is only written when
// - calling WriteEntity,
// - or directly calling WriteAsXml or WriteAsJson,
// - or if the status is one for which no response is allowed (i.e.,
//   204 (http.StatusNoContent) or 304 (http.StatusNotModified))
func (r *Response) WriteHeader(httpStatus int) {
    r.statusCode = httpStatus
    // if 204 then WriteEntity will not be called so we need to pass this code
    if http.StatusNoContent == httpStatus ||
        http.StatusNotModified == httpStatus {
        r.ResponseWriter.WriteHeader(httpStatus)
    }
}

// StatusCode returns the code that has been written using WriteHeader.
func (r Response) StatusCode() int {
    if 0 == r.statusCode {
        // no status code has been written yet; assume OK
        return http.StatusOK
    }
    return r.statusCode
}

// Write writes the data to the connection as part of an HTTP reply.
// Write is part of http.ResponseWriter interface.
func (r *Response) Write(bytes []byte) (int, error) {
    written, err := r.ResponseWriter.Write(bytes)
    r.contentLength += written
    return written, err
}

// ContentLength returns the number of bytes written for the response content.
// Note that this value is only correct if all data is written through the Response using its Write* methods.
// Data written directly using the underlying http.ResponseWriter is not accounted for.
func (r Response) ContentLength() int {
    return r.contentLength
}

// CloseNotify is part of http.CloseNotifier interface
func (r Response) CloseNotify() <-chan bool {
    return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

func (r *Response) RemoveSource() {
    r.Source = ""
}

func (r *Response) WriteResp(value interface{}) error {
    if value == nil { // do not write a nil representation
        return nil
    }
    for _, qualifiedMime := range strings.Split(r.requestAccept, ",") {
        mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ")
        if 0 == len(mime) || mime == "*/*" {
            for _, each := range r.routeProduces {
                if MIME_JSON == each {
                    return r.WriteAsJson(value)
                }
                if MIME_XML == each {
                    return r.WriteAsXml(value)
                }
            }
        } else { // mime is not blank; see if we have a match in Produces
            for _, each := range r.routeProduces {
                if mime == each {
                    if MIME_JSON == each {
                        return r.WriteAsJson(value)
                    }
                    if MIME_XML == each {
                        return r.WriteAsXml(value)
                    }
                }
            }
        }
    }
    if DefaultResponseMimeType == MIME_JSON {
        return r.WriteAsJson(value)
    } else if DefaultResponseMimeType == MIME_XML {
        return r.WriteAsXml(value)
    } else {
        if trace {
            traceLogger.Printf("mismatch in mime-types and no defaults; (http)Accept=%v,(route)Produces=%v\n", r.requestAccept, r.routeProduces)
        }
        r.WriteHeader(http.StatusNotAcceptable) // for recording only
        r.ResponseWriter.WriteHeader(http.StatusNotAcceptable)
        if _, err := r.Write([]byte("406: Not Acceptable")); err != nil {
            return err
        }
    }
    return nil
}
<|endoftext|>


<commit_before>package whois

import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"net/mail"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/saintfish/chardet"
	"golang.org/x/net/html/charset"
	"golang.org/x/text/encoding"
	"golang.org/x/text/transform"
)

// Response represents a whois response from a server.
type Response struct {
	// Query and Host are copied from the Request.
	Query string
	Host  string

	// FetchedAt is the date and time the response was fetched from the server.
	FetchedAt time.Time

	// MediaType and Charset hold the MIME-type and character set of the response body.
	MediaType string
	Charset   string

	// Body contains the raw bytes of the network response (minus HTTP headers).
	Body []byte
}

// NewResponse initializes a new whois response.
func NewResponse(query, host string) *Response {
	return &Response{
		Query:     query,
		Host:      host,
		FetchedAt: time.Now().UTC(),
	}
}

// Adapter returns an appropriate Adapter for the Response.
func (res *Response) Adapter() Adapter {
	return adapterFor(res.Host)
}

// String returns a string representation of the response text.
// Returns an empty string if an error occurs.
func (res *Response) String() string {
	text, err := res.Text()
	if err != nil {
		return ""
	}
	return string(text)
}

// Text returns the UTF-8 text content from the response body
// or any errors that occur while decoding.
func (res *Response) Text() ([]byte, error) {
	return res.Adapter().Text(res)
}

// Reader returns a new UTF-8 io.Reader for the response body.
func (res *Response) Reader() (io.Reader, error) {
	enc, err := res.Encoding()
	if err != nil {
		return nil, err
	}
	return transform.NewReader(bytes.NewReader(res.Body), enc.NewDecoder()), nil
}

// Encoding returns an Encoding for the response body.
func (res *Response) Encoding() (encoding.Encoding, error) {
	enc, _ := charset.Lookup(res.Charset)
	if enc == nil {
		return nil, fmt.Errorf("no encoding found for %s", res.Charset)
	}
	return enc, nil
}

// DetectContentType detects and sets the response content type and charset.
func (res *Response) DetectContentType(ct string) {
	// Sensible defaults
	res.MediaType = "text/plain"
	res.Charset = ""

	// Autodetect if not passed a Content-Type header
	if ct == "" {
		ct = http.DetectContentType(res.Body)
	}

	// Content type (e.g. text/plain or text/html)
	mt, params, err := mime.ParseMediaType(ct)
	if err != nil {
		return
	}
	res.MediaType = mt

	// Character set (e.g. utf-8)
	cs, ok := params["charset"]
	if ok {
		res.Charset = cs
	}
	res.DetectCharset()
}

// DetectCharset returns best guess for the reesponse body character set.
func (res *Response) DetectCharset() {
	// Detect via BOM / HTML meta tag
	_, cs1, ok1 := charset.DetermineEncoding(res.Body, res.MediaType)

	// Detect via ICU
	cs2, ok2, html := "", false, false
	var det *chardet.Detector
	if strings.Contains(res.MediaType, "html") || true {
		det = chardet.NewHtmlDetector()
		html = true
	} else {
		det = chardet.NewTextDetector()
	}
	r, err := det.DetectAll(res.Body)
	if err == nil && len(r) > 0 {
		cs2 = strings.ToLower(r[0].Charset)
		ok2 = r[0].Confidence > 50
	}

	// Prefer charset if HTML, otherwise ICU
	if !ok2 && (ok1 || html) {
		res.Charset = cs1
	} else {
		res.Charset = cs2
	}

	// fmt.Printf("Detected charset via go.net/html/charset: %s (%t)\n", cs1, ok1)
	// fmt.Printf("Detected charset via saintfish/chardet:   %s (%d)\n", cs2, r[0].Confidence)
}

// Checksum returns a hex-encoded SHA-1 checksum of the response Body.
func (res *Response) Checksum() string {
	h := sha1.New()
	h.Write(res.Body)
	return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}

// Header returns a stringproto header representing the response.
func (res *Response) Header() http.Header {
	h := make(http.Header)
	h.Set("Query", res.Query)
	h.Set("Host", res.Host)
	h.Set("Fetched-At", res.FetchedAt.Format(time.RFC3339))
	h.Set("Content-Type", res.ContentType())
	h.Set("Content-Length", strconv.Itoa(len(res.Body)))
	h.Set("Content-Checksum", res.Checksum())
	return h
}

// ContentType returns an RFC 2045 compatible internet media type string.
func (res *Response) ContentType() string {
	return mime.FormatMediaType(res.MediaType, map[string]string{"charset": res.Charset})
}

// WriteMIME writes a MIME-formatted representation of the response to an io.Writer.
func (res *Response) WriteMIME(w io.Writer) error {
	io.WriteString(w, "MIME-Version: 1.0\r\n")
	err := res.Header().Write(w)
	if err != nil {
		return err
	}
	_, err = io.WriteString(w, "\r\n")
	if err != nil {
		return err
	}
	_, err = w.Write(res.Body)
	if err != nil {
		return err
	}
	return nil
}

// ReadMIME reads a MIME-formatted representation of the response into a Response.
func ReadMIME(r io.Reader) (*Response, error) {
	msg, err := mail.ReadMessage(r)
	if err != nil {
		return nil, err
	}
	h := msg.Header
	res := NewResponse(h.Get("Query"), h.Get("Host"))
	if res.Body, err = ioutil.ReadAll(msg.Body); err != nil {
		return res, err
	}
	if res.FetchedAt, err = time.Parse(time.RFC3339, h.Get("Fetched-At")); err != nil {
		return res, err
	}
	mt, params, err := mime.ParseMediaType(h.Get("Content-Type"))
	if err != nil {
		return res, err
	}
	res.MediaType = mt
	res.Charset = params["charset"]
	return res, nil
}

// ReadMIMEFile opens and reads a response MIME file at path.
// Returns any errors.
func ReadMIMEFile(path string) (*Response, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return ReadMIME(f)
}
<commit_msg>default Response.MediaType and Charset<commit_after>package whois

import (
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"net/mail"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/saintfish/chardet"
	"golang.org/x/net/html/charset"
	"golang.org/x/text/encoding"
	"golang.org/x/text/transform"
)

// Response represents a whois response from a server.
type Response struct {
	// Query and Host are copied from the Request.
	Query string
	Host  string

	// FetchedAt is the date and time the response was fetched from the server.
	FetchedAt time.Time

	// MediaType and Charset hold the MIME-type and character set of the response body.
	MediaType string
	Charset   string

	// Body contains the raw bytes of the network response (minus HTTP headers).
	Body []byte
}

// NewResponse initializes a new whois response.
func NewResponse(query, host string) *Response {
	return &Response{
		Query:     query,
		Host:      host,
		FetchedAt: time.Now().UTC(),
		MediaType: "text/plain",
		Charset:   "utf-8",
	}
}

// Adapter returns an appropriate Adapter for the Response.
func (res *Response) Adapter() Adapter {
	return adapterFor(res.Host)
}

// String returns a string representation of the response text.
// Returns an empty string if an error occurs.
func (res *Response) String() string {
	text, err := res.Text()
	if err != nil {
		return ""
	}
	return string(text)
}

// Text returns the UTF-8 text content from the response body
// or any errors that occur while decoding.
func (res *Response) Text() ([]byte, error) {
	return res.Adapter().Text(res)
}

// Reader returns a new UTF-8 io.Reader for the response body.
func (res *Response) Reader() (io.Reader, error) {
	enc, err := res.Encoding()
	if err != nil {
		return nil, err
	}
	return transform.NewReader(bytes.NewReader(res.Body), enc.NewDecoder()), nil
}

// Encoding returns an Encoding for the response body.
func (res *Response) Encoding() (encoding.Encoding, error) {
	enc, _ := charset.Lookup(res.Charset)
	if enc == nil {
		return nil, fmt.Errorf("no encoding found for %s", res.Charset)
	}
	return enc, nil
}

// DetectContentType detects and sets the response content type and charset.
func (res *Response) DetectContentType(ct string) {
	// Autodetect if not passed a Content-Type header
	if ct == "" {
		ct = http.DetectContentType(res.Body)
	}

	// Content type (e.g. text/plain or text/html)
	mt, params, err := mime.ParseMediaType(ct)
	if err != nil {
		return
	}
	res.MediaType = mt

	// Character set (e.g. utf-8)
	cs, ok := params["charset"]
	if ok {
		res.Charset = cs
	}
	res.DetectCharset()
}

// DetectCharset returns best guess for the reesponse body character set.
func (res *Response) DetectCharset() {
	// Detect via BOM / HTML meta tag
	_, cs1, ok1 := charset.DetermineEncoding(res.Body, res.MediaType)

	// Detect via ICU
	cs2, ok2, html := "", false, false
	var det *chardet.Detector
	if strings.Contains(res.MediaType, "html") || true {
		det = chardet.NewHtmlDetector()
		html = true
	} else {
		det = chardet.NewTextDetector()
	}
	r, err := det.DetectAll(res.Body)
	if err == nil && len(r) > 0 {
		cs2 = strings.ToLower(r[0].Charset)
		ok2 = r[0].Confidence > 50
	}

	// Prefer charset if HTML, otherwise ICU
	if !ok2 && (ok1 || html) {
		res.Charset = cs1
	} else {
		res.Charset = cs2
	}

	// fmt.Printf("Detected charset via go.net/html/charset: %s (%t)\n", cs1, ok1)
	// fmt.Printf("Detected charset via saintfish/chardet:   %s (%d)\n", cs2, r[0].Confidence)
}

// Checksum returns a hex-encoded SHA-1 checksum of the response Body.
func (res *Response) Checksum() string {
	h := sha1.New()
	h.Write(res.Body)
	return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
}

// Header returns a stringproto header representing the response.
func (res *Response) Header() http.Header {
	h := make(http.Header)
	h.Set("Query", res.Query)
	h.Set("Host", res.Host)
	h.Set("Fetched-At", res.FetchedAt.Format(time.RFC3339))
	h.Set("Content-Type", res.ContentType())
	h.Set("Content-Length", strconv.Itoa(len(res.Body)))
	h.Set("Content-Checksum", res.Checksum())
	return h
}

// ContentType returns an RFC 2045 compatible internet media type string.
func (res *Response) ContentType() string {
	return mime.FormatMediaType(res.MediaType, map[string]string{"charset": res.Charset})
}

// WriteMIME writes a MIME-formatted representation of the response to an io.Writer.
func (res *Response) WriteMIME(w io.Writer) error {
	io.WriteString(w, "MIME-Version: 1.0\r\n")
	err := res.Header().Write(w)
	if err != nil {
		return err
	}
	_, err = io.WriteString(w, "\r\n")
	if err != nil {
		return err
	}
	_, err = w.Write(res.Body)
	if err != nil {
		return err
	}
	return nil
}

// ReadMIME reads a MIME-formatted representation of the response into a Response.
func ReadMIME(r io.Reader) (*Response, error) {
	msg, err := mail.ReadMessage(r)
	if err != nil {
		return nil, err
	}
	h := msg.Header
	res := NewResponse(h.Get("Query"), h.Get("Host"))
	if res.Body, err = ioutil.ReadAll(msg.Body); err != nil {
		return res, err
	}
	if res.FetchedAt, err = time.Parse(time.RFC3339, h.Get("Fetched-At")); err != nil {
		return res, err
	}
	mt, params, err := mime.ParseMediaType(h.Get("Content-Type"))
	if err != nil {
		return res, err
	}
	res.MediaType = mt
	res.Charset = params["charset"]
	return res, nil
}

// ReadMIMEFile opens and reads a response MIME file at path.
// Returns any errors.
func ReadMIMEFile(path string) (*Response, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return ReadMIME(f)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"mqtt"
)

type mqtts_listener struct {
	provider mqtt.Provider
}

func newListener(provider mqtt.Provider) *mqtts_listener {
	return &mqtts_listener{provider}
}
func (this *mqtts_listener) ProcessConnect(eventConnect mqtt.EventConnect) {
	log.Println("Received CONNECT")
	serverSession := eventConnect.GetSession().(mqtt.ServerSession)

	pktconnack := mqtt.NewPacketConnack()
	pktconnack.SetSPFlag(false)
	pktconnack.SetReturnCode(mqtt.CONNACK_RETURNCODE_ACCEPTED)

	serverSession.Acknowledge(pktconnack)
}
func (this *mqtts_listener) ProcessPublish(eventPublish mqtt.EventPublish) {

}
func (this *mqtts_listener) ProcessSubscribe(eventSubscribe mqtt.EventSubscribe) {
	log.Printf("Received SUBSCRIBE with %v", eventSubscribe.GetSubscribeTopics())
	serverSession := eventSubscribe.GetSession().(mqtt.ServerSession)

	pktsuback := mqtt.NewPacketSuback()
	pktsuback.SetPacketId(eventSubscribe.GetPacketId())
	qos := eventSubscribe.GetQoSs()
	retCodes := make([]byte, len(qos))
	for i := 0; i < len(qos); i++ {
		retCodes[i] = byte(qos[i])
	}
	pktsuback.SetReturnCodes(retCodes)

	serverSession.Acknowledge(pktsuback)
}
func (this *mqtts_listener) ProcessUnsubscribe(eventUnsubscribe mqtt.EventUnsubscribe) {
	log.Printf("Received UNSUBSCRIBE with %v", eventUnsubscribe.GetUnsubscribeTopics())
}

func (this *mqtts_listener) ProcessTimeout(eventTimeout mqtt.EventTimeout) {
	log.Println("Received Timeout")
}
func (this *mqtts_listener) ProcessIOException(eventIOException mqtt.EventIOException) {
	log.Println("Received IOException")
}
func (this *mqtts_listener) ProcessSessionTerminated(eventSessionTerminated mqtt.EventSessionTerminated) {
	log.Println("Session Terminated with Reason: ", eventSessionTerminated.GetReason())
}
<commit_msg>add publish<commit_after>package main

import (
	"log"
	"mqtt"
)

type mqtts_listener struct {
	provider mqtt.Provider
}

func newListener(provider mqtt.Provider) *mqtts_listener {
	return &mqtts_listener{provider}
}
func (this *mqtts_listener) ProcessConnect(eventConnect mqtt.EventConnect) {
	log.Println("Received CONNECT")
	serverSession := eventConnect.GetSession().(mqtt.ServerSession)

	pktconnack := mqtt.NewPacketConnack()
	pktconnack.SetSPFlag(false)
	pktconnack.SetReturnCode(mqtt.CONNACK_RETURNCODE_ACCEPTED)

	serverSession.Acknowledge(pktconnack)
}
func (this *mqtts_listener) ProcessPublish(eventPublish mqtt.EventPublish) {
	log.Printf("Received Publish with DUP %v QoS %v RETAIN %v Topic: %v\n",
		eventPublish.GetMessage().GetDup(),
		eventPublish.GetMessage().GetQos(),
		eventPublish.GetMessage().GetRetain(),
		eventPublish.GetMessage().GetTopic())
}
func (this *mqtts_listener) ProcessSubscribe(eventSubscribe mqtt.EventSubscribe) {
	log.Printf("Received SUBSCRIBE with %v", eventSubscribe.GetSubscribeTopics())
	serverSession := eventSubscribe.GetSession().(mqtt.ServerSession)

	pktsuback := mqtt.NewPacketSuback()
	pktsuback.SetPacketId(eventSubscribe.GetPacketId())
	qos := eventSubscribe.GetQoSs()
	retCodes := make([]byte, len(qos))
	for i := 0; i < len(qos); i++ {
		retCodes[i] = byte(qos[i])
	}
	pktsuback.SetReturnCodes(retCodes)

	serverSession.Acknowledge(pktsuback)
}
func (this *mqtts_listener) ProcessUnsubscribe(eventUnsubscribe mqtt.EventUnsubscribe) {
	log.Printf("Received UNSUBSCRIBE with %v", eventUnsubscribe.GetUnsubscribeTopics())
}

func (this *mqtts_listener) ProcessTimeout(eventTimeout mqtt.EventTimeout) {
	log.Println("Received Timeout")
}
func (this *mqtts_listener) ProcessIOException(eventIOException mqtt.EventIOException) {
	log.Println("Received IOException")
}
func (this *mqtts_listener) ProcessSessionTerminated(eventSessionTerminated mqtt.EventSessionTerminated) {
	log.Println("Session Terminated with Reason: ", eventSessionTerminated.GetReason())
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Workiva, LLC

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 rest

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"sort"
	"sync"

	"github.com/gorilla/mux"
)

const (
	defaultLogPrefix     = "rest "
	defaultDocsDirectory = "_docs/"
)

// Address is the address and port to bind to (e.g. ":8080").
type Address string

// FilePath represents a file path.
type FilePath string

// Configuration contains settings for configuring an API.
type Configuration struct {
	Debug         bool
	Logger        *log.Logger
	GenerateDocs  bool
	DocsDirectory string
}

// Debugf prints the formatted string to the Configuration Logger if Debug is enabled.
func (c *Configuration) Debugf(format string, v ...interface{}) {
	if c.Debug {
		c.Logger.Printf(format, v)
	}
}

// NewConfiguration returns a default Configuration.
func NewConfiguration() *Configuration {
	logger := log.New(os.Stdout, defaultLogPrefix, log.LstdFlags)
	return &Configuration{
		Debug:         true,
		Logger:        logger,
		GenerateDocs:  true,
		DocsDirectory: defaultDocsDirectory,
	}
}

// Middleware can be passed in to API#Start and API#StartTLS and will be
// invoked on every request to a route handled by the API. Returns true if the
// request should be terminated, false if it should continue.
type Middleware func(w http.ResponseWriter, r *http.Request) bool

// middlewareProxy proxies an http.Handler by invoking middleware before
// passing the request to the Handler. It implements the http.Handler
// interface.
type middlewareProxy struct {
	handler    http.Handler
	middleware []Middleware
}

// ServeHTTP invokes middleware on the request and then delegates to the
// proxied http.Handler.
func (m *middlewareProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	for _, middleware := range m.middleware {
		if middleware(w, r) {
			return
		}
	}
	m.handler.ServeHTTP(w, r)
}

// wrapMiddleware returns an http.Handler with the Middleware applied.
func wrapMiddleware(handler http.Handler, middleware ...Middleware) http.Handler {
	return &middlewareProxy{
		handler:    handler,
		middleware: middleware,
	}
}

// API is the top-level interface encapsulating an HTTP REST server. It's responsible for
// registering ResourceHandlers and routing requests. Use NewAPI to retrieve an instance.
type API interface {
	http.Handler

	// Start begins serving requests. This will block unless it fails, in which case an
	// error will be returned. This will validate any defined Rules. If any Rules are
	// invalid, it will panic. Any provided Middleware will be invoked for every request
	// handled by the API.
	Start(Address, ...Middleware) error

	// StartTLS begins serving requests received over HTTPS connections. This will block
	// unless it fails, in which case an error will be returned. Files containing a
	// certificate and matching private key for the server must be provided. If the
	// certificate is signed by a certificate authority, the certFile should be the
	// concatenation of the server's certificate followed by the CA's certificate. This
	// will validate any defined Rules. If any Rules are invalid, it will panic. Any
	// provided Middleware will be invoked for every request handled by the API.
	StartTLS(Address, FilePath, FilePath, ...Middleware) error

	// RegisterResourceHandler binds the provided ResourceHandler to the appropriate REST
	// endpoints and applies any specified middleware. Endpoints will have the following
	// base URL: /api/:version/resourceName.
	RegisterResourceHandler(ResourceHandler, ...RequestMiddleware)

	// RegisterHandlerFunc binds the http.HandlerFunc to the provided URI and applies any
	// specified middleware.
	RegisterHandlerFunc(string, http.HandlerFunc, ...RequestMiddleware)

	// RegisterHandler binds the http.Handler to the provided URI and applies any specified
	// middleware.
	RegisterHandler(string, http.Handler, ...RequestMiddleware)

	// RegisterPathPrefix binds the http.HandlerFunc to URIs matched by the given path
	// prefix and applies any specified middleware.
	RegisterPathPrefix(string, http.HandlerFunc, ...RequestMiddleware)

	// RegisterResponseSerializer registers the provided ResponseSerializer with the given
	// format. If the format has already been registered, it will be overwritten.
	RegisterResponseSerializer(string, ResponseSerializer)

	// UnregisterResponseSerializer unregisters the ResponseSerializer with the provided
	// format. If the format hasn't been registered, this is a no-op.
	UnregisterResponseSerializer(string)

	// AvailableFormats returns a slice containing all of the available serialization
	// formats currently available.
	AvailableFormats() []string

	// Configuration returns the API Configuration.
	Configuration() *Configuration

	// ResourceHandlers returns a slice containing the registered ResourceHandlers.
	ResourceHandlers() []ResourceHandler

	// Validate will validate the Rules configured for this API. It returns nil
	// if all Rules are valid, otherwise returns the first encountered
	// validation error.
	Validate() error

	// responseSerializer returns a ResponseSerializer for the given format type. If the
	// format is not implemented, the returned serializer will be nil and the error set.
	responseSerializer(string) (ResponseSerializer, error)
}

// RequestMiddleware is a function that returns a HandlerFunc wrapping the provided HandlerFunc.
// This allows injecting custom logic to operate on requests (e.g. performing authentication).
type RequestMiddleware func(http.HandlerFunc) http.HandlerFunc

// newAuthMiddleware returns a RequestMiddleware used to authenticate requests.
func newAuthMiddleware(authenticate func(*http.Request) error) RequestMiddleware {
	return func(wrapped http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			if err := authenticate(r); err != nil {
				w.WriteHeader(http.StatusUnauthorized)
				w.Write([]byte(err.Error()))
				return
			}
			wrapped(w, r)
		}
	}
}

// muxAPI is an implementation of the API interface which relies on the gorilla/mux
// package to handle request dispatching (see http://www.gorillatoolkit.org/pkg/mux).
type muxAPI struct {
	config             *Configuration
	router             *mux.Router
	mu                 sync.RWMutex
	handler            *requestHandler
	serializerRegistry map[string]ResponseSerializer
	resourceHandlers   []ResourceHandler
}

// NewAPI returns a newly allocated API instance.
func NewAPI(config *Configuration) API {
	r := mux.NewRouter()
	restAPI := &muxAPI{
		config:             config,
		router:             r,
		serializerRegistry: map[string]ResponseSerializer{"json": &jsonSerializer{}},
		resourceHandlers:   make([]ResourceHandler, 0),
	}
	restAPI.handler = &requestHandler{restAPI}
	return restAPI
}

// Start begins serving requests. This will block unless it fails, in which case an error will be
// returned.
func (r *muxAPI) Start(addr Address, middleware ...Middleware) error {
	r.preprocess()
	return http.ListenAndServe(string(addr), wrapMiddleware(r.router, middleware...))
}

// StartTLS begins serving requests received over HTTPS connections. This will block unless it
// fails, in which case an error will be returned. Files containing a certificate and matching
// private key for the server must be provided. If the certificate is signed by a certificate
// authority, the certFile should be the concatenation of the server's certificate followed by
// the CA's certificate.
func (r *muxAPI) StartTLS(addr Address, certFile, keyFile FilePath, middleware ...Middleware) error {
	r.preprocess()
	return http.ListenAndServeTLS(string(addr), string(certFile), string(keyFile), wrapMiddleware(r.router, middleware...))
}

// preprocess performs any necessary preprocessing before the server can be started, including
// Rule validation.
func (r *muxAPI) preprocess() {
	r.validateRulesOrPanic()
	if r.config.GenerateDocs {
		if err := newDocGenerator().generateDocs(r); err != nil {
			log.Fatal(err)
		}
	}
}

// RegisterResourceHandler binds the provided ResourceHandler to the appropriate REST endpoints and
// applies any specified middleware. Endpoints will have the following base URL:
// /api/:version/resourceName.
func (r *muxAPI) RegisterResourceHandler(h ResourceHandler, middleware ...RequestMiddleware) {
	h = resourceHandlerProxy{h}
	resource := h.ResourceName()
	middleware = append(middleware, newAuthMiddleware(h.Authenticate))

	r.router.HandleFunc(
		h.CreateURI(), applyMiddleware(r.handler.handleCreate(h), middleware),
	).Methods("POST").Name(resource + ":create")
	r.config.Debugf("Registered create handler at POST %s", h.CreateURI())

	r.router.HandleFunc(
		h.ReadListURI(), applyMiddleware(r.handler.handleReadList(h), middleware),
	).Methods("GET").Name(resource + ":readList")
	r.config.Debugf("Registered read list handler at GET %s", h.ReadListURI())

	r.router.HandleFunc(
		h.ReadURI(), applyMiddleware(r.handler.handleRead(h), middleware),
	).Methods("GET").Name(resource + ":read")
	r.config.Debugf("Registered read handler at GET %s", h.ReadURI())

	r.router.HandleFunc(
		h.UpdateListURI(), applyMiddleware(r.handler.handleUpdateList(h), middleware),
	).Methods("PUT").Name(resource + ":updateList")
	r.config.Debugf("Registered update list handler at PUT %s", h.UpdateListURI())

	r.router.HandleFunc(
		h.UpdateURI(), applyMiddleware(r.handler.handleUpdate(h), middleware),
	).Methods("PUT").Name(resource + ":update")
	r.config.Debugf("Registered update handler at PUT %s", h.UpdateURI())

	r.router.HandleFunc(
		h.DeleteURI(), applyMiddleware(r.handler.handleDelete(h), middleware),
	).Methods("DELETE").Name(resource + ":delete")
	r.config.Debugf("Registered delete handler at DELETE %s", h.DeleteURI())

	// Some browsers don't support PUT and DELETE, so allow method overriding.
	// POST requests with X-HTTP-Method-Override=PUT/DELETE will route to the
	// respective handlers.
	r.router.HandleFunc(
		h.UpdateListURI(), applyMiddleware(r.handler.handleUpdateList(h), middleware),
	).Methods("POST").Headers("X-HTTP-Method-Override", "PUT").Name(resource + ":updateListOverride")

	r.router.HandleFunc(
		h.UpdateURI(), applyMiddleware(r.handler.handleUpdate(h), middleware),
	).Methods("POST").Headers("X-HTTP-Method-Override", "PUT").Name(resource + ":updateOverride")

	r.router.HandleFunc(
		h.DeleteURI(), applyMiddleware(r.handler.handleDelete(h), middleware),
	).Methods("POST").Headers("X-HTTP-Method-Override", "DELETE").Name(resource + ":deleteOverride")

	r.resourceHandlers = append(r.resourceHandlers, h)
}

// RegisterHandlerFunc binds the http.HandlerFunc to the provided URI and applies any
// specified middleware.
func (r *muxAPI) RegisterHandlerFunc(uri string, handler http.HandlerFunc,
	middleware ...RequestMiddleware) {
	r.router.HandleFunc(uri, applyMiddleware(handler, middleware))
}

// RegisterHandler binds the http.Handler to the provided URI and applies any specified
// middleware.
func (r *muxAPI) RegisterHandler(uri string, handler http.Handler, middleware ...RequestMiddleware) {
	r.router.HandleFunc(uri, applyMiddleware(handler.ServeHTTP, middleware))
}

// RegisterPathPrefix binds the http.HandlerFunc to URIs matched by the given path
// prefix and applies any specified middleware.
func (r *muxAPI) RegisterPathPrefix(uri string, handler http.HandlerFunc,
	middleware ...RequestMiddleware) {
	r.router.PathPrefix(uri).HandlerFunc(applyMiddleware(handler, middleware))
}

// ServeHTTP handles an HTTP request.
func (r *muxAPI) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	r.router.ServeHTTP(w, req)
}

// RegisterResponseSerializer registers the provided ResponseSerializer with the given format. If the
// format has already been registered, it will be overwritten.
func (r *muxAPI) RegisterResponseSerializer(format string, serializer ResponseSerializer) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.serializerRegistry[format] = serializer
}

// UnregisterResponseSerializer unregisters the ResponseSerializer with the provided format. If the
// format hasn't been registered, this is a no-op.
func (r *muxAPI) UnregisterResponseSerializer(format string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	delete(r.serializerRegistry, format)
}

// AvailableFormats returns a slice containing all of the available serialization formats
// currently available.
func (r *muxAPI) AvailableFormats() []string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	formats := make([]string, 0, len(r.serializerRegistry))
	for format := range r.serializerRegistry {
		formats = append(formats, format)
	}
	sort.Strings(formats)
	return formats
}

// ResourceHandlers returns a slice containing the registered ResourceHandlers.
func (r *muxAPI) ResourceHandlers() []ResourceHandler {
	return r.resourceHandlers
}

// Configuration returns the API Configuration.
func (r *muxAPI) Configuration() *Configuration {
	return r.config
}

// Validate will validate the Rules configured for this API. It returns nil if
// all Rules are valid, otherwise returns the first encountered validation
// error.
func (r *muxAPI) Validate() error {
	for _, handler := range r.resourceHandlers {
		rules := handler.Rules()
		if rules == nil || rules.Size() == 0 {
			continue
		}

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

// validateRulesOrPanic verifies that the Rules for each ResourceHandler
// registered with the muxAPI are valid, meaning they specify fields that exist
// and correct types. If a Rule is invalid, this will panic.
func (r *muxAPI) validateRulesOrPanic() {
	if err := r.Validate(); err != nil {
		panic(err)
	}
}

// responseSerializer returns a ResponseSerializer for the given format type. If the format
// is not implemented, the returned serializer will be nil and the error set.
func (r *muxAPI) responseSerializer(format string) (ResponseSerializer, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	if serializer, ok := r.serializerRegistry[format]; ok {
		return serializer, nil
	}
	return nil, fmt.Errorf("Format not implemented: %s", format)
}

// applyMiddleware wraps the HandlerFunc with the provided RequestMiddleware and returns the
// function composition.
func applyMiddleware(h http.HandlerFunc, middleware []RequestMiddleware) http.HandlerFunc {
	for _, m := range middleware {
		h = m(h)
	}

	return h
}
<commit_msg>Use log.Printf instead of log.Fatal in preprocess<commit_after>/*
Copyright 2014 Workiva, LLC

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 rest

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"sort"
	"sync"

	"github.com/gorilla/mux"
)

const (
	defaultLogPrefix     = "rest "
	defaultDocsDirectory = "_docs/"
)

// Address is the address and port to bind to (e.g. ":8080").
type Address string

// FilePath represents a file path.
type FilePath string

// Configuration contains settings for configuring an API.
type Configuration struct {
	Debug         bool
	Logger        *log.Logger
	GenerateDocs  bool
	DocsDirectory string
}

// Debugf prints the formatted string to the Configuration Logger if Debug is enabled.
func (c *Configuration) Debugf(format string, v ...interface{}) {
	if c.Debug {
		c.Logger.Printf(format, v)
	}
}

// NewConfiguration returns a default Configuration.
func NewConfiguration() *Configuration {
	logger := log.New(os.Stdout, defaultLogPrefix, log.LstdFlags)
	return &Configuration{
		Debug:         true,
		Logger:        logger,
		GenerateDocs:  true,
		DocsDirectory: defaultDocsDirectory,
	}
}

// Middleware can be passed in to API#Start and API#StartTLS and will be
// invoked on every request to a route handled by the API. Returns true if the
// request should be terminated, false if it should continue.
type Middleware func(w http.ResponseWriter, r *http.Request) bool

// middlewareProxy proxies an http.Handler by invoking middleware before
// passing the request to the Handler. It implements the http.Handler
// interface.
type middlewareProxy struct {
	handler    http.Handler
	middleware []Middleware
}

// ServeHTTP invokes middleware on the request and then delegates to the
// proxied http.Handler.
func (m *middlewareProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	for _, middleware := range m.middleware {
		if middleware(w, r) {
			return
		}
	}
	m.handler.ServeHTTP(w, r)
}

// wrapMiddleware returns an http.Handler with the Middleware applied.
func wrapMiddleware(handler http.Handler, middleware ...Middleware) http.Handler {
	return &middlewareProxy{
		handler:    handler,
		middleware: middleware,
	}
}

// API is the top-level interface encapsulating an HTTP REST server. It's responsible for
// registering ResourceHandlers and routing requests. Use NewAPI to retrieve an instance.
type API interface {
	http.Handler

	// Start begins serving requests. This will block unless it fails, in which case an
	// error will be returned. This will validate any defined Rules. If any Rules are
	// invalid, it will panic. Any provided Middleware will be invoked for every request
	// handled by the API.
	Start(Address, ...Middleware) error

	// StartTLS begins serving requests received over HTTPS connections. This will block
	// unless it fails, in which case an error will be returned. Files containing a
	// certificate and matching private key for the server must be provided. If the
	// certificate is signed by a certificate authority, the certFile should be the
	// concatenation of the server's certificate followed by the CA's certificate. This
	// will validate any defined Rules. If any Rules are invalid, it will panic. Any
	// provided Middleware will be invoked for every request handled by the API.
	StartTLS(Address, FilePath, FilePath, ...Middleware) error

	// RegisterResourceHandler binds the provided ResourceHandler to the appropriate REST
	// endpoints and applies any specified middleware. Endpoints will have the following
	// base URL: /api/:version/resourceName.
	RegisterResourceHandler(ResourceHandler, ...RequestMiddleware)

	// RegisterHandlerFunc binds the http.HandlerFunc to the provided URI and applies any
	// specified middleware.
	RegisterHandlerFunc(string, http.HandlerFunc, ...RequestMiddleware)

	// RegisterHandler binds the http.Handler to the provided URI and applies any specified
	// middleware.
	RegisterHandler(string, http.Handler, ...RequestMiddleware)

	// RegisterPathPrefix binds the http.HandlerFunc to URIs matched by the given path
	// prefix and applies any specified middleware.
	RegisterPathPrefix(string, http.HandlerFunc, ...RequestMiddleware)

	// RegisterResponseSerializer registers the provided ResponseSerializer with the given
	// format. If the format has already been registered, it will be overwritten.
	RegisterResponseSerializer(string, ResponseSerializer)

	// UnregisterResponseSerializer unregisters the ResponseSerializer with the provided
	// format. If the format hasn't been registered, this is a no-op.
	UnregisterResponseSerializer(string)

	// AvailableFormats returns a slice containing all of the available serialization
	// formats currently available.
	AvailableFormats() []string

	// Configuration returns the API Configuration.
	Configuration() *Configuration

	// ResourceHandlers returns a slice containing the registered ResourceHandlers.
	ResourceHandlers() []ResourceHandler

	// Validate will validate the Rules configured for this API. It returns nil
	// if all Rules are valid, otherwise returns the first encountered
	// validation error.
	Validate() error

	// responseSerializer returns a ResponseSerializer for the given format type. If the
	// format is not implemented, the returned serializer will be nil and the error set.
	responseSerializer(string) (ResponseSerializer, error)
}

// RequestMiddleware is a function that returns a HandlerFunc wrapping the provided HandlerFunc.
// This allows injecting custom logic to operate on requests (e.g. performing authentication).
type RequestMiddleware func(http.HandlerFunc) http.HandlerFunc

// newAuthMiddleware returns a RequestMiddleware used to authenticate requests.
func newAuthMiddleware(authenticate func(*http.Request) error) RequestMiddleware {
	return func(wrapped http.HandlerFunc) http.HandlerFunc {
		return func(w http.ResponseWriter, r *http.Request) {
			if err := authenticate(r); err != nil {
				w.WriteHeader(http.StatusUnauthorized)
				w.Write([]byte(err.Error()))
				return
			}
			wrapped(w, r)
		}
	}
}

// muxAPI is an implementation of the API interface which relies on the gorilla/mux
// package to handle request dispatching (see http://www.gorillatoolkit.org/pkg/mux).
type muxAPI struct {
	config             *Configuration
	router             *mux.Router
	mu                 sync.RWMutex
	handler            *requestHandler
	serializerRegistry map[string]ResponseSerializer
	resourceHandlers   []ResourceHandler
}

// NewAPI returns a newly allocated API instance.
func NewAPI(config *Configuration) API {
	r := mux.NewRouter()
	restAPI := &muxAPI{
		config:             config,
		router:             r,
		serializerRegistry: map[string]ResponseSerializer{"json": &jsonSerializer{}},
		resourceHandlers:   make([]ResourceHandler, 0),
	}
	restAPI.handler = &requestHandler{restAPI}
	return restAPI
}

// Start begins serving requests. This will block unless it fails, in which case an error will be
// returned.
func (r *muxAPI) Start(addr Address, middleware ...Middleware) error {
	r.preprocess()
	return http.ListenAndServe(string(addr), wrapMiddleware(r.router, middleware...))
}

// StartTLS begins serving requests received over HTTPS connections. This will block unless it
// fails, in which case an error will be returned. Files containing a certificate and matching
// private key for the server must be provided. If the certificate is signed by a certificate
// authority, the certFile should be the concatenation of the server's certificate followed by
// the CA's certificate.
func (r *muxAPI) StartTLS(addr Address, certFile, keyFile FilePath, middleware ...Middleware) error {
	r.preprocess()
	return http.ListenAndServeTLS(string(addr), string(certFile), string(keyFile), wrapMiddleware(r.router, middleware...))
}

// preprocess performs any necessary preprocessing before the server can be started, including
// Rule validation.
func (r *muxAPI) preprocess() {
	r.validateRulesOrPanic()
	if r.config.GenerateDocs {
		if err := newDocGenerator().generateDocs(r); err != nil {
			log.Printf("documentation could not be generated: %v", err)
		}
	}
}

// RegisterResourceHandler binds the provided ResourceHandler to the appropriate REST endpoints and
// applies any specified middleware. Endpoints will have the following base URL:
// /api/:version/resourceName.
func (r *muxAPI) RegisterResourceHandler(h ResourceHandler, middleware ...RequestMiddleware) {
	h = resourceHandlerProxy{h}
	resource := h.ResourceName()
	middleware = append(middleware, newAuthMiddleware(h.Authenticate))

	r.router.HandleFunc(
		h.CreateURI(), applyMiddleware(r.handler.handleCreate(h), middleware),
	).Methods("POST").Name(resource + ":create")
	r.config.Debugf("Registered create handler at POST %s", h.CreateURI())

	r.router.HandleFunc(
		h.ReadListURI(), applyMiddleware(r.handler.handleReadList(h), middleware),
	).Methods("GET").Name(resource + ":readList")
	r.config.Debugf("Registered read list handler at GET %s", h.ReadListURI())

	r.router.HandleFunc(
		h.ReadURI(), applyMiddleware(r.handler.handleRead(h), middleware),
	).Methods("GET").Name(resource + ":read")
	r.config.Debugf("Registered read handler at GET %s", h.ReadURI())

	r.router.HandleFunc(
		h.UpdateListURI(), applyMiddleware(r.handler.handleUpdateList(h), middleware),
	).Methods("PUT").Name(resource + ":updateList")
	r.config.Debugf("Registered update list handler at PUT %s", h.UpdateListURI())

	r.router.HandleFunc(
		h.UpdateURI(), applyMiddleware(r.handler.handleUpdate(h), middleware),
	).Methods("PUT").Name(resource + ":update")
	r.config.Debugf("Registered update handler at PUT %s", h.UpdateURI())

	r.router.HandleFunc(
		h.DeleteURI(), applyMiddleware(r.handler.handleDelete(h), middleware),
	).Methods("DELETE").Name(resource + ":delete")
	r.config.Debugf("Registered delete handler at DELETE %s", h.DeleteURI())

	// Some browsers don't support PUT and DELETE, so allow method overriding.
	// POST requests with X-HTTP-Method-Override=PUT/DELETE will route to the
	// respective handlers.
	r.router.HandleFunc(
		h.UpdateListURI(), applyMiddleware(r.handler.handleUpdateList(h), middleware),
	).Methods("POST").Headers("X-HTTP-Method-Override", "PUT").Name(resource + ":updateListOverride")

	r.router.HandleFunc(
		h.UpdateURI(), applyMiddleware(r.handler.handleUpdate(h), middleware),
	).Methods("POST").Headers("X-HTTP-Method-Override", "PUT").Name(resource + ":updateOverride")

	r.router.HandleFunc(
		h.DeleteURI(), applyMiddleware(r.handler.handleDelete(h), middleware),
	).Methods("POST").Headers("X-HTTP-Method-Override", "DELETE").Name(resource + ":deleteOverride")

	r.resourceHandlers = append(r.resourceHandlers, h)
}

// RegisterHandlerFunc binds the http.HandlerFunc to the provided URI and applies any
// specified middleware.
func (r *muxAPI) RegisterHandlerFunc(uri string, handler http.HandlerFunc,
	middleware ...RequestMiddleware) {
	r.router.HandleFunc(uri, applyMiddleware(handler, middleware))
}

// RegisterHandler binds the http.Handler to the provided URI and applies any specified
// middleware.
func (r *muxAPI) RegisterHandler(uri string, handler http.Handler, middleware ...RequestMiddleware) {
	r.router.HandleFunc(uri, applyMiddleware(handler.ServeHTTP, middleware))
}

// RegisterPathPrefix binds the http.HandlerFunc to URIs matched by the given path
// prefix and applies any specified middleware.
func (r *muxAPI) RegisterPathPrefix(uri string, handler http.HandlerFunc,
	middleware ...RequestMiddleware) {
	r.router.PathPrefix(uri).HandlerFunc(applyMiddleware(handler, middleware))
}

// ServeHTTP handles an HTTP request.
func (r *muxAPI) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	r.router.ServeHTTP(w, req)
}

// RegisterResponseSerializer registers the provided ResponseSerializer with the given format. If the
// format has already been registered, it will be overwritten.
func (r *muxAPI) RegisterResponseSerializer(format string, serializer ResponseSerializer) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.serializerRegistry[format] = serializer
}

// UnregisterResponseSerializer unregisters the ResponseSerializer with the provided format. If the
// format hasn't been registered, this is a no-op.
func (r *muxAPI) UnregisterResponseSerializer(format string) {
	r.mu.Lock()
	defer r.mu.Unlock()
	delete(r.serializerRegistry, format)
}

// AvailableFormats returns a slice containing all of the available serialization formats
// currently available.
func (r *muxAPI) AvailableFormats() []string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	formats := make([]string, 0, len(r.serializerRegistry))
	for format := range r.serializerRegistry {
		formats = append(formats, format)
	}
	sort.Strings(formats)
	return formats
}

// ResourceHandlers returns a slice containing the registered ResourceHandlers.
func (r *muxAPI) ResourceHandlers() []ResourceHandler {
	return r.resourceHandlers
}

// Configuration returns the API Configuration.
func (r *muxAPI) Configuration() *Configuration {
	return r.config
}

// Validate will validate the Rules configured for this API. It returns nil if
// all Rules are valid, otherwise returns the first encountered validation
// error.
func (r *muxAPI) Validate() error {
	for _, handler := range r.resourceHandlers {
		rules := handler.Rules()
		if rules == nil || rules.Size() == 0 {
			continue
		}

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

// validateRulesOrPanic verifies that the Rules for each ResourceHandler
// registered with the muxAPI are valid, meaning they specify fields that exist
// and correct types. If a Rule is invalid, this will panic.
func (r *muxAPI) validateRulesOrPanic() {
	if err := r.Validate(); err != nil {
		panic(err)
	}
}

// responseSerializer returns a ResponseSerializer for the given format type. If the format
// is not implemented, the returned serializer will be nil and the error set.
func (r *muxAPI) responseSerializer(format string) (ResponseSerializer, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	if serializer, ok := r.serializerRegistry[format]; ok {
		return serializer, nil
	}
	return nil, fmt.Errorf("Format not implemented: %s", format)
}

// applyMiddleware wraps the HandlerFunc with the provided RequestMiddleware and returns the
// function composition.
func applyMiddleware(h http.HandlerFunc, middleware []RequestMiddleware) http.HandlerFunc {
	for _, m := range middleware {
		h = m(h)
	}

	return h
}
<|endoftext|>


<commit_before>package restic

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/debug"
	"github.com/restic/restic/repository"

	"github.com/juju/errors"
)

// Restorer is used to restore a snapshot to a directory.
type Restorer struct {
	repo *repository.Repository
	sn   *Snapshot

	Error            func(dir string, node *Node, err error) error
	SelectForRestore func(item string, dstpath string, node *Node) bool
}

var restorerAbortOnAllErrors = func(str string, node *Node, err error) error { return err }

// NewRestorer creates a restorer preloaded with the content from the snapshot id.
func NewRestorer(repo *repository.Repository, id backend.ID) (*Restorer, error) {
	r := &Restorer{repo: repo, Error: restorerAbortOnAllErrors}

	var err error

	r.sn, err = LoadSnapshot(repo, id)
	if err != nil {
		return nil, errors.Annotate(err, "load snapshot for restorer")
	}

	return r, nil
}

func (res *Restorer) restoreTo(dst string, dir string, treeID backend.ID) error {
	tree, err := LoadTree(res.repo, treeID)
	if err != nil {
		return res.Error(dir, nil, errors.Annotate(err, "LoadTree"))
	}

	for _, node := range tree.Nodes {
		excluded, err := res.restoreNodeTo(node, dir, dst)
		if err != nil {
			return err
		}

		if node.Type == "dir" {
			if node.Subtree == nil {
				return fmt.Errorf("Dir without subtree in tree %v", treeID.Str())
			}

			subp := filepath.Join(dir, node.Name)
			err = res.restoreTo(dst, subp, node.Subtree)
			if err != nil {
				err = res.Error(subp, node, errors.Annotate(err, "restore subtree"))
				if err != nil {
					return err
				}
			}

			if !excluded {
				// Restore directory timestamp at the end. If we would do it earlier, restoring files within
				// the directory would overwrite the timestamp of the directory they are in.
				if err := node.RestoreTimestamps(filepath.Join(dst, dir, node.Name)); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (res *Restorer) restoreNodeTo(node *Node, dir string, dst string) (excluded bool, err error) {
	debug.Log("Restorer.restoreNodeTo", "node %v, dir %v, dst %v", node.Name, dir, dst)
	dstPath := filepath.Join(dst, dir, node.Name)

	if res.SelectForRestore != nil {
		debug.Log("Restorer.restoreNodeTo", "running select filter for %v", node.Name)

		if !res.SelectForRestore(filepath.Join(dir, node.Name), dstPath, node) {
			debug.Log("Restorer.restoreNodeTo", "SelectForRestore returned false")
			return true, nil
		}
	}

	err = node.CreateAt(dstPath, res.repo)
	if err != nil {
		debug.Log("Restorer.restoreNodeTo", "node.CreateAt(%s) error %v", dstPath, err)
	}

	// Did it fail because of ENOENT?
	if pe, ok := errors.Cause(err).(*os.PathError); ok {
		errn, ok := pe.Err.(syscall.Errno)
		if ok && errn == syscall.ENOENT {
			debug.Log("Restorer.restoreNodeTo", "create intermediate paths")

			// Create parent directories and retry
			err = os.MkdirAll(filepath.Dir(dstPath), 0700)
			if err == nil || err == os.ErrExist {
				err = node.CreateAt(dstPath, res.repo)
			}
		}
	}

	if err != nil {
		debug.Log("Restorer.restoreNodeTo", "error %v", err)
		err = res.Error(dstPath, node, errors.Annotate(err, "create node"))
		if err != nil {
			return false, err
		}
	}

	debug.Log("Restorer.restoreNodeTo", "successfully restored %v", node.Name)

	return false, nil
}

// RestoreTo creates the directories and files in the snapshot below dir.
// Before an item is created, res.Filter is called.
func (res *Restorer) RestoreTo(dir string) error {
	return res.restoreTo(dir, "", res.sn.Tree)
}

// Snapshot returns the snapshot this restorer is configured to use.
func (res *Restorer) Snapshot() *Snapshot {
	return res.sn
}
<commit_msg>restorer: Move filter to `restoreTo()`<commit_after>package restic

import (
	"fmt"
	"os"
	"path/filepath"
	"syscall"

	"github.com/restic/restic/backend"
	"github.com/restic/restic/debug"
	"github.com/restic/restic/repository"

	"github.com/juju/errors"
)

// Restorer is used to restore a snapshot to a directory.
type Restorer struct {
	repo *repository.Repository
	sn   *Snapshot

	Error            func(dir string, node *Node, err error) error
	SelectForRestore func(item string, dstpath string, node *Node) bool
}

var restorerAbortOnAllErrors = func(str string, node *Node, err error) error { return err }

// NewRestorer creates a restorer preloaded with the content from the snapshot id.
func NewRestorer(repo *repository.Repository, id backend.ID) (*Restorer, error) {
	r := &Restorer{repo: repo, Error: restorerAbortOnAllErrors}

	var err error

	r.sn, err = LoadSnapshot(repo, id)
	if err != nil {
		return nil, errors.Annotate(err, "load snapshot for restorer")
	}

	return r, nil
}

func (res *Restorer) restoreTo(dst string, dir string, treeID backend.ID) error {
	tree, err := LoadTree(res.repo, treeID)
	if err != nil {
		return res.Error(dir, nil, errors.Annotate(err, "LoadTree"))
	}

	for _, node := range tree.Nodes {
		selectedForRestore := true
		if res.SelectForRestore != nil {
			debug.Log("Restorer.restoreTo", "running select filter for %v", node.Name)

			selectedForRestore = res.SelectForRestore(filepath.Join(dir, node.Name),
				filepath.Join(dst, dir, node.Name), node)
			debug.Log("Restorer.restoreNodeTo", "SelectForRestore returned %v", selectedForRestore)
		}

		if selectedForRestore {
			err := res.restoreNodeTo(node, dir, dst)
			if err != nil {
				return err
			}
		}

		if node.Type == "dir" {
			if node.Subtree == nil {
				return fmt.Errorf("Dir without subtree in tree %v", treeID.Str())
			}

			subp := filepath.Join(dir, node.Name)
			err = res.restoreTo(dst, subp, node.Subtree)
			if err != nil {
				err = res.Error(subp, node, errors.Annotate(err, "restore subtree"))
				if err != nil {
					return err
				}
			}

			if selectedForRestore {
				// Restore directory timestamp at the end. If we would do it earlier, restoring files within
				// the directory would overwrite the timestamp of the directory they are in.
				if err := node.RestoreTimestamps(filepath.Join(dst, dir, node.Name)); err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (res *Restorer) restoreNodeTo(node *Node, dir string, dst string) error {
	debug.Log("Restorer.restoreNodeTo", "node %v, dir %v, dst %v", node.Name, dir, dst)
	dstPath := filepath.Join(dst, dir, node.Name)

	err := node.CreateAt(dstPath, res.repo)
	if err != nil {
		debug.Log("Restorer.restoreNodeTo", "node.CreateAt(%s) error %v", dstPath, err)
	}

	// Did it fail because of ENOENT?
	if pe, ok := errors.Cause(err).(*os.PathError); ok {
		errn, ok := pe.Err.(syscall.Errno)
		if ok && errn == syscall.ENOENT {
			debug.Log("Restorer.restoreNodeTo", "create intermediate paths")

			// Create parent directories and retry
			err = os.MkdirAll(filepath.Dir(dstPath), 0700)
			if err == nil || err == os.ErrExist {
				err = node.CreateAt(dstPath, res.repo)
			}
		}
	}

	if err != nil {
		debug.Log("Restorer.restoreNodeTo", "error %v", err)
		err = res.Error(dstPath, node, errors.Annotate(err, "create node"))
		if err != nil {
			return err
		}
	}

	debug.Log("Restorer.restoreNodeTo", "successfully restored %v", node.Name)

	return nil
}

// RestoreTo creates the directories and files in the snapshot below dir.
// Before an item is created, res.Filter is called.
func (res *Restorer) RestoreTo(dir string) error {
	return res.restoreTo(dir, "", res.sn.Tree)
}

// Snapshot returns the snapshot this restorer is configured to use.
func (res *Restorer) Snapshot() *Snapshot {
	return res.sn
}
<|endoftext|>


<commit_before>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/dag"
)

// TargetsTransformer is a GraphTransformer that, when the user specifies a
// list of resources to target, limits the graph to only those resources and
// their dependencies.
type TargetsTransformer struct {
	// List of targeted resource names specified by the user
	Targets []string

	// Set to true when we're in a `terraform destroy` or a
	// `terraform plan -destroy`
	Destroy bool
}

func (t *TargetsTransformer) Transform(g *Graph) error {
	if len(t.Targets) > 0 {
		// TODO: duplicated in OrphanTransformer; pull up parsing earlier
		addrs, err := t.parseTargetAddresses()
		if err != nil {
			return err
		}

		targetedNodes, err := t.selectTargetedNodes(g, addrs)
		if err != nil {
			return err
		}

		for _, v := range g.Vertices() {
			if _, ok := v.(GraphNodeAddressable); ok {
				if !targetedNodes.Include(v) {
					log.Printf("[DEBUG] Removing %s, filtered by targeting.", v)
					g.Remove(v)
				}
			}
		}
	}
	return nil
}

func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) {
	addrs := make([]ResourceAddress, len(t.Targets))
	for i, target := range t.Targets {
		ta, err := ParseResourceAddress(target)
		if err != nil {
			return nil, err
		}
		addrs[i] = *ta
	}
	return addrs, nil
}

// Returns the list of targeted nodes. A targeted node is either addressed
// directly, or is an Ancestor of a targeted node. Destroy mode keeps
// Descendents instead of Ancestors.
func (t *TargetsTransformer) selectTargetedNodes(
	g *Graph, addrs []ResourceAddress) (*dag.Set, error) {
	targetedNodes := new(dag.Set)
	for _, v := range g.Vertices() {
		if t.nodeIsTarget(v, addrs) {
			targetedNodes.Add(v)

			// We inform nodes that ask about the list of targets - helps for nodes
			// that need to dynamically expand. Note that this only occurs for nodes
			// that are already directly targeted.
			if tn, ok := v.(GraphNodeTargetable); ok {
				tn.SetTargets(addrs)
			}

			var deps *dag.Set
			var err error
			if t.Destroy {
				deps, err = g.Descendents(v)
			} else {
				deps, err = g.Ancestors(v)
			}
			if err != nil {
				return nil, err
			}

			for _, d := range deps.List() {
				targetedNodes.Add(d)
			}
		}
	}
	return targetedNodes, nil
}

func (t *TargetsTransformer) nodeIsTarget(
	v dag.Vertex, addrs []ResourceAddress) bool {
	r, ok := v.(GraphNodeAddressable)
	if !ok {
		return false
	}
	addr := r.ResourceAddress()
	for _, targetAddr := range addrs {
		if targetAddr.Equals(addr) {
			return true
		}
	}
	return false
}
<commit_msg>core: improve debug logging when targeting<commit_after>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/dag"
)

// TargetsTransformer is a GraphTransformer that, when the user specifies a
// list of resources to target, limits the graph to only those resources and
// their dependencies.
type TargetsTransformer struct {
	// List of targeted resource names specified by the user
	Targets []string

	// Set to true when we're in a `terraform destroy` or a
	// `terraform plan -destroy`
	Destroy bool
}

func (t *TargetsTransformer) Transform(g *Graph) error {
	if len(t.Targets) > 0 {
		// TODO: duplicated in OrphanTransformer; pull up parsing earlier
		addrs, err := t.parseTargetAddresses()
		if err != nil {
			return err
		}

		targetedNodes, err := t.selectTargetedNodes(g, addrs)
		if err != nil {
			return err
		}

		for _, v := range g.Vertices() {
			if _, ok := v.(GraphNodeAddressable); ok {
				if !targetedNodes.Include(v) {
					log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v))
					g.Remove(v)
				}
			}
		}
	}
	return nil
}

func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) {
	addrs := make([]ResourceAddress, len(t.Targets))
	for i, target := range t.Targets {
		ta, err := ParseResourceAddress(target)
		if err != nil {
			return nil, err
		}
		addrs[i] = *ta
	}
	return addrs, nil
}

// Returns the list of targeted nodes. A targeted node is either addressed
// directly, or is an Ancestor of a targeted node. Destroy mode keeps
// Descendents instead of Ancestors.
func (t *TargetsTransformer) selectTargetedNodes(
	g *Graph, addrs []ResourceAddress) (*dag.Set, error) {
	targetedNodes := new(dag.Set)
	for _, v := range g.Vertices() {
		if t.nodeIsTarget(v, addrs) {
			targetedNodes.Add(v)

			// We inform nodes that ask about the list of targets - helps for nodes
			// that need to dynamically expand. Note that this only occurs for nodes
			// that are already directly targeted.
			if tn, ok := v.(GraphNodeTargetable); ok {
				tn.SetTargets(addrs)
			}

			var deps *dag.Set
			var err error
			if t.Destroy {
				deps, err = g.Descendents(v)
			} else {
				deps, err = g.Ancestors(v)
			}
			if err != nil {
				return nil, err
			}

			for _, d := range deps.List() {
				targetedNodes.Add(d)
			}
		}
	}
	return targetedNodes, nil
}

func (t *TargetsTransformer) nodeIsTarget(
	v dag.Vertex, addrs []ResourceAddress) bool {
	r, ok := v.(GraphNodeAddressable)
	if !ok {
		return false
	}
	addr := r.ResourceAddress()
	for _, targetAddr := range addrs {
		if targetAddr.Equals(addr) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// Examples represents the examples loaded from examples.json.
type Examples []Example

// Examples represents an example loaded from examples.json.
type Example struct {
	Title       string `json:"title"`
	Link        string `json:"link"`
	Description string `json:"description"`
	Type        string `json:"type"`
}

func main() {
	addr := flag.String("address", ":80", "Address to host the HTTP server on.")
	flag.Parse()

	log.Println("Listening on", *addr)
	err := serve(*addr)
	if err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}

func serve(addr string) error {
	// Load the examples
	examples, err := getExamples()
	if err != nil {
		return err
	}

	// Load the templates
	homeTemplate := template.Must(template.ParseFiles("index.html"))

	// Serve the required pages
	// DIY 'mux' to avoid additional dependencies
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		parts := strings.Split(r.URL.Path, "/")
		if len(parts) > 3 && // 1 / example:2 / link:3 / [ static: 4 ]
			parts[1] == "example" {
			exampleLink := parts[2]
			for _, example := range *examples {
				if example.Link != exampleLink {
					continue
				}
				fiddle := filepath.Join(exampleLink, "jsfiddle")
				if len(parts[3]) != 0 {
					http.StripPrefix("/example/"+exampleLink+"/", http.FileServer(http.Dir(fiddle))).ServeHTTP(w, r)
					return
				}

				temp := template.Must(template.ParseFiles("example.html"))
				_, err = temp.ParseFiles(filepath.Join(fiddle, "demo.html"))
				if err != nil {
					panic(err)
				}

				temp.Execute(w, example)
				return
			}
		}

		// Serve the main page
		homeTemplate.Execute(w, examples)
	})

	// Start the server
	return http.ListenAndServe(addr, nil)
}

// getExamples loads the examples from the examples.json file.
func getExamples() (*Examples, error) {
	file, err := os.Open("./examples.json")
	if err != nil {
		return nil, fmt.Errorf("failed to list examples (please run in the examples folder): %v", err)
	}

	var examples Examples
	err = json.NewDecoder(file).Decode(&examples)
	if err != nil {
		return nil, fmt.Errorf("failed to parse examples: %v", err)
	}

	return &examples, nil
}
<commit_msg>Examples: close examples.json reader<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// Examples represents the examples loaded from examples.json.
type Examples []Example

// Examples represents an example loaded from examples.json.
type Example struct {
	Title       string `json:"title"`
	Link        string `json:"link"`
	Description string `json:"description"`
	Type        string `json:"type"`
}

func main() {
	addr := flag.String("address", ":80", "Address to host the HTTP server on.")
	flag.Parse()

	log.Println("Listening on", *addr)
	err := serve(*addr)
	if err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}

func serve(addr string) error {
	// Load the examples
	examples, err := getExamples()
	if err != nil {
		return err
	}

	// Load the templates
	homeTemplate := template.Must(template.ParseFiles("index.html"))

	// Serve the required pages
	// DIY 'mux' to avoid additional dependencies
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		parts := strings.Split(r.URL.Path, "/")
		if len(parts) > 3 && // 1 / example:2 / link:3 / [ static: 4 ]
			parts[1] == "example" {
			exampleLink := parts[2]
			for _, example := range *examples {
				if example.Link != exampleLink {
					continue
				}
				fiddle := filepath.Join(exampleLink, "jsfiddle")
				if len(parts[3]) != 0 {
					http.StripPrefix("/example/"+exampleLink+"/", http.FileServer(http.Dir(fiddle))).ServeHTTP(w, r)
					return
				}

				temp := template.Must(template.ParseFiles("example.html"))
				_, err = temp.ParseFiles(filepath.Join(fiddle, "demo.html"))
				if err != nil {
					panic(err)
				}

				temp.Execute(w, example)
				return
			}
		}

		// Serve the main page
		homeTemplate.Execute(w, examples)
	})

	// Start the server
	return http.ListenAndServe(addr, nil)
}

// getExamples loads the examples from the examples.json file.
func getExamples() (*Examples, error) {
	file, err := os.Open("./examples.json")
	defer file.Close()
	if err != nil {
		return nil, fmt.Errorf("failed to list examples (please run in the examples folder): %v", err)
	}

	var examples Examples
	err = json.NewDecoder(file).Decode(&examples)
	if err != nil {
		return nil, fmt.Errorf("failed to parse examples: %v", err)
	}

	return &examples, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"sync"

	"github.com/gocql/gocql"
	"github.com/skeswa/gophr/common"
)

func main() {
	log.Println("Establishing connection to DB")
	cluster := gocql.NewCluster("gophr.dev")
	cluster.ProtoVersion = 4
	cluster.Keyspace = "gophr"
	cluster.Consistency = gocql.One
	session, err := cluster.CreateSession()
	if err != nil {
		log.Println("Connection failed to establish successfully")
		log.Fatalln(err)
	}
	defer session.Close()
	log.Println("Connection established successfully")

	log.Println("Fetching godoc metadata")
	godocMetadataList, err := fetchGodocMetadata()
	if err != nil {
		log.Println("Failed to fetch godoc metadata")
		log.Fatalln(err)
	}

	log.Println("Fetching awesome go list")
	awesomeGoIndex, err := fetchAwesomeGoList()
	if err != nil {
		log.Println("Failed to fetch awesome go list")
		log.Fatalln(err)
	}

	log.Println("Preparing to build package models")
	packageModels, err := buildPackageModels(godocMetadataList, awesomeGoIndex)
	if err != nil {
		log.Println("Failed to build package models")
		log.Fatalln(err)
	}

	log.Println("Preparing to insert packages into database")
	var wg sync.WaitGroup
	for _, packageModel := range packageModels {
		err = common.InsertPackage(session, packageModel)
		go func(packageModel *common.PackageModel) {
			wg.Add(1)
			if err != nil {
				json, errz := packageModel.MarshalJSON()
				if errz == nil {
					log.Fatalln(string(json[:]), err)
				}
			}
			wg.Done()
		}(packageModel)
	}
	wg.Wait()

	log.Println("Finished inserting packages into database")
}
<commit_msg>make db inserts concurrent<commit_after>package main

import (
	"log"
	"sync"

	"github.com/gocql/gocql"
	"github.com/skeswa/gophr/common"
)

func main() {
	log.Println("Establishing connection to DB")
	cluster := gocql.NewCluster("gophr.dev")
	cluster.ProtoVersion = 4
	cluster.Keyspace = "gophr"
	cluster.Consistency = gocql.One
	session, err := cluster.CreateSession()
	if err != nil {
		log.Println("Connection failed to establish successfully")
		log.Fatalln(err)
	}
	defer session.Close()
	log.Println("Connection established successfully")

	log.Println("Fetching godoc metadata")
	godocMetadataList, err := fetchGodocMetadata()
	if err != nil {
		log.Println("Failed to fetch godoc metadata")
		log.Fatalln(err)
	}

	log.Println("Fetching awesome go list")
	awesomeGoIndex, err := fetchAwesomeGoList()
	if err != nil {
		log.Println("Failed to fetch awesome go list")
		log.Fatalln(err)
	}

	log.Println("Preparing to build package models")
	packageModels, err := buildPackageModels(godocMetadataList, awesomeGoIndex)
	if err != nil {
		log.Println("Failed to build package models")
		log.Fatalln(err)
	}

	log.Println("Preparing to insert packages into database")

	var wg sync.WaitGroup
	var insertPackageErrors []error

	nbConcurrentInserts := 20
	packageChan := make(chan *common.PackageModel, nbConcurrentInserts)
	for i := 0; i < nbConcurrentInserts; i++ {
		wg.Add(1)
		go func() {
			for packageModel := range packageChan {
				err := common.InsertPackage(session, packageModel)
				if err != nil {
					insertPackageErrors = append(insertPackageErrors, err)
				}
			}
			wg.Done()
		}()
	}

	for _, packageModel := range packageModels {
		packageChan <- packageModel
	}
	close(packageChan)
	wg.Wait()

	for _, insertErr := range insertPackageErrors {
		log.Println(insertErr)
	}

	log.Println("Finished inserting packages into database")
}
<|endoftext|>


<commit_before>package board

import (
	"gitlab.com/kanban/kanban/models"
	"gitlab.com/kanban/kanban/modules/middleware"
	"net/http"
	"fmt"
)

// ListCards gets a list of card on board accessible by the authenticated user.
func ListCards(ctx *middleware.Context) {
	cards, err := models.ListCards(ctx.User, ctx.Provider, ctx.Query("project_id"))

	if err != nil {
		ctx.JSON(http.StatusUnauthorized, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: cards,
	})
}

// CreateCard creates a new board card.
func CreateCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.CreateCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.create",
	})
}

// UpdateCard updates an existing board card.
func UpdateCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.UpdateCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.update",
	})
}

// DeleteCard closed an existing board card.
func DeleteCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.DeleteCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.delete",
	})
}

// MoveToCard updates an existing board card.
func MoveToCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.UpdateCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.move",
	})

	source := models.ParseLabelToStage(form.Stage["source"])
	dest := models.ParseLabelToStage(form.Stage["dest"])

	com := models.CommentRequest{
	CardId: form.CardId,
		ProjectId: form.ProjectId,
		Body: fmt.Sprintf("moved issue from **%s** to **%s**", source.Name, dest.Name),
	}

	go func() {
		models.CreateComment(ctx.User, ctx.Provider, &com)
	}()
}
<commit_msg>fixed comment spam when card is moved to same column<commit_after>package board

import (
	"gitlab.com/kanban/kanban/models"
	"gitlab.com/kanban/kanban/modules/middleware"
	"net/http"
	"fmt"
)

// ListCards gets a list of card on board accessible by the authenticated user.
func ListCards(ctx *middleware.Context) {
	cards, err := models.ListCards(ctx.User, ctx.Provider, ctx.Query("project_id"))

	if err != nil {
		ctx.JSON(http.StatusUnauthorized, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: cards,
	})
}

// CreateCard creates a new board card.
func CreateCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.CreateCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.create",
	})
}

// UpdateCard updates an existing board card.
func UpdateCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.UpdateCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.update",
	})
}

// DeleteCard closed an existing board card.
func DeleteCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.DeleteCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.delete",
	})
}

// MoveToCard updates an existing board card.
func MoveToCard(ctx *middleware.Context, form models.CardRequest) {
	card, code, err := models.UpdateCard(ctx.User, ctx.Provider, &form)

	if err != nil {
		ctx.JSON(code, &models.ResponseError{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, &models.Response{
		Data: card,
	})

	ctx.Broadcast(card.RoutingKey(), &models.Response{
		Data: card,
		Event: "card.move",
	})

	source := models.ParseLabelToStage(form.Stage["source"])
	dest := models.ParseLabelToStage(form.Stage["dest"])

	if source.Name != dest.Name {
		com := models.CommentRequest{
		CardId: form.CardId,
			ProjectId: form.ProjectId,
			Body: fmt.Sprintf("moved issue from **%s** to **%s**", source.Name, dest.Name),
		}

		go func() {
			models.CreateComment(ctx.User, ctx.Provider, &com)
		}()
	}
}
<|endoftext|>


<commit_before>package ruby_def

import (
	"encoding/json"
	"strings"

	"sourcegraph.com/sourcegraph/srclib/graph"
)

func init() {
	graph.RegisterMakeDefFormatter("rubygem", newDefFormatter)
	graph.RegisterMakeDefFormatter("ruby", newDefFormatter)
}

// DefData should be kept in sync with the def 'Data' field emitted by the Ruby
// grapher.
type DefData struct {
	RubyKind   string
	TypeString string
	Module     string
	RubyPath   string
	Signature  string
	ReturnType string
}

func (s *DefData) isLocalVar() bool {
	return strings.Contains(s.RubyPath, ">_local_")
}

func newDefFormatter(s *graph.Def) graph.DefFormatter {
	var si DefData
	if len(s.Data) > 0 {
		if err := json.Unmarshal(s.Data, &si); err != nil {
			panic("unmarshal Ruby def data: " + err.Error())
		}
	}
	return defFormatter{s, &si}
}

type defFormatter struct {
	def  *graph.Def
	data *DefData
}

func (f defFormatter) Language() string { return "JavaScript" }

func (f defFormatter) DefKeyword() string {
	switch f.data.RubyKind {
	case "method":
		return "def"
	case "class", "module":
		return f.data.RubyKind
	}
	return ""
}

func (f defFormatter) Kind() string { return f.data.RubyKind }

func (f defFormatter) Name(qual graph.Qualification) string {
	if f.data.isLocalVar() {
		return f.def.Name
	}

	switch qual {
	case graph.Unqualified:
		return f.def.Name
	case graph.ScopeQualified:
		return f.data.RubyPath
	case graph.DepQualified:
		return f.data.RubyPath
	case graph.RepositoryWideQualified:
		return f.data.RubyPath
	case graph.LanguageWideQualified:
		return f.data.RubyPath
	}
	panic("Name: unhandled qual " + string(qual))
}

func (f defFormatter) NameAndTypeSeparator() string {
	if f.data.RubyKind == "method" {
		return ""
	}
	return " "
}

func (f defFormatter) Type(qual graph.Qualification) string {
	var ts string
	if f.data.RubyKind == "method" {
		if i := strings.Index(f.data.Signature, "("); i != -1 {
			ts = f.data.Signature[i:]
		}
		ts += " " + cleanType(f.data.ReturnType)
	} else {
		ts = cleanType(f.data.TypeString)
	}
	return strings.TrimPrefix(ts, "::")
}

func cleanType(t string) string {
	t = strings.TrimSuffix(t, "#")
	switch t {
	case "NilClass":
		return "nil"
	case "TrueClass":
		return "true"
	case "FalseClass":
		return "false"
	}
	return t
}
<commit_msg>Fixed typo in formatter<commit_after>package ruby_def

import (
	"encoding/json"
	"strings"

	"sourcegraph.com/sourcegraph/srclib/graph"
)

func init() {
	graph.RegisterMakeDefFormatter("rubygem", newDefFormatter)
	graph.RegisterMakeDefFormatter("ruby", newDefFormatter)
}

// DefData should be kept in sync with the def 'Data' field emitted by the Ruby
// grapher.
type DefData struct {
	RubyKind   string
	TypeString string
	Module     string
	RubyPath   string
	Signature  string
	ReturnType string
}

func (s *DefData) isLocalVar() bool {
	return strings.Contains(s.RubyPath, ">_local_")
}

func newDefFormatter(s *graph.Def) graph.DefFormatter {
	var si DefData
	if len(s.Data) > 0 {
		if err := json.Unmarshal(s.Data, &si); err != nil {
			panic("unmarshal Ruby def data: " + err.Error())
		}
	}
	return defFormatter{s, &si}
}

type defFormatter struct {
	def  *graph.Def
	data *DefData
}

func (f defFormatter) Language() string { return "Ruby" }

func (f defFormatter) DefKeyword() string {
	switch f.data.RubyKind {
	case "method":
		return "def"
	case "class", "module":
		return f.data.RubyKind
	}
	return ""
}

func (f defFormatter) Kind() string { return f.data.RubyKind }

func (f defFormatter) Name(qual graph.Qualification) string {
	if f.data.isLocalVar() {
		return f.def.Name
	}

	switch qual {
	case graph.Unqualified:
		return f.def.Name
	case graph.ScopeQualified:
		return f.data.RubyPath
	case graph.DepQualified:
		return f.data.RubyPath
	case graph.RepositoryWideQualified:
		return f.data.RubyPath
	case graph.LanguageWideQualified:
		return f.data.RubyPath
	}
	panic("Name: unhandled qual " + string(qual))
}

func (f defFormatter) NameAndTypeSeparator() string {
	if f.data.RubyKind == "method" {
		return ""
	}
	return " "
}

func (f defFormatter) Type(qual graph.Qualification) string {
	var ts string
	if f.data.RubyKind == "method" {
		if i := strings.Index(f.data.Signature, "("); i != -1 {
			ts = f.data.Signature[i:]
		}
		ts += " " + cleanType(f.data.ReturnType)
	} else {
		ts = cleanType(f.data.TypeString)
	}
	return strings.TrimPrefix(ts, "::")
}

func cleanType(t string) string {
	t = strings.TrimSuffix(t, "#")
	switch t {
	case "NilClass":
		return "nil"
	case "TrueClass":
		return "true"
	case "FalseClass":
		return "false"
	}
	return t
}
<|endoftext|>