<commit_before>package log4nova

import (
    "net/http"
    "github.com/Polarishq/bouncer/models"
    "sync"
    "time"
    "context"
    logger "github.com/Sirupsen/logrus"
    "github.com/Polarishq/bouncer/client/events"
    rtclient "github.com/go-openapi/runtime/client"
    "github.com/Polarishq/bouncer/client"
    "github.com/go-openapi/strfmt"
    "net/http/httputil"
    "strings"
    "bytes"
    "bufio"
    "github.com/x-cray/logrus-prefixed-formatter"
)

// Stats data structure
type NovaLogger struct {
    handler             http.Handler
    captureResponseBody bool
    readLock            sync.Mutex
    writeLock           sync.Mutex
    client              events.ClientInterface
    flushInterval       int
}

type loggingResponseWriter struct {
    headers     http.Header
    w           http.ResponseWriter
    data        []byte
    code        int
    captureBody bool
}

type novaLogFormat struct {

}

//NewNovaHandler creates a new instance of the Nova Logging Handler
func NewNovaHandler(handler http.Handler, captureResponseBody bool) *NovaLogger {
    return &NovaLogger{
        readLock:   sync.Mutex{},
        writeLock:  sync.Mutex{},
        client:     client.New(rtclient.New("", "", []string{}), strfmt.Default).Events,
        flushInterval: 1000,
    }
}

func (nl *NovaLogger) writeLogsToChannel(logs *bytes.Buffer, ch chan string) {
    scanner := bufio.NewScanner(logs)
    for scanner.Scan() {
        log := scanner.Text()

        ch <- log
    }
    close(ch)
    return
}

func (nl *NovaLogger) formatLogs(in chan string) chan *models.Event {
    //Format logs for splunk
    out := make(chan *models.Event)
        for {
            select {
            case log, ok := <-in:
                if !ok {
                    for {
                        if len(out) > 0 {
                            time.Sleep(100 * time.Millisecond)
                        } else {
                            break
                        }
                    }
                    break
                } else {
                    nl.readLock.Lock()
                    event := models.Event{
                        //Entity: i.entity,
                        //Source: i.source,
                        Event:  map[string]*string{"raw": &log},
                    }
                    out <- &event
                    nl.readLock.Unlock()
                }
            }
        }
    return out
}

func (nl *NovaLogger) flushFromOutputChannel(out chan *models.Event) error {
    for {
        select {
            case event, ok := <- out:
                if !ok {

                } else {
                    nl.writeLock.Lock()
                    ctx, cancel := context.WithTimeout(context.Background(), 5000*time.Millisecond)
                    defer cancel()
                    params := &events.EventsParams{
                        Events:  models.Events{event},
                        Input:   &"input type here",
                        Context: ctx,
                    }
                    auth := rtclient.BasicAuth("", "")
                    _, err := nl.client.Events(params, auth)

                    if err != nil {

                    } else {

                    }

                    nl.writeLock.Unlock()
                }
        }
        time.Sleep(time.Duration(nl.flushInterval) * time.Millisecond)
    }
}

//func (i *Input) Send(r io.Reader) {
//    mutex := sync.Mutex{}
//
//    events := inputModels.Events{}
//    log.Debugf("Starting scanner loop")
//
//    ch := make(chan string)
//
//    // Read from stdin, send all lines to a channel
//    go func(ch chan string) {
//        scanner := bufio.NewScanner(r)
//        for scanner.Scan() {
//            line := scanner.Text()
//            // log.Debugf("line: %s", line)
//            ch <- line
//        }
//        if err := scanner.Err(); err != nil {
//            log.WithError(err).Errorf("Error received from scanner")
//        }
//        close(ch)
//        return
//    }(ch)
//
//    // Read events slice, flush to Events endpoint
//    go func() {
//        for {
//            if len(events) > 0 {
//                mutex.Lock()
//                var ctx context.Context
//                var cancel context.CancelFunc
//                if i.ctx == nil {
//                    ctx, cancel = context.WithTimeout(context.Background(), 5000*time.Millisecond)
//                    defer cancel()
//                } else {
//                    ctx = i.ctx
//                }
//                params := &inputClientEvents.EventsParams{
//                    Events:  events,
//                    Input:   &i.input,
//                    Context: ctx,
//                }
//                eok, err := i.client.Events(params, i.creds.ClientAuth)
//                if eok != nil {
//                    log.Infof("Bytes: %d Events: %d", eok.Payload.Bytes, eok.Payload.Count)
//                }
//                if err != nil {
//                    log.Errorf("Error received from Events: %s", err)
//                }
//                events = inputModels.Events{}
//                mutex.Unlock()
//            }
//            time.Sleep(time.Duration(i.flushInterval) * time.Millisecond)
//        }
//    }()
//
//    // Read from channel, add to events Slice
//readloop:
//    for {
//        select {
//        case line, ok := <-ch:
//            if !ok {
//                for {
//                    if len(events) > 0 {
//                        log.Debugf("Waiting for events queue to empty")
//                        time.Sleep(100 * time.Millisecond)
//                    } else {
//                        break
//                    }
//                }
//                break readloop
//            } else {
//                mutex.Lock()
//                // log.Debugf("line: %s", line)
//                event := inputModels.Event{
//                    Entity: i.entity,
//                    Source: i.source,
//                    Event:  map[string]string{"raw": line},
//                }
//                events = append(events, &event)
//                mutex.Unlock()
//            }
//        }
//    }
//}

func stringify(r *http.Request) string {
    dump, _ := httputil.DumpRequest(r, true)
    return strings.Replace(string(dump), "\n", " ", -1)
}

func (nl *NovaLogger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // create logging
    buf := new(bytes.Buffer)
    logger.SetOutput(buf)
    logger.SetFormatter(&prefixed.TextFormatter{TimestampFormat: "Jan 02 03:04:05.000"})

    // Get your logs
    startTime := time.Now()
    logger.WithFields(logger.Fields{
        "request": stringify(r),
    }).Infof("Logging Request")

    //logger.Infof("LoggingHandler: request: %+v string_request %+v", r, stringify(r))
    lwr := loggingResponseWriter{w: w, captureBody: nl.captureResponseBody}
    nl.handler.ServeHTTP(&lwr, r)
    endTime := time.Now()
    logger.WithFields(logger.Fields{
        "response_code": lwr.code,
        "headers": lwr.headers,
        "body": string(lwr.data),
        "response_start": startTime,
        "response_end": endTime,
        "response_time": endTime.Sub(startTime),
    }).Infof("Logging Response")

    //Debugf("LoggingHandler: response code=%d header='%v' string_body='%+v' time=%v",
    //    lwr.code, lwr.headers, string(lwr.data), endTime.Sub(startTime))

    // Begin the output process
    in := make(chan string)
    go nl.writeLogsToChannel(buf, in)
    out := nl.formatLogs(in)
    go nl.flushFromOutputChannel(out)
}

func (lw *loggingResponseWriter) Write(b []byte) (int, error) {
    if lw.captureBody {
        lw.data = append(lw.data, b...)
    }
    return lw.w.Write(b)
}

func (lw *loggingResponseWriter) WriteHeader(code int) {
    lw.headers = lw.Header()
    lw.code = code
    lw.w.WriteHeader(code)
}

func (lw *loggingResponseWriter) Header() http.Header {
    return lw.w.Header()
}<commit_msg>Latest wip<commit_after>package log4nova

import (
    "net/http"
    "github.com/Polarishq/bouncer/models"
    "sync"
    "time"
    "context"
    logger "github.com/Sirupsen/logrus"
    "github.com/Polarishq/bouncer/client/events"
    rtclient "github.com/go-openapi/runtime/client"
    "github.com/Polarishq/bouncer/client"
    "github.com/go-openapi/strfmt"
    "net/http/httputil"
    "strings"
    "bytes"
    "bufio"
    "github.com/x-cray/logrus-prefixed-formatter"
    "os"
    "errors"
)

// Stats data structure
type NovaLogger struct {
    handler             http.Handler
    captureResponseBody bool
    readLock            sync.Mutex
    writeLock           sync.Mutex
    client              events.ClientInterface
    sendInterval        int
    clientID            string
    clientSecret        string
    host                string
}

type loggingResponseWriter struct {
    headers     http.Header
    w           http.ResponseWriter
    data        []byte
    code        int
    captureBody bool
}

type novaLogFormat struct {

}

//NewNovaHandler creates a new instance of the Nova Logging Handler
func NewNovaHandler(handler http.Handler, captureResponseBody bool) *NovaLogger {
    clientID := os.Getenv("NOVA_CLIENT_ID")
    clientSecret := os.Getenv("NOVA_CLIENT_SECRET")
    if clientID == "" || clientSecret == "" {
        panic(errors.New("Client ID or Client Secret not set properly on env"))
    }

    return &NovaLogger{
        readLock:   sync.Mutex{},
        writeLock:  sync.Mutex{},
        client:     client.New(rtclient.New(client.DefaultHost, client.DefaultBasePath, client.DefaultSchemes), strfmt.Default).Events,
        sendInterval: 1000,
        clientID: clientID,
        clientSecret: clientSecret,
    }
}

func (nl *NovaLogger) writeLogsToChannel(logs *bytes.Buffer, ch chan string) {
    scanner := bufio.NewScanner(logs)
    for scanner.Scan() {
        log := scanner.Text()

        ch <- log
    }
    close(ch)
    return
}

func (nl *NovaLogger) formatLogs(in chan string) chan *models.Event {
    //Format logs for splunk
    out := make(chan *models.Event)
        for {
            select {
            case log, ok := <-in:
                if !ok {
                    for {
                        if len(out) > 0 {
                            time.Sleep(time.Duration(nl.sendInterval)/2 * time.Millisecond)
                        } else {
                            break
                        }
                    }
                    break
                } else {
                    nl.readLock.Lock()
                    event := models.Event{
                        Entity: "log4nova",
                        Source: nl.host,
                        Event:  map[string]*string{"raw": &log},
                    }
                    out <- &event
                    nl.readLock.Unlock()
                }
            }
        }
    return out
}

func (nl *NovaLogger) flushFromOutputChannel(out chan *models.Event) error {
    for {
        select {
            case event, ok := <- out:
                if !ok {

                } else {
                    nl.writeLock.Lock()
                    ctx, cancel := context.WithTimeout(context.Background(), 5000*time.Millisecond)
                    defer cancel()
                    params := &events.EventsParams{
                        Events:  models.Events{event},
                        Input:   &"input type here",
                        Context: ctx,
                    }
                    auth := rtclient.BasicAuth("", "")
                    _, err := nl.client.Events(params, auth)

                    if err != nil {

                    } else {

                    }

                    nl.writeLock.Unlock()
                }
        }
        time.Sleep(time.Duration(nl.sendInterval) * time.Millisecond)
    }
}

func stringify(r *http.Request) string {
    dump, _ := httputil.DumpRequest(r, true)
    return strings.Replace(string(dump), "\n", " ", -1)
}

func (nl *NovaLogger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    nl.host = r.Host
    // create logging
    buf := new(bytes.Buffer)
    logger.SetOutput(buf)
    logger.SetFormatter(&prefixed.TextFormatter{TimestampFormat: "Jan 02 03:04:05.000"})

    // Get your logs
    startTime := time.Now()
    logger.WithFields(logger.Fields{
        "request": stringify(r),
    }).Infof("Logging Request")

    lwr := loggingResponseWriter{w: w, captureBody: nl.captureResponseBody}
    nl.handler.ServeHTTP(&lwr, r)
    endTime := time.Now()
    logger.WithFields(logger.Fields{
        "response_code": lwr.code,
        "headers": lwr.headers,
        "body": string(lwr.data),
        "response_start": startTime,
        "response_end": endTime,
        "response_time": endTime.Sub(startTime),
    }).Infof("Logging Response")

    // Begin the output process
    in := make(chan string)
    go nl.writeLogsToChannel(buf, in)
    out := nl.formatLogs(in)
    go nl.flushFromOutputChannel(out)
}

func (lw *loggingResponseWriter) Write(b []byte) (int, error) {
    if lw.captureBody {
        lw.data = append(lw.data, b...)
    }
    return lw.w.Write(b)
}

func (lw *loggingResponseWriter) WriteHeader(code int) {
    lw.headers = lw.Header()
    lw.code = code
    lw.w.WriteHeader(code)
}

func (lw *loggingResponseWriter) Header() http.Header {
    return lw.w.Header()
}<|endoftext|>


<commit_before>package mmbot

import (
	"fmt"
	"mmbot/message"
	"regexp"
)

type Handler interface {
	CanHandle(*message.InMessage) bool
	Handle(*message.InMessage) error
}

type HandlerAction func(*message.InMessage) error

type PatternHandler struct {
	MessageType message.Type
	Pattern     *regexp.Regexp
	Action      HandlerAction
}

func (h *PatternHandler) CanHandle(msg *message.InMessage) bool {
	_, ok := h.matchPattern(msg)
	return ok
}

func (h *PatternHandler) Handle(msg *message.InMessage) error {
	matches, ok := h.matchPattern(msg)
	if !ok {
		return fmt.Errorf("Cannot handle message: %#v", msg)
	}
	msg.Matches = matches

	if err := h.Action(msg); err != nil {
		return err
	}

	return nil
}

func (h *PatternHandler) matchPattern(msg *message.InMessage) ([]string, bool) {
	if !h.matchMessageType(msg.Type) {
		return nil, false
	}

	if msg.Type == message.MentionMessage {
		mentionName := msg.MentionName()
		if mentionName != msg.Sender.SenderName() {
			return nil, false
		}
	}

	text := msg.Text
	if msg.Type == message.MentionMessage {
		text = msg.MentionlessText()
	}

	matches := h.Pattern.FindStringSubmatch(text)
	if matches == nil {
		return nil, false
	}

	return matches, true
}

func (h *PatternHandler) matchMessageType(t message.Type) bool {
	if h.MessageType == 0 {
		return true
	}
	return t&h.MessageType != 0
}

func (h *PatternHandler) trimBotName(text string, name string) string {
	pattern := fmt.Sprintf(`\A@?(?:%s)\s*[:,]?\s+`, regexp.QuoteMeta(name))
	re := regexp.MustCompile(pattern)
	if loc := re.FindStringIndex(text); loc != nil {
		return text[loc[1]:]
	}

	return text
}
<commit_msg>Fix PatternHandler<commit_after>package mmbot

import (
	"fmt"
	"mmbot/message"
	"regexp"
)

type Handler interface {
	CanHandle(*message.InMessage) bool
	Handle(*message.InMessage) error
}

type HandlerAction func(*message.InMessage) error

type PatternHandler struct {
	MessageType message.Type
	Pattern     *regexp.Regexp
	Action      HandlerAction
}

func (h PatternHandler) CanHandle(msg *message.InMessage) bool {
	_, ok := h.matchPattern(msg)
	return ok
}

func (h PatternHandler) Handle(msg *message.InMessage) error {
	matches, ok := h.matchPattern(msg)
	if !ok {
		return fmt.Errorf("Cannot handle message: %#v", msg)
	}
	msg.Matches = matches

	if err := h.Action(msg); err != nil {
		return err
	}

	return nil
}

func (h PatternHandler) matchPattern(msg *message.InMessage) ([]string, bool) {
	if !h.matchMessageType(msg.Type) {
		return nil, false
	}

	if msg.Type == message.MentionMessage {
		mentionName := msg.MentionName()
		if mentionName != msg.Sender.SenderName() {
			return nil, false
		}
	}

	text := msg.Text
	if msg.Type == message.MentionMessage {
		text = msg.MentionlessText()
	}

	matches := h.Pattern.FindStringSubmatch(text)
	if matches == nil {
		return nil, false
	}

	return matches, true
}

func (h PatternHandler) matchMessageType(t message.Type) bool {
	if h.MessageType == 0 {
		return true
	}
	return t&h.MessageType != 0
}

func (h PatternHandler) trimBotName(text string, name string) string {
	pattern := fmt.Sprintf(`\A@?(?:%s)\s*[:,]?\s+`, regexp.QuoteMeta(name))
	re := regexp.MustCompile(pattern)
	if loc := re.FindStringIndex(text); loc != nil {
		return text[loc[1]:]
	}

	return text
}
<|endoftext|>


<commit_before>/*
Package compress provides a clever gzip compressing handler.

It takes care to not handle small contents, or contents that are already compressed (like JPEG, MPEG or PDF).
Trying to gzip them not only wastes CPU but can potentially increase the response size.

Make sure to include this handler above any other handler that alter the response body.
*/
package compress

import (
	"compress/gzip"
	"net/http"
	"strconv"
	"strings"
	"sync"
)

const gzippableMinSize = 1400

var gzipPool = sync.Pool{New: func() interface{} { return gzip.NewWriter(nil) }}

var notGzippableTypes = map[string]struct{}{
	"application/font-woff": {},
	"application/gzip":      {},
	"application/pdf":       {},
	"application/zip":       {},
	"audio/mp4":             {},
	"audio/mpeg":            {},
	"audio/webm":            {},
	"image/gif":             {},
	"image/jpeg":            {},
	"image/png":             {},
	"image/webp":            {},
	"video/h264":            {},
	"video/mp4":             {},
	"video/mpeg":            {},
	"video/ogg":             {},
	"video/vp8":             {},
	"video/webm":            {},
}

// An Handler provides a clever gzip compressing handler.
type Handler struct {
	Next http.Handler
}

// Handle returns a Handler wrapping another http.Handler.
func Handle(h http.Handler) *Handler {
	return &Handler{h}
}

// HandleFunc returns a Handler wrapping an http.HandlerFunc.
func HandleFunc(f http.HandlerFunc) *Handler {
	return Handle(f)
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Vary", "Accept-Encoding")

	if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || r.Header.Get("Sec-WebSocket-Key") != "" {
		h.Next.ServeHTTP(w, r)
		return
	}

	cw := &compressWriter{
		ResponseWriter: w,
		gzipWriter:     gzipPool.Get().(*gzip.Writer),
	}
	defer gzipPool.Put(cw.gzipWriter)
	defer cw.close()

	h.Next.ServeHTTP(cw, r)
}

// compressWriter binds the downstream repsonse writing into gzipWriter if the first content is detected as gzippable.
type compressWriter struct {
	http.ResponseWriter
	gzipWriter *gzip.Writer
	gzipDetect bool // gzipDetect tells if the gzippable detection has been done.
	gzipUse    bool // gzipUse tells if gzip is used for the response.
	status     int
}

// WriteHeader catches a downstream WriteHeader call and caches the status code.
// The header will be written later, at the first Write call, after the gzipping detection has been done.
func (cw *compressWriter) WriteHeader(status int) {
	cw.status = status
}

// writePostponedHeader writes the response header with the cached status code.
func (cw *compressWriter) writePostponedHeader() {
	if cw.status == 0 {
		cw.status = http.StatusOK
	}
	cw.ResponseWriter.WriteHeader(cw.status)
}

// Write sets the compressing headers and calls the gzip writer, but only if the Content-Type header defines a compressible content.
// Otherwise, it calls the original Write method.
func (cw *compressWriter) Write(b []byte) (int, error) {
	if !cw.gzipDetect {
		cl, _ := strconv.Atoi(cw.ResponseWriter.Header().Get("Content-Length"))
		if cl < 1 {
			cl = len(b) // If no Content-Length, take the length of this first chunk.
		}

		ct := cw.ResponseWriter.Header().Get("Content-Type")
		if ct == "" {
			ct = http.DetectContentType(b)
			cw.ResponseWriter.Header().Set("Content-Type", ct)
		}

		if isGzippable(cl, ct) {
			cw.gzipUse = true
			cw.setGzipHeaders()
			cw.gzipWriter.Reset(cw.ResponseWriter)
		}

		cw.writePostponedHeader()
		cw.gzipDetect = true
	}

	if cw.gzipUse {
		return cw.gzipWriter.Write(b)
	}
	return cw.ResponseWriter.Write(b)
}

// close closes the gzip writer if it has been used.
func (cw *compressWriter) close() {
	if cw.gzipUse {
		cw.gzipWriter.Close()
	}
}

// setGzipHeaders sets the Content-Encoding header for a gzip response.
// Because the compressed content will have a new size, it also removes the Content-Length header as it could have been set downstream by another handler.
func (cw *compressWriter) setGzipHeaders() {
	cw.ResponseWriter.Header().Del("Content-Length")
	cw.ResponseWriter.Header().Set("Content-Encoding", "gzip")
}

// isGzippable checks if a content must be compressed following its content length (cl) and content type (ct).
func isGzippable(cl int, ct string) bool {
	if cl < gzippableMinSize || ct == "" {
		return false
	}

	_, ok := notGzippableTypes[strings.ToLower(strings.SplitN(ct, ";", 2)[0])]
	return !ok
}
<commit_msg>isGzippable refactoring<commit_after>/*
Package compress provides a clever gzip compressing handler.

It takes care to not handle small contents, or contents that are already compressed (like JPEG, MPEG or PDF).
Trying to gzip them not only wastes CPU but can potentially increase the response size.

Make sure to include this handler above any other handler that alter the response body.
*/
package compress

import (
	"compress/gzip"
	"net/http"
	"strconv"
	"strings"
	"sync"
)

const gzippableMinSize = 1400

var gzipPool = sync.Pool{New: func() interface{} { return gzip.NewWriter(nil) }}

var notGzippableTypes = map[string]struct{}{
	"application/font-woff": {},
	"application/gzip":      {},
	"application/pdf":       {},
	"application/zip":       {},
	"audio/mp4":             {},
	"audio/mpeg":            {},
	"audio/webm":            {},
	"image/gif":             {},
	"image/jpeg":            {},
	"image/png":             {},
	"image/webp":            {},
	"video/h264":            {},
	"video/mp4":             {},
	"video/mpeg":            {},
	"video/ogg":             {},
	"video/vp8":             {},
	"video/webm":            {},
}

// An Handler provides a clever gzip compressing handler.
type Handler struct {
	Next http.Handler
}

// Handle returns a Handler wrapping another http.Handler.
func Handle(h http.Handler) *Handler {
	return &Handler{h}
}

// HandleFunc returns a Handler wrapping an http.HandlerFunc.
func HandleFunc(f http.HandlerFunc) *Handler {
	return Handle(f)
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Vary", "Accept-Encoding")

	if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || r.Header.Get("Sec-WebSocket-Key") != "" {
		h.Next.ServeHTTP(w, r)
		return
	}

	cw := &compressWriter{
		ResponseWriter: w,
		gzipWriter:     gzipPool.Get().(*gzip.Writer),
	}
	defer gzipPool.Put(cw.gzipWriter)
	defer cw.close()

	h.Next.ServeHTTP(cw, r)
}

// compressWriter binds the downstream repsonse writing into gzipWriter if the first content is detected as gzippable.
type compressWriter struct {
	http.ResponseWriter
	gzipWriter *gzip.Writer
	gzipDetect bool // gzipDetect tells if the gzippable detection has been done.
	gzipUse    bool // gzipUse tells if gzip is used for the response.
	status     int
}

// WriteHeader catches a downstream WriteHeader call and caches the status code.
// The header will be written later, at the first Write call, after the gzipping detection has been done.
func (cw *compressWriter) WriteHeader(status int) {
	cw.status = status
}

// writePostponedHeader writes the response header with the cached status code.
func (cw *compressWriter) writePostponedHeader() {
	if cw.status == 0 {
		cw.status = http.StatusOK
	}
	cw.ResponseWriter.WriteHeader(cw.status)
}

// Write sets the compressing headers and calls the gzip writer, but only if the Content-Type header defines a compressible content.
// Otherwise, it calls the original Write method.
func (cw *compressWriter) Write(b []byte) (int, error) {
	if !cw.gzipDetect {
		cl, _ := strconv.Atoi(cw.ResponseWriter.Header().Get("Content-Length"))
		if cl < 1 {
			cl = len(b) // If no Content-Length, take the length of this first chunk.
		}

		ct := cw.ResponseWriter.Header().Get("Content-Type")
		if ct == "" {
			ct = http.DetectContentType(b)
			cw.ResponseWriter.Header().Set("Content-Type", ct)
		}

		if isGzippable(cl, ct) {
			cw.gzipUse = true
			cw.setGzipHeaders()
			cw.gzipWriter.Reset(cw.ResponseWriter)
		}

		cw.writePostponedHeader()
		cw.gzipDetect = true
	}

	if cw.gzipUse {
		return cw.gzipWriter.Write(b)
	}
	return cw.ResponseWriter.Write(b)
}

// close closes the gzip writer if it has been used.
func (cw *compressWriter) close() {
	if cw.gzipUse {
		cw.gzipWriter.Close()
	}
}

// setGzipHeaders sets the Content-Encoding header for a gzip response.
// Because the compressed content will have a new size, it also removes the Content-Length header as it could have been set downstream by another handler.
func (cw *compressWriter) setGzipHeaders() {
	cw.ResponseWriter.Header().Del("Content-Length")
	cw.ResponseWriter.Header().Set("Content-Encoding", "gzip")
}

// isGzippable checks if a content must be compressed following its content length (cl) and content type (ct).
func isGzippable(cl int, ct string) bool {
	if cl < gzippableMinSize || ct == "" {
		return false
	}

	if i := strings.IndexByte(ct, ';'); i >= 0 {
		ct = ct[:i]
	}
	ct = strings.ToLower(ct)
	_, ok := notGzippableTypes[ct]
	return !ok
}
<|endoftext|>


<commit_before>package darwini

import (
	"net/http"

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

// Handler is a HTTP handler that also takes a Context.
type Handler interface {
	ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request)
}

// HandlerFunc is an adapter that allows the use of functions or
// methods as Handlers.
type HandlerFunc func(ctx context.Context, w http.ResponseWriter, req *http.Request)

var _ Handler = HandlerFunc(nil)

func (fn HandlerFunc) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	fn(ctx, w, req)
}

// WithContext adapts a darwini.Handler to work as a net/http.Handler.
// The context will be canceled when the HTTP client disconnects
// early.
func WithContext(h Handler) http.Handler {
	return withContext{h}
}

type withContext struct {
	Handler
}

var _ http.Handler = withContext{}

func (h withContext) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	if n, ok := w.(http.CloseNotifier); ok {
		gone := n.CloseNotify()
		go func() {
			select {
			case <-ctx.Done():
				return
			case <-gone:
				cancel()
			}
		}()
	}

	h.Handler.ServeHTTP(ctx, w, req)
}

// NoContext adapts a net/http Handler to work as a darwini.Handler.
// Context deadlines or cancellation are not respected.
func NoContext(h http.Handler) Handler {
	return noContext{h}
}

type noContext struct {
	http.Handler
}

var _ Handler = noContext{}

func (h noContext) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	h.Handler.ServeHTTP(w, req)
}
<commit_msg>WithContext docs: fix bad sentence<commit_after>package darwini

import (
	"net/http"

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

// Handler is a HTTP handler that also takes a Context.
type Handler interface {
	ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request)
}

// HandlerFunc is an adapter that allows the use of functions or
// methods as Handlers.
type HandlerFunc func(ctx context.Context, w http.ResponseWriter, req *http.Request)

var _ Handler = HandlerFunc(nil)

func (fn HandlerFunc) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	fn(ctx, w, req)
}

// WithContext adapts a darwini.Handler to work as a net/http.Handler.
// The context will be canceled when the HTTP client disconnects.
func WithContext(h Handler) http.Handler {
	return withContext{h}
}

type withContext struct {
	Handler
}

var _ http.Handler = withContext{}

func (h withContext) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	if n, ok := w.(http.CloseNotifier); ok {
		gone := n.CloseNotify()
		go func() {
			select {
			case <-ctx.Done():
				return
			case <-gone:
				cancel()
			}
		}()
	}

	h.Handler.ServeHTTP(ctx, w, req)
}

// NoContext adapts a net/http Handler to work as a darwini.Handler.
// Context deadlines or cancellation are not respected.
func NoContext(h http.Handler) Handler {
	return noContext{h}
}

type noContext struct {
	http.Handler
}

var _ Handler = noContext{}

func (h noContext) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	h.Handler.ServeHTTP(w, req)
}
<|endoftext|>


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

package main

import (
	"crypto/rand"
	"crypto/sha512"
	"encoding/json"
	"fmt"
	"labix.org/v2/mgo/bson"
	"net/http"
)

func newPassword() string {
	var random [32]byte
	rand.Read(random[:])
	h := sha512.New()
	h.Sum([]byte(bson.NewObjectId().Hex()))
	h.Sum(random[:])
	return fmt.Sprintf("%x", h.Sum(nil))
}

func Add(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusCreated)
}

func Bind(w http.ResponseWriter, r *http.Request) error {
	name := r.URL.Query().Get(":name")
	database := session().DB(name)
	err := database.AddUser(name, "", false)
	if err != nil {
		return err
	}
	data := map[string]string{
		"MONGO_URI":           coalesceEnv("127.0.0.1:27017", "MONGODB_PUBLIC_URI", "MONGODB_URI"),
		"MONGO_USER":          name,
		"MONGO_PASSWORD":      newPassword(),
		"MONGO_DATABASE_NAME": name,
	}
	b, err := json.Marshal(&data)
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	_, err = w.Write(b)
	return err
}

func Unbind(w http.ResponseWriter, r *http.Request) error {
	name := r.URL.Query().Get(":name")
	database := session().DB(name)
	err := database.RemoveUser(name)
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

func Remove(w http.ResponseWriter, r *http.Request) error {
	name := r.URL.Query().Get(":name")
	err := session().DB(name).DropDatabase()
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

func Status(w http.ResponseWriter, r *http.Request) error {
	if err := session().Ping(); err != nil {
		return err
	}
	w.WriteHeader(http.StatusNoContent)
	return nil
}

type Handler func(http.ResponseWriter, *http.Request) error

func (fn Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := fn(w, r); err != nil {
		http.Error(w, err.Error(), 500)
	}
}
<commit_msg>handler: fix user creation<commit_after>// Copyright 2013 mongoapi authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"crypto/rand"
	"crypto/sha512"
	"encoding/json"
	"fmt"
	"labix.org/v2/mgo/bson"
	"net/http"
)

func newPassword() string {
	var random [32]byte
	rand.Read(random[:])
	h := sha512.New()
	h.Sum([]byte(bson.NewObjectId().Hex()))
	h.Sum(random[:])
	return fmt.Sprintf("%x", h.Sum(nil))
}

func Add(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusCreated)
}

func Bind(w http.ResponseWriter, r *http.Request) error {
	password := newPassword()
	name := r.URL.Query().Get(":name")
	database := session().DB(name)
	err := database.AddUser(name, password, false)
	if err != nil {
		return err
	}
	data := map[string]string{
		"MONGO_URI":           coalesceEnv("127.0.0.1:27017", "MONGODB_PUBLIC_URI", "MONGODB_URI"),
		"MONGO_USER":          name,
		"MONGO_PASSWORD":      password,
		"MONGO_DATABASE_NAME": name,
	}
	b, err := json.Marshal(&data)
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	_, err = w.Write(b)
	return err
}

func Unbind(w http.ResponseWriter, r *http.Request) error {
	name := r.URL.Query().Get(":name")
	database := session().DB(name)
	err := database.RemoveUser(name)
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

func Remove(w http.ResponseWriter, r *http.Request) error {
	name := r.URL.Query().Get(":name")
	err := session().DB(name).DropDatabase()
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

func Status(w http.ResponseWriter, r *http.Request) error {
	if err := session().Ping(); err != nil {
		return err
	}
	w.WriteHeader(http.StatusNoContent)
	return nil
}

type Handler func(http.ResponseWriter, *http.Request) error

func (fn Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := fn(w, r); err != nil {
		http.Error(w, err.Error(), 500)
	}
}
<|endoftext|>


<commit_before>package darwini

import (
	"net/http"

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

// Handler is a HTTP handler that also takes a Context.
type Handler interface {
	ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request)
}

// HandlerFunc is an adapter that allows the use of functions or
// methods as Handlers.
type HandlerFunc func(ctx context.Context, w http.ResponseWriter, req *http.Request)

var _ Handler = HandlerFunc(nil)

func (fn HandlerFunc) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	fn(ctx, w, req)
}
<commit_msg>WithContext and NoContext connect mux.Handlers and net/http.Handlers<commit_after>package darwini

import (
	"net/http"

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

// Handler is a HTTP handler that also takes a Context.
type Handler interface {
	ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request)
}

// HandlerFunc is an adapter that allows the use of functions or
// methods as Handlers.
type HandlerFunc func(ctx context.Context, w http.ResponseWriter, req *http.Request)

var _ Handler = HandlerFunc(nil)

func (fn HandlerFunc) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	fn(ctx, w, req)
}

// WithContext adapts a darwini.Handler to work as a net/http.Handler.
// The context will be canceled when the HTTP client disconnects
// early.
func WithContext(h Handler) http.Handler {
	return withContext{h}
}

type withContext struct {
	Handler
}

var _ http.Handler = withContext{}

func (h withContext) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	if n, ok := w.(http.CloseNotifier); ok {
		gone := n.CloseNotify()
		go func() {
			select {
			case <-ctx.Done():
				return
			case <-gone:
				cancel()
			}
		}()
	}

	h.Handler.ServeHTTP(ctx, w, req)
}

// NoContext adapts a net/http Handler to work as a darwini.Handler.
// Context deadlines or cancellation are not respected.
func NoContext(h http.Handler) Handler {
	return noContext{h}
}

type noContext struct {
	http.Handler
}

var _ Handler = noContext{}

func (h noContext) ServeHTTP(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	h.Handler.ServeHTTP(w, req)
}
<|endoftext|>


<commit_before>// Package infuse provides an immutable, concurrency-safe middleware handler
// that conforms to http.Handler. An infuse.Handler is fully compatible with
// the standard library, supports flexible chaining, and provides a shared
// context between middleware handlers within a single request without
// relying on global state, locks, or shared closures.
package infuse

import "net/http"

// A Handler is a middleware handler that conforms to http.Handler.
//
// An http.Handler passed to the Handle method can call the http.Handler
// provided immediately after it using infuse.Next. All handlers within a
// single request-response cycle can share data of any type using infuse.Get
// and infuse.Set.
type Handler interface {
	// Handle returns a new infuse.Handler that serves the provided
	// http.Handler after all existing http.Handlers attached to the old
	// infuse.Handler are served. The provided http.Handler will be called
	// if and only if the previously-provided http.Handler calls infuse.Next
	// or there is no previously-provided http.Handler.
	//
	// The provided http.Handler may be an infuse.Handler itself. However,
	// calls to infuse.Next inside of a nested infuse.Handler are local to that
	// infuse.Handler and will not cause handlers outside of it to be called.
	// Therefore, for infuse.Handlers A and B and http.Handler C,
	//   A.Handle(B).Handle(C)
	// will never serve http.Handler C, but
	//   A.Handle(B.Handle(C))
	// may serve http.Handler C.
	Handle(handler http.Handler) Handler

	// HandleFunc has the same behavior as Handle, but it takes a handler
	// function instead of an http.Handler.
	HandleFunc(handler func(http.ResponseWriter, *http.Request)) Handler

	// Stack has the same behavior as Handle but will implicitly serve an
	// http.Handler attached after the provided http.Handler, if another
	// http.Handler is attached. The provided http.Handler will still only be
	// called if the previously-provided http.Handler calls infuse.Next or
	// there is no previously-provided http.Handler.
	//
	// Stack is useful for serving generic handlers that do not know about
	// infuse. It can also be used to serve another infuse.Handler.
	//
	// Note that for infuse.Handlers A and B and http.Handler C,
	//   A.Handle(B).Handle(C)
	// will never serve http.Handler C. While
	//   A.Stack(B).Handle(C)
	// will always serve http.Handler C after infuse.Handler B is served.
	// However, it is preferable to use
	//   A.Handle(B.Handle(C))
	// as it permits serving C when the last http.Handler attached to B calls
	// infuse.Next.
	//
	// Finally, do not call infuse.Next in a stacked http.Handler unless you
	// intend to serve the rest of the middleware chain multiple times.
	Stack(handler http.Handler) Handler

	// StackFunc is the same as Stack, but it takes a handler function
	// instead of an http.Handler.
	StackFunc(handler func(http.ResponseWriter, *http.Request)) Handler

	// ServeHTTP serves the infuse.Handler, starting with the first
	// http.Handler attached.
	ServeHTTP(response http.ResponseWriter, request *http.Request)
}

// New returns a new infuse.Handler.
func New() Handler {
	return (*layer)(nil)
}

type layer struct {
	handler http.Handler
	prev    *layer
}

func (l *layer) Handle(handler http.Handler) Handler {
	return &layer{handler, l}
}

func (l *layer) HandleFunc(handler func(http.ResponseWriter, *http.Request)) Handler {
	return l.Handle(http.HandlerFunc(handler))
}

func (l *layer) Stack(handler http.Handler) Handler {
	return l.HandleFunc(func(response http.ResponseWriter, request *http.Request) {
		handler.ServeHTTP(response, request)
		Next(response, request)
	})
}

func (l *layer) StackFunc(handler func(http.ResponseWriter, *http.Request)) Handler {
	return l.Stack(http.HandlerFunc(handler))
}

func (l *layer) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	if l == nil {
		return
	}

	sharedResponse := &contextualResponse{ResponseWriter: response}

	current := l
	for ; current.prev != nil; current = current.prev {
		sharedResponse.layers = append(sharedResponse.layers, current)
	}
	current.handler.ServeHTTP(sharedResponse, request)
}

type contextualResponse struct {
	http.ResponseWriter
	context interface{}
	layers  []*layer
}

func (c *contextualResponse) next(request *http.Request) bool {
	if len(c.layers) == 0 {
		return false
	}

	originalLayers := c.layers
	nextLayer := c.layers[len(c.layers)-1]
	c.layers = c.layers[:len(c.layers)-1]
	defer func() { c.layers = originalLayers }()

	nextLayer.handler.ServeHTTP(c, request)
	return true
}

// Next serves the next http.Handler. Next should only be called from an
// http.Handler attached to an infuse.Handler. See infuse.Handler for more
// information.
//
// Next will return false if no subsequent http.Handler is attached, or if the
// provided http.ResponseWriter was not served by an infuse.Handler. For Next
// to successfully serve the correct handler and return true, the response
// must be the same http.ResponseWriter that the current http.Handler was
// called with (via its infuse.Handler).
//
// Calling Next multiple times in the same handler will run the rest of the
// middleware chain attached to the infuse.Handler for each call.
func Next(response http.ResponseWriter, request *http.Request) bool {
	sharedResponse, ok := response.(*contextualResponse)
	return ok && sharedResponse.next(request)
}

// Get will retrieve a context value that is shared by each http.Handler
// attached to the same infuse.Handler within a single request-response cycle.
// http.Handlers that are attached to different infuse.Handlers do not share
// the same context value.
//
// If the context value is a pointer, map, or slice, changes to the referent
// data will be seen by other http.Handlers that share the context value. If
// called with an invalid response, Get returns nil.
//
// To retrieve a value of a particular type, consider wrapping infuse.Get:
//   func GetMyContext(response http.ResponseWriter) *MyContext {
//      return infuse.Get(response).(*MyContext)
//   }
//
// Example using a map:
//   func HandlerMap(response http.ResponseWriter) map[string]string {
//      handlerMap, ok := infuse.Get(response).(map[string]string)
//      if !ok || handlerMap == nil {
//         handlerMap = make(map[string]string)
//         if ok := infuse.Set(response, handlerMap); !ok {
//            return nil
//         }
//      }
//      return handlerMap
//   }
func Get(response http.ResponseWriter) interface{} {
	sharedResponse, ok := response.(*contextualResponse)
	if !ok {
		return nil
	}
	return sharedResponse.context
}

// Set will store a context value that is shared by the each http.Handler
// attached to the same infuse.Handler within a single request-response cycle.
// http.Handlers that are attached to different infuse.Handlers do not share
// the same context value. Set will return false if the response is invalid.
func Set(response http.ResponseWriter, value interface{}) bool {
	sharedResponse, ok := response.(*contextualResponse)
	if !ok {
		return false
	}
	sharedResponse.context = value
	return true
}
<commit_msg>Make response type more immutable<commit_after>// Package infuse provides an immutable, concurrency-safe middleware handler
// that conforms to http.Handler. An infuse.Handler is fully compatible with
// the standard library, supports flexible chaining, and provides a shared
// context between middleware handlers within a single request without
// relying on global state, locks, or shared closures.
package infuse

import "net/http"

// A Handler is a middleware handler that conforms to http.Handler.
//
// An http.Handler passed to the Handle method can call the http.Handler
// provided immediately after it using infuse.Next. All handlers within a
// single request-response cycle can share data of any type using infuse.Get
// and infuse.Set.
type Handler interface {
	// Handle returns a new infuse.Handler that serves the provided
	// http.Handler after all existing http.Handlers attached to the old
	// infuse.Handler are served. The provided http.Handler will be called
	// if and only if the previously-provided http.Handler calls infuse.Next
	// or there is no previously-provided http.Handler.
	//
	// The provided http.Handler may be an infuse.Handler itself. However,
	// calls to infuse.Next inside of a nested infuse.Handler are local to that
	// infuse.Handler and will not cause handlers outside of it to be called.
	// Therefore, for infuse.Handlers A and B and http.Handler C,
	//   A.Handle(B).Handle(C)
	// will never serve http.Handler C, but
	//   A.Handle(B.Handle(C))
	// may serve http.Handler C.
	Handle(handler http.Handler) Handler

	// HandleFunc has the same behavior as Handle, but it takes a handler
	// function instead of an http.Handler.
	HandleFunc(handler func(http.ResponseWriter, *http.Request)) Handler

	// Stack has the same behavior as Handle but will implicitly serve an
	// http.Handler attached after the provided http.Handler, if another
	// http.Handler is attached. The provided http.Handler will still only be
	// called if the previously-provided http.Handler calls infuse.Next or
	// there is no previously-provided http.Handler.
	//
	// Stack is useful for serving generic handlers that do not know about
	// infuse. It can also be used to serve another infuse.Handler.
	//
	// Note that for infuse.Handlers A and B and http.Handler C,
	//   A.Handle(B).Handle(C)
	// will never serve http.Handler C. While
	//   A.Stack(B).Handle(C)
	// will always serve http.Handler C after infuse.Handler B is served.
	// However, it is preferable to use
	//   A.Handle(B.Handle(C))
	// as it permits serving C when the last http.Handler attached to B calls
	// infuse.Next.
	//
	// Finally, do not call infuse.Next in a stacked http.Handler unless you
	// intend to serve the rest of the middleware chain multiple times.
	Stack(handler http.Handler) Handler

	// StackFunc is the same as Stack, but it takes a handler function
	// instead of an http.Handler.
	StackFunc(handler func(http.ResponseWriter, *http.Request)) Handler

	// ServeHTTP serves the infuse.Handler, starting with the first
	// http.Handler attached.
	ServeHTTP(response http.ResponseWriter, request *http.Request)
}

// New returns a new infuse.Handler.
func New() Handler {
	return (*layer)(nil)
}

type layer struct {
	handler http.Handler
	prev    *layer
}

func (l *layer) Handle(handler http.Handler) Handler {
	return &layer{handler, l}
}

func (l *layer) HandleFunc(handler func(http.ResponseWriter, *http.Request)) Handler {
	return l.Handle(http.HandlerFunc(handler))
}

func (l *layer) Stack(handler http.Handler) Handler {
	return l.HandleFunc(func(response http.ResponseWriter, request *http.Request) {
		handler.ServeHTTP(response, request)
		Next(response, request)
	})
}

func (l *layer) StackFunc(handler func(http.ResponseWriter, *http.Request)) Handler {
	return l.Stack(http.HandlerFunc(handler))
}

func (l *layer) ServeHTTP(response http.ResponseWriter, request *http.Request) {
	if l == nil {
		return
	}

	sharedResponse := newLayeredResponse(response)
	current := l
	for ; current.prev != nil; current = current.prev {
		sharedResponse.layers = append(sharedResponse.layers, current)
	}
	current.handler.ServeHTTP(sharedResponse, request)
}

type layeredResponse struct {
	*contextualResponse
	layers []*layer
}

type contextualResponse struct {
	http.ResponseWriter
	context interface{}
}

func newLayeredResponse(response http.ResponseWriter) *layeredResponse {
	return &layeredResponse{&contextualResponse{response, nil}, nil}
}

func (l *layeredResponse) next(request *http.Request) bool {
	if len(l.layers) == 0 {
		return false
	}

	next := l.layers[len(l.layers)-1]
	remaining := l.layers[:len(l.layers)-1]
	sharedResponse := &layeredResponse{l.contextualResponse, remaining}
	next.handler.ServeHTTP(sharedResponse, request)
	return true
}

// Next serves the next http.Handler. Next should only be called from an
// http.Handler attached to an infuse.Handler. See infuse.Handler for more
// information.
//
// Next will return false if no subsequent http.Handler is attached, or if the
// provided http.ResponseWriter was not served by an infuse.Handler. For Next
// to successfully serve the correct handler and return true, the response
// must be the same http.ResponseWriter that the current http.Handler was
// called with (via its infuse.Handler).
//
// Calling Next multiple times in the same handler will run the rest of the
// middleware chain attached to the infuse.Handler for each call.
func Next(response http.ResponseWriter, request *http.Request) bool {
	sharedResponse, ok := response.(*layeredResponse)
	return ok && sharedResponse.next(request)
}

// Get will retrieve a context value that is shared by each http.Handler
// attached to the same infuse.Handler within a single request-response cycle.
// http.Handlers that are attached to different infuse.Handlers do not share
// the same context value.
//
// If the context value is a pointer, map, or slice, changes to the referent
// data will be seen by other http.Handlers that share the context value. If
// called with an invalid response, Get returns nil.
//
// To retrieve a value of a particular type, consider wrapping infuse.Get:
//   func GetMyContext(response http.ResponseWriter) *MyContext {
//      return infuse.Get(response).(*MyContext)
//   }
//
// Example using a map:
//   func HandlerMap(response http.ResponseWriter) map[string]string {
//      handlerMap, ok := infuse.Get(response).(map[string]string)
//      if !ok || handlerMap == nil {
//         handlerMap = make(map[string]string)
//         if ok := infuse.Set(response, handlerMap); !ok {
//            return nil
//         }
//      }
//      return handlerMap
//   }
func Get(response http.ResponseWriter) interface{} {
	sharedResponse, ok := response.(*layeredResponse)
	if !ok {
		return nil
	}
	return sharedResponse.context
}

// Set will store a context value that is shared by the each http.Handler
// attached to the same infuse.Handler within a single request-response cycle.
// http.Handlers that are attached to different infuse.Handlers do not share
// the same context value. Set will return false if the response is invalid.
func Set(response http.ResponseWriter, value interface{}) bool {
	sharedResponse, ok := response.(*layeredResponse)
	if !ok {
		return false
	}
	sharedResponse.context = value
	return true
}
<|endoftext|>


<commit_before>package client

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"

	"github.com/flynn/go-discoverd"
	"github.com/flynn/lorne/types"
	"github.com/flynn/rpcplus"
)

var ErrNoServers = errors.New("lorne: no servers found")

func New(id string) (*Client, error) {
	services, err := discoverd.NewServiceSet("flynn-lorne." + id)
	if err != nil {
		return nil, err
	}
	addrs := services.Addrs()
	if len(addrs) == 0 {
		return nil, ErrNoServers
	}
	c, err := rpcplus.DialHTTP("tcp", addrs[0])
	return &Client{c, services}, err
}

type Client struct {
	c *rpcplus.Client

	service *discoverd.ServiceSet
}

func (c *Client) JobList() (map[string]lorne.Job, error) {
	var jobs map[string]lorne.Job
	err := c.c.Call("Host.JobList", struct{}{}, &jobs)
	return jobs, err
}

func (c *Client) GetJob(id string) (*lorne.Job, error) {
	var res lorne.Job
	err := c.c.Call("Host.GetJob", id, &res)
	return &res, err
}

func (c *Client) StopJob(id string) error {
	return c.c.Call("Host.StopJob", id, &struct{}{})
}

var ErrWouldWait = errors.New("lorne: attach would wait")

func (c *Client) Attach(req *lorne.AttachReq, wait bool) (ReadWriteCloser, func() error, error) {
	data, err := json.Marshal(req)
	if err != nil {
		return nil, nil, err
	}
	httpReq, err := http.NewRequest("POST", "/attach", bytes.NewBuffer(data))
	if err != nil {
		return nil, nil, err
	}
	addrs := c.service.Addrs()
	if len(addrs) == 0 {
		return nil, nil, ErrNoServers
	}
	conn, err := net.Dial("tcp", addrs[0])
	if err != nil {
		return nil, nil, err
	}
	clientconn := httputil.NewClientConn(conn, nil)
	res, err := clientconn.Do(httpReq)
	if err != nil && err != httputil.ErrPersistEOF {
		return nil, nil, err
	}
	if res.StatusCode != 200 {
		return nil, nil, fmt.Errorf("lorne: unexpected status %d", res.StatusCode)
	}
	var rwc io.ReadWriteCloser
	var buf *bufio.Reader
	rwc, buf = clientconn.Hijack()
	if buf.Buffered() > 0 {
		rwc = struct {
			io.Reader
			writeCloser
		}{
			io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc),
			rwc.(writeCloser),
		}
	}

	attachState := make([]byte, 1)
	if _, err := rwc.Read(attachState); err != nil {
		rwc.Close()
		return nil, nil, err
	}

	handleState := func() error {
		switch attachState[0] {
		case lorne.AttachSuccess:
			return nil
		case lorne.AttachError:
			errBytes, err := ioutil.ReadAll(rwc)
			rwc.Close()
			if err != nil {
				return err
			}
			return errors.New(string(errBytes))
		default:
			rwc.Close()
			return fmt.Errorf("lorne: unknown attach state: %d", attachState)
		}
	}

	if attachState[0] == lorne.AttachWaiting {
		if !wait {
			rwc.Close()
			return nil, nil, ErrWouldWait
		}
		return rwc.(ReadWriteCloser), func() error {
			if _, err := rwc.Read(attachState); err != nil {
				rwc.Close()
				return err
			}
			return handleState()
		}, nil
	}

	return rwc.(ReadWriteCloser), nil, handleState()
}

type ReadWriteCloser interface {
	io.ReadWriteCloser
	CloseWrite() error
}

type writeCloser interface {
	io.WriteCloser
	CloseWrite() error
}
<commit_msg>pkg/lorne: using attributes for id<commit_after>package client

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"

	"github.com/flynn/go-discoverd"
	"github.com/flynn/lorne/types"
	"github.com/flynn/rpcplus"
)

var ErrNoServers = errors.New("lorne: no servers found")

func New(id string) (*Client, error) {
	services, err := discoverd.NewServiceSet("flynn-lorne")
	services.Filter(map[string]string{"id": id})
	if err != nil {
		return nil, err
	}
	addrs := services.Addrs()
	if len(addrs) == 0 {
		return nil, ErrNoServers
	}
	c, err := rpcplus.DialHTTP("tcp", addrs[0])
	return &Client{c, services}, err
}

type Client struct {
	c *rpcplus.Client

	service *discoverd.ServiceSet
}

func (c *Client) JobList() (map[string]lorne.Job, error) {
	var jobs map[string]lorne.Job
	err := c.c.Call("Host.JobList", struct{}{}, &jobs)
	return jobs, err
}

func (c *Client) GetJob(id string) (*lorne.Job, error) {
	var res lorne.Job
	err := c.c.Call("Host.GetJob", id, &res)
	return &res, err
}

func (c *Client) StopJob(id string) error {
	return c.c.Call("Host.StopJob", id, &struct{}{})
}

var ErrWouldWait = errors.New("lorne: attach would wait")

func (c *Client) Attach(req *lorne.AttachReq, wait bool) (ReadWriteCloser, func() error, error) {
	data, err := json.Marshal(req)
	if err != nil {
		return nil, nil, err
	}
	httpReq, err := http.NewRequest("POST", "/attach", bytes.NewBuffer(data))
	if err != nil {
		return nil, nil, err
	}
	addrs := c.service.Addrs()
	if len(addrs) == 0 {
		return nil, nil, ErrNoServers
	}
	conn, err := net.Dial("tcp", addrs[0])
	if err != nil {
		return nil, nil, err
	}
	clientconn := httputil.NewClientConn(conn, nil)
	res, err := clientconn.Do(httpReq)
	if err != nil && err != httputil.ErrPersistEOF {
		return nil, nil, err
	}
	if res.StatusCode != 200 {
		return nil, nil, fmt.Errorf("lorne: unexpected status %d", res.StatusCode)
	}
	var rwc io.ReadWriteCloser
	var buf *bufio.Reader
	rwc, buf = clientconn.Hijack()
	if buf.Buffered() > 0 {
		rwc = struct {
			io.Reader
			writeCloser
		}{
			io.MultiReader(io.LimitReader(buf, int64(buf.Buffered())), rwc),
			rwc.(writeCloser),
		}
	}

	attachState := make([]byte, 1)
	if _, err := rwc.Read(attachState); err != nil {
		rwc.Close()
		return nil, nil, err
	}

	handleState := func() error {
		switch attachState[0] {
		case lorne.AttachSuccess:
			return nil
		case lorne.AttachError:
			errBytes, err := ioutil.ReadAll(rwc)
			rwc.Close()
			if err != nil {
				return err
			}
			return errors.New(string(errBytes))
		default:
			rwc.Close()
			return fmt.Errorf("lorne: unknown attach state: %d", attachState)
		}
	}

	if attachState[0] == lorne.AttachWaiting {
		if !wait {
			rwc.Close()
			return nil, nil, ErrWouldWait
		}
		return rwc.(ReadWriteCloser), func() error {
			if _, err := rwc.Read(attachState); err != nil {
				rwc.Close()
				return err
			}
			return handleState()
		}, nil
	}

	return rwc.(ReadWriteCloser), nil, handleState()
}

type ReadWriteCloser interface {
	io.ReadWriteCloser
	CloseWrite() error
}

type writeCloser interface {
	io.WriteCloser
	CloseWrite() error
}
<|endoftext|>


<commit_before>package rpcclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strings"

	"github.com/pkg/errors"
	types "github.com/tendermint/go-rpc/types"
	wire "github.com/tendermint/go-wire"
)

// HTTPClient is a common interface for ClientJSONRPC and ClientURI.
type HTTPClient interface {
	Call(method string, params map[string]interface{}, result interface{}) (interface{}, error)
}

// TODO: Deprecate support for IP:PORT or /path/to/socket
func makeHTTPDialer(remoteAddr string) (string, func(string, string) (net.Conn, error)) {

	parts := strings.SplitN(remoteAddr, "://", 2)
	var protocol, address string
	if len(parts) != 2 {
		log.Warn("WARNING (go-rpc): Please use fully formed listening addresses, including the tcp:// or unix:// prefix")
		protocol = types.SocketType(remoteAddr)
		address = remoteAddr
	} else {
		protocol, address = parts[0], parts[1]
	}

	trimmedAddress := strings.Replace(address, "/", ".", -1) // replace / with . for http requests (dummy domain)
	return trimmedAddress, func(proto, addr string) (net.Conn, error) {
		return net.Dial(protocol, address)
	}
}

// We overwrite the http.Client.Dial so we can do http over tcp or unix.
// remoteAddr should be fully featured (eg. with tcp:// or unix://)
func makeHTTPClient(remoteAddr string) (string, *http.Client) {
	address, dialer := makeHTTPDialer(remoteAddr)
	return "http://" + address, &http.Client{
		Transport: &http.Transport{
			Dial: dialer,
		},
	}
}

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

// JSON rpc takes params as a slice
type ClientJSONRPC struct {
	address string
	client  *http.Client
}

func NewClientJSONRPC(remote string) *ClientJSONRPC {
	address, client := makeHTTPClient(remote)
	return &ClientJSONRPC{
		address: address,
		client:  client,
	}
}

func (c *ClientJSONRPC) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	// we need this step because we attempt to decode values using `go-wire`
	// (handlers.go:176) on the server side
	encodedParams := make(map[string]interface{})
	for k, v := range params {
		encodedParams[k] = json.RawMessage(wire.JSONBytes(v))
	}
	request := types.RPCRequest{
		JSONRPC: "2.0",
		Method:  method,
		Params:  encodedParams,
		ID:      "",
	}
	requestBytes, err := json.Marshal(request)
	if err != nil {
		return nil, err
	}
	requestBuf := bytes.NewBuffer(requestBytes)
	// log.Info(Fmt("RPC request to %v (%v): %v", c.remote, method, string(requestBytes)))
	httpResponse, err := c.client.Post(c.address, "text/json", requestBuf)
	if err != nil {
		return nil, err
	}
	defer httpResponse.Body.Close()
	responseBytes, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return nil, err
	}
	// 	log.Info(Fmt("RPC response: %v", string(responseBytes)))
	return unmarshalResponseBytes(responseBytes, result)
}

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

// URI takes params as a map
type ClientURI struct {
	address string
	client  *http.Client
}

func NewClientURI(remote string) *ClientURI {
	address, client := makeHTTPClient(remote)
	return &ClientURI{
		address: address,
		client:  client,
	}
}

func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	values, err := argsToURLValues(params)
	if err != nil {
		return nil, err
	}
	// log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
	resp, err := c.client.PostForm(c.address+"/"+method, values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	responseBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return unmarshalResponseBytes(responseBytes, result)
}

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

func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
	// read response
	// if rpc/core/types is imported, the result will unmarshal
	// into the correct type
	// log.Notice("response", "response", string(responseBytes))
	var err error
	response := &types.RPCResponse{}
	err = json.Unmarshal(responseBytes, response)
	if err != nil {
		return nil, errors.Errorf("Error unmarshalling rpc response: %v", err)
	}
	errorStr := response.Error
	if errorStr != "" {
		return nil, errors.Errorf("Response error: %v", errorStr)
	}
	// unmarshal the RawMessage into the result
	result = wire.ReadJSONPtr(result, *response.Result, &err)
	if err != nil {
		return nil, errors.Errorf("Error unmarshalling rpc response result: %v", err)
	}
	return result, nil
}

func argsToURLValues(args map[string]interface{}) (url.Values, error) {
	values := make(url.Values)
	if len(args) == 0 {
		return values, nil
	}
	err := argsToJson(args)
	if err != nil {
		return nil, err
	}
	for key, val := range args {
		values.Set(key, val.(string))
	}
	return values, nil
}

func argsToJson(args map[string]interface{}) error {
	var n int
	var err error
	for k, v := range args {
		// Convert byte slices to "0x"-prefixed hex
		byteSlice, isByteSlice := reflect.ValueOf(v).Interface().([]byte)
		if isByteSlice {
			args[k] = fmt.Sprintf("0x%X", byteSlice)
			continue
		}

		// Pass everything else to go-wire
		buf := new(bytes.Buffer)
		wire.WriteJSON(v, buf, &n, &err)
		if err != nil {
			return err
		}
		args[k] = buf.String()
	}
	return nil
}
<commit_msg>Properly encode json.RawMessage<commit_after>package rpcclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"reflect"
	"strings"

	"github.com/pkg/errors"
	types "github.com/tendermint/go-rpc/types"
	wire "github.com/tendermint/go-wire"
)

// HTTPClient is a common interface for ClientJSONRPC and ClientURI.
type HTTPClient interface {
	Call(method string, params map[string]interface{}, result interface{}) (interface{}, error)
}

// TODO: Deprecate support for IP:PORT or /path/to/socket
func makeHTTPDialer(remoteAddr string) (string, func(string, string) (net.Conn, error)) {

	parts := strings.SplitN(remoteAddr, "://", 2)
	var protocol, address string
	if len(parts) != 2 {
		log.Warn("WARNING (go-rpc): Please use fully formed listening addresses, including the tcp:// or unix:// prefix")
		protocol = types.SocketType(remoteAddr)
		address = remoteAddr
	} else {
		protocol, address = parts[0], parts[1]
	}

	trimmedAddress := strings.Replace(address, "/", ".", -1) // replace / with . for http requests (dummy domain)
	return trimmedAddress, func(proto, addr string) (net.Conn, error) {
		return net.Dial(protocol, address)
	}
}

// We overwrite the http.Client.Dial so we can do http over tcp or unix.
// remoteAddr should be fully featured (eg. with tcp:// or unix://)
func makeHTTPClient(remoteAddr string) (string, *http.Client) {
	address, dialer := makeHTTPDialer(remoteAddr)
	return "http://" + address, &http.Client{
		Transport: &http.Transport{
			Dial: dialer,
		},
	}
}

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

// JSON rpc takes params as a slice
type ClientJSONRPC struct {
	address string
	client  *http.Client
}

func NewClientJSONRPC(remote string) *ClientJSONRPC {
	address, client := makeHTTPClient(remote)
	return &ClientJSONRPC{
		address: address,
		client:  client,
	}
}

func (c *ClientJSONRPC) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	// we need this step because we attempt to decode values using `go-wire`
	// (handlers.go:176) on the server side
	encodedParams := make(map[string]interface{})
	for k, v := range params {
		// log.Printf("%s: %v (%s)\n", k, v, string(wire.JSONBytes(v)))
		bytes := json.RawMessage(wire.JSONBytes(v))
		encodedParams[k] = &bytes
	}
	request := types.RPCRequest{
		JSONRPC: "2.0",
		Method:  method,
		Params:  encodedParams,
		ID:      "",
	}
	requestBytes, err := json.Marshal(request)
	if err != nil {
		return nil, err
	}
	// log.Info(string(requestBytes))
	requestBuf := bytes.NewBuffer(requestBytes)
	// log.Info(Fmt("RPC request to %v (%v): %v", c.remote, method, string(requestBytes)))
	httpResponse, err := c.client.Post(c.address, "text/json", requestBuf)
	if err != nil {
		return nil, err
	}
	defer httpResponse.Body.Close()
	responseBytes, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return nil, err
	}
	// 	log.Info(Fmt("RPC response: %v", string(responseBytes)))
	return unmarshalResponseBytes(responseBytes, result)
}

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

// URI takes params as a map
type ClientURI struct {
	address string
	client  *http.Client
}

func NewClientURI(remote string) *ClientURI {
	address, client := makeHTTPClient(remote)
	return &ClientURI{
		address: address,
		client:  client,
	}
}

func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	values, err := argsToURLValues(params)
	if err != nil {
		return nil, err
	}
	// log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
	resp, err := c.client.PostForm(c.address+"/"+method, values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	responseBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return unmarshalResponseBytes(responseBytes, result)
}

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

func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
	// read response
	// if rpc/core/types is imported, the result will unmarshal
	// into the correct type
	// log.Notice("response", "response", string(responseBytes))
	var err error
	response := &types.RPCResponse{}
	err = json.Unmarshal(responseBytes, response)
	if err != nil {
		return nil, errors.Errorf("Error unmarshalling rpc response: %v", err)
	}
	errorStr := response.Error
	if errorStr != "" {
		return nil, errors.Errorf("Response error: %v", errorStr)
	}
	// unmarshal the RawMessage into the result
	result = wire.ReadJSONPtr(result, *response.Result, &err)
	if err != nil {
		return nil, errors.Errorf("Error unmarshalling rpc response result: %v", err)
	}
	return result, nil
}

func argsToURLValues(args map[string]interface{}) (url.Values, error) {
	values := make(url.Values)
	if len(args) == 0 {
		return values, nil
	}
	err := argsToJson(args)
	if err != nil {
		return nil, err
	}
	for key, val := range args {
		values.Set(key, val.(string))
	}
	return values, nil
}

func argsToJson(args map[string]interface{}) error {
	var n int
	var err error
	for k, v := range args {
		// Convert byte slices to "0x"-prefixed hex
		byteSlice, isByteSlice := reflect.ValueOf(v).Interface().([]byte)
		if isByteSlice {
			args[k] = fmt.Sprintf("0x%X", byteSlice)
			continue
		}

		// Pass everything else to go-wire
		buf := new(bytes.Buffer)
		wire.WriteJSON(v, buf, &n, &err)
		if err != nil {
			return err
		}
		args[k] = buf.String()
	}
	return nil
}
<|endoftext|>


<commit_before>package messages

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dloa/media-protocol/utility"
	"log"
	"strconv"
	"strings"
)

const PUBLISHER_ROOT_KEY = "alexandria-publisher"

type AlexandriaPublisher struct {
	AlexandriaPublisher struct {
		// required publisher metadata
		Name      string `json:"name"`
		Address   string `json:"address"`
		Timestamp int64  `json:"timestamp"`

		// optional fields
		Emailmd5   string `json:"emailmd5"`
		Bitmessage string `json:"bitmessage"`
	} `json:"alexandria-publisher"`
	Signature string `json:"signature"`
}

func CheckPublisherAddressExists(address string, dbtx *sql.Tx) bool {
	// check if this publisher address is already in-use
	stmtstr := `select name from publisher where address = ?`

	rows, stmterr := dbtx.Query(stmtstr, address)
	if stmterr != nil {
		fmt.Println("exit 91248")
		log.Fatal(stmterr)
	}

	var rowsCount int = 0
	for rows.Next() {
		rowsCount++
	}

	rows.Close()
	return rowsCount > 0

}

func CreateNewPublisherTxComment(b []byte) {
	// given some JSON, post it to the blockchain using either a tx-comment or multipart tx-comment

}

func StorePublisher(publisher AlexandriaPublisher, dbtx *sql.Tx, txid string, block int, hash string) {
	// store in database
	stmtstr := `insert into publisher (name, address, timestamp, txid, block, emailmd5, bitmessage, hash, signature, active) values (?, ?, ?, "` + txid + `", ` + strconv.Itoa(block) + `, ?, ?, "` + hash + `", ?, 1)`

	stmt, err := dbtx.Prepare(stmtstr)
	if err != nil {
		fmt.Println("exit 100")
		log.Fatal(err)
	}

	_, stmterr := stmt.Exec(publisher.AlexandriaPublisher.Name, publisher.AlexandriaPublisher.Address, publisher.AlexandriaPublisher.Timestamp, publisher.AlexandriaPublisher.Emailmd5, publisher.AlexandriaPublisher.Bitmessage, publisher.Signature)
	if err != nil {
		fmt.Println("exit 101")
		log.Fatal(stmterr)
	}

	stmt.Close()

}

func VerifyPublisher(b []byte) (AlexandriaPublisher, error) {

	var v AlexandriaPublisher
	var i interface{}
	var m map[string]interface{}

	if !strings.HasPrefix(string(b), `{ "alexandria-publisher"`) {
		return v, errors.New("Not alexandria-publisher")
	}

	// fmt.Printf("Attempting to verify alexandria-publisher JSON...")

	if !utility.IsJSON(string(b)) {
		return v, ErrNotJSON
	}

	err := json.Unmarshal(b, &v)
	if err != nil {
		return v, err
	}

	errr := json.Unmarshal(b, &i)
	if errr != nil {
		return v, err
	}

	m = i.(map[string]interface{})
	var signature string

	// check the JSON object root key
	// find the signature string
	for key, val := range m {
		if key == "signature" {
			signature = val.(string)
		} else {
			if key != PUBLISHER_ROOT_KEY {
				return v, errors.New("can't verify publisher - JSON object root key doesn't match accepted value")
			}
		}
	}

	// verify signature
	if v.Signature != signature {
		return v, ErrBadSignature
	}

	// verify signature was created by this address
	// signature pre-image for publisher is <name>-<address>-<timestamp>
	val, _ := utility.CheckSignature(v.AlexandriaPublisher.Address, signature, v.AlexandriaPublisher.Name+"-"+v.AlexandriaPublisher.Address+"-"+strconv.FormatInt(v.AlexandriaPublisher.Timestamp, 10))
	if val == false {
		return v, ErrBadSignature
	}

	// fmt.Println(" -- VERIFIED --")
	return v, nil

}
<commit_msg>Fix publisher prefix check<commit_after>package messages

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dloa/media-protocol/utility"
	"log"
	"strconv"
	"strings"
)

const PUBLISHER_ROOT_KEY = "alexandria-publisher"

type AlexandriaPublisher struct {
	AlexandriaPublisher struct {
		// required publisher metadata
		Name      string `json:"name"`
		Address   string `json:"address"`
		Timestamp int64  `json:"timestamp"`

		// optional fields
		Emailmd5   string `json:"emailmd5"`
		Bitmessage string `json:"bitmessage"`
	} `json:"alexandria-publisher"`
	Signature string `json:"signature"`
}

func CheckPublisherAddressExists(address string, dbtx *sql.Tx) bool {
	// check if this publisher address is already in-use
	stmtstr := `select name from publisher where address = ?`

	rows, stmterr := dbtx.Query(stmtstr, address)
	if stmterr != nil {
		fmt.Println("exit 91248")
		log.Fatal(stmterr)
	}

	var rowsCount int = 0
	for rows.Next() {
		rowsCount++
	}

	rows.Close()
	return rowsCount > 0

}

func CreateNewPublisherTxComment(b []byte) {
	// given some JSON, post it to the blockchain using either a tx-comment or multipart tx-comment

}

func StorePublisher(publisher AlexandriaPublisher, dbtx *sql.Tx, txid string, block int, hash string) {
	// store in database
	stmtstr := `insert into publisher (name, address, timestamp, txid, block, emailmd5, bitmessage, hash, signature, active) values (?, ?, ?, "` + txid + `", ` + strconv.Itoa(block) + `, ?, ?, "` + hash + `", ?, 1)`

	stmt, err := dbtx.Prepare(stmtstr)
	if err != nil {
		fmt.Println("exit 100")
		log.Fatal(err)
	}

	_, stmterr := stmt.Exec(publisher.AlexandriaPublisher.Name, publisher.AlexandriaPublisher.Address, publisher.AlexandriaPublisher.Timestamp, publisher.AlexandriaPublisher.Emailmd5, publisher.AlexandriaPublisher.Bitmessage, publisher.Signature)
	if err != nil {
		fmt.Println("exit 101")
		log.Fatal(stmterr)
	}

	stmt.Close()

}

func VerifyPublisher(b []byte) (AlexandriaPublisher, error) {

	var v AlexandriaPublisher
	var i interface{}
	var m map[string]interface{}

	if !strings.HasPrefix(string(b), `{ "alexandria-publisher"`) &&
		!strings.HasPrefix(string(b), `{"alexandria-publisher"`) {
		return v, ErrWrongPrefix
	}

	// fmt.Printf("Attempting to verify alexandria-publisher JSON...")

	if !utility.IsJSON(string(b)) {
		return v, ErrNotJSON
	}

	err := json.Unmarshal(b, &v)
	if err != nil {
		return v, err
	}

	errr := json.Unmarshal(b, &i)
	if errr != nil {
		return v, err
	}

	m = i.(map[string]interface{})
	var signature string

	// check the JSON object root key
	// find the signature string
	for key, val := range m {
		if key == "signature" {
			signature = val.(string)
		} else {
			if key != PUBLISHER_ROOT_KEY {
				return v, errors.New("can't verify publisher - JSON object root key doesn't match accepted value")
			}
		}
	}

	// verify signature
	if v.Signature != signature {
		return v, ErrBadSignature
	}

	// verify signature was created by this address
	// signature pre-image for publisher is <name>-<address>-<timestamp>
	val, _ := utility.CheckSignature(v.AlexandriaPublisher.Address, signature, v.AlexandriaPublisher.Name+"-"+v.AlexandriaPublisher.Address+"-"+strconv.FormatInt(v.AlexandriaPublisher.Timestamp, 10))
	if val == false {
		return v, ErrBadSignature
	}

	// fmt.Println(" -- VERIFIED --")
	return v, nil

}
<|endoftext|>


<commit_before>package utils

import (
	"github.com/jfrogdev/jfrog-cli-go/jfrog-client/utils/io/fileutils"
	"github.com/jfrogdev/jfrog-cli-go/jfrog-cli/utils/cliutils"
	"encoding/json"
	"strconv"
	"github.com/jfrogdev/jfrog-cli-go/jfrog-client/artifactory/services/utils"
	"fmt"
	"bytes"
	"github.com/jfrogdev/jfrog-cli-go/jfrog-client/utils/errorutils"
	"errors"
)

type SpecFiles struct {
	Files []File
}

func (spec *SpecFiles) Get(index int) *File {
	if index < len(spec.Files) {
		return &spec.Files[index]
	}
	return new(File)
}

func CreateSpecFromFile(specFilePath string, specVars map[string]string) (spec *SpecFiles, err error) {
	spec = new(SpecFiles)
	content, err := fileutils.ReadFile(specFilePath)
	if errorutils.CheckError(err) != nil {
		return
	}

	if len(specVars) > 0 {
		content = replaceSpecVars(content, specVars)
	}

	err = json.Unmarshal(content, spec)
	if errorutils.CheckError(err) != nil {
		return
	}
	return
}

func replaceSpecVars(content []byte, specVars map[string]string) []byte {
	cliutils.CliLogger.Debug("Replacing variables in the provided File Spec: \n" + string(content))
	for key, val := range specVars {
		key = "${" + key + "}"
		cliutils.CliLogger.Debug(fmt.Sprintf("Replacing '%s' with '%s'", key, val))
		content = bytes.Replace(content, []byte(key), []byte(val), -1)
	}
	cliutils.CliLogger.Debug("The reformatted File Spec is: \n" + string(content))
	return content
}

func CreateSpec(pattern string, excludePatterns []string, target, props, build string, recursive, flat, regexp, includeDirs bool) (spec *SpecFiles) {
	spec = &SpecFiles{
		Files: []File{
			{
				Pattern:         pattern,
				ExcludePatterns: excludePatterns,
				Target:          target,
				Props:           props,
				Build:           build,
				Recursive:       strconv.FormatBool(recursive),
				Flat:            strconv.FormatBool(flat),
				Regexp:          strconv.FormatBool(regexp),
				IncludeDirs:     strconv.FormatBool(includeDirs),
			},
		},
	}
	return spec
}

type File struct {
	Aql             utils.Aql
	Pattern         string
	ExcludePatterns []string
	Target          string
	Props           string
	Build           string
	Recursive       string
	Flat            string
	Regexp          string
	IncludeDirs     string
}

func (f File) IsFlat(defaultValue bool) (bool, error) {
	return cliutils.StringToBool(f.Flat, defaultValue)
}

func (f *File) ToArtifatoryUploadParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()

	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive

	regexp, err := cliutils.StringToBool(f.Regexp, false)
	if err != nil {
		return nil, err
	}
	params.Regexp = regexp

	includeDirs, err := cliutils.StringToBool(f.IncludeDirs, false)
	if err != nil {
		return nil, err
	}
	params.IncludeDirs = includeDirs
	return params, nil
}

func (f *File) ToArtifatoryDownloadParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive

	includeDirs, err := cliutils.StringToBool(f.IncludeDirs, false)
	if err != nil {
		return nil, err
	}
	params.IncludeDirs = includeDirs
	return params, nil
}

func (f *File) ToArtifatoryDeleteParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive
	return params, nil
}

func (f *File) ToArtifatorySearchParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive

	return params, nil
}

func (f *File) ToArtifatoryMoveCopyParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive
	return params, nil
}

func (f *File) ToArtifatorySetPropsParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, false)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive
	return params, nil
}

func (f *File) toArtifactoryCommonParams() *utils.ArtifactoryCommonParams {
	params := new(utils.ArtifactoryCommonParams)
	params.Aql = f.Aql
	params.Pattern = f.Pattern
	params.ExcludePatterns = f.ExcludePatterns
	params.Target = f.Target
	params.Props = f.Props
	params.Build = f.Build
	return params
}

func ValidateSpec(files []File, isTargetMandatory bool) error {
	if len(files) == 0 {
		return errors.New("Spec must include at least one file group")
	}
	for _, file := range files {
		isAql := len(file.Aql.ItemsFind) > 0
		isPattern := len(file.Pattern) > 0
		isExcludePattern := len(file.ExcludePatterns) > 0 && len(file.ExcludePatterns[0]) > 0
		isTarget := len(file.Target) > 0

		if isTargetMandatory && !isTarget {
			return errors.New("Spec must include the target values")
		}
		if !isAql && !isPattern {
			return errors.New("Spec must include either the aql or pattern values")
		}
		if isAql && isPattern {
			return errors.New("Spec cannot include both the aql and pattern values")
		}
		if isAql && isExcludePattern {
			return errors.New("Spec cannot include both the aql and exclude-patterns values")
		}
	}
	return nil
}<commit_msg>jfrog rt set-props --include-dirs flag doesn't work #106<commit_after>package utils

import (
	"github.com/jfrogdev/jfrog-cli-go/jfrog-client/utils/io/fileutils"
	"github.com/jfrogdev/jfrog-cli-go/jfrog-cli/utils/cliutils"
	"encoding/json"
	"strconv"
	"github.com/jfrogdev/jfrog-cli-go/jfrog-client/artifactory/services/utils"
	"fmt"
	"bytes"
	"github.com/jfrogdev/jfrog-cli-go/jfrog-client/utils/errorutils"
	"errors"
)

type SpecFiles struct {
	Files []File
}

func (spec *SpecFiles) Get(index int) *File {
	if index < len(spec.Files) {
		return &spec.Files[index]
	}
	return new(File)
}

func CreateSpecFromFile(specFilePath string, specVars map[string]string) (spec *SpecFiles, err error) {
	spec = new(SpecFiles)
	content, err := fileutils.ReadFile(specFilePath)
	if errorutils.CheckError(err) != nil {
		return
	}

	if len(specVars) > 0 {
		content = replaceSpecVars(content, specVars)
	}

	err = json.Unmarshal(content, spec)
	if errorutils.CheckError(err) != nil {
		return
	}
	return
}

func replaceSpecVars(content []byte, specVars map[string]string) []byte {
	cliutils.CliLogger.Debug("Replacing variables in the provided File Spec: \n" + string(content))
	for key, val := range specVars {
		key = "${" + key + "}"
		cliutils.CliLogger.Debug(fmt.Sprintf("Replacing '%s' with '%s'", key, val))
		content = bytes.Replace(content, []byte(key), []byte(val), -1)
	}
	cliutils.CliLogger.Debug("The reformatted File Spec is: \n" + string(content))
	return content
}

func CreateSpec(pattern string, excludePatterns []string, target, props, build string, recursive, flat, regexp, includeDirs bool) (spec *SpecFiles) {
	spec = &SpecFiles{
		Files: []File{
			{
				Pattern:         pattern,
				ExcludePatterns: excludePatterns,
				Target:          target,
				Props:           props,
				Build:           build,
				Recursive:       strconv.FormatBool(recursive),
				Flat:            strconv.FormatBool(flat),
				Regexp:          strconv.FormatBool(regexp),
				IncludeDirs:     strconv.FormatBool(includeDirs),
			},
		},
	}
	return spec
}

type File struct {
	Aql             utils.Aql
	Pattern         string
	ExcludePatterns []string
	Target          string
	Props           string
	Build           string
	Recursive       string
	Flat            string
	Regexp          string
	IncludeDirs     string
}

func (f File) IsFlat(defaultValue bool) (bool, error) {
	return cliutils.StringToBool(f.Flat, defaultValue)
}

func (f *File) ToArtifatoryUploadParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()

	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive

	regexp, err := cliutils.StringToBool(f.Regexp, false)
	if err != nil {
		return nil, err
	}
	params.Regexp = regexp

	includeDirs, err := cliutils.StringToBool(f.IncludeDirs, false)
	if err != nil {
		return nil, err
	}
	params.IncludeDirs = includeDirs
	return params, nil
}

func (f *File) ToArtifatoryDownloadParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive

	includeDirs, err := cliutils.StringToBool(f.IncludeDirs, false)
	if err != nil {
		return nil, err
	}
	params.IncludeDirs = includeDirs
	return params, nil
}

func (f *File) ToArtifatoryDeleteParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive
	return params, nil
}

func (f *File) ToArtifatorySearchParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive

	return params, nil
}

func (f *File) ToArtifatoryMoveCopyParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, true)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive
	return params, nil
}

func (f *File) ToArtifatorySetPropsParams() (*utils.ArtifactoryCommonParams, error) {
	params := f.toArtifactoryCommonParams()
	recursive, err := cliutils.StringToBool(f.Recursive, false)
	if err != nil {
		return nil, err
	}
	params.Recursive = recursive
	params.IncludeDirs, err = cliutils.StringToBool(f.IncludeDirs, false)
	if err != nil {
		return nil, err
	}
	return params, nil
}

func (f *File) toArtifactoryCommonParams() *utils.ArtifactoryCommonParams {
	params := new(utils.ArtifactoryCommonParams)
	params.Aql = f.Aql
	params.Pattern = f.Pattern
	params.ExcludePatterns = f.ExcludePatterns
	params.Target = f.Target
	params.Props = f.Props
	params.Build = f.Build
	return params
}

func ValidateSpec(files []File, isTargetMandatory bool) error {
	if len(files) == 0 {
		return errors.New("Spec must include at least one file group")
	}
	for _, file := range files {
		isAql := len(file.Aql.ItemsFind) > 0
		isPattern := len(file.Pattern) > 0
		isExcludePattern := len(file.ExcludePatterns) > 0 && len(file.ExcludePatterns[0]) > 0
		isTarget := len(file.Target) > 0

		if isTargetMandatory && !isTarget {
			return errors.New("Spec must include the target values")
		}
		if !isAql && !isPattern {
			return errors.New("Spec must include either the aql or pattern values")
		}
		if isAql && isPattern {
			return errors.New("Spec cannot include both the aql and pattern values")
		}
		if isAql && isExcludePattern {
			return errors.New("Spec cannot include both the aql and exclude-patterns values")
		}
	}
	return nil
}<|endoftext|>


<commit_before>package client

import (
	"math/rand"
	"time"

	"github.com/aws/aws-sdk-go/aws/request"
)

// DefaultRetryer implements basic retry logic using exponential backoff for
// most services. If you want to implement custom retry logic, implement the
// request.Retryer interface or create a structure type that composes this
// struct and override the specific methods. For example, to override only
// the MaxRetries method:
//
//		type retryer struct {
//      service.DefaultRetryer
//    }
//
//    // This implementation always has 100 max retries
//    func (d retryer) MaxRetries() uint { return 100 }
type DefaultRetryer struct {
	NumMaxRetries int
}

// MaxRetries returns the number of maximum returns the service will use to make
// an individual API request.
func (d DefaultRetryer) MaxRetries() int {
	return d.NumMaxRetries
}

// RetryRules returns the delay duration before retrying this request again
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
	// Set the upper limit of delay in retrying at ~five minutes
	minTime := 30
	throttle := d.shouldThrottle(r)
	if throttle {
		minTime = 1000
	}

	retryCount := r.RetryCount
	if retryCount > 13 {
		retryCount = 13
	} else if throttle && retryCount > 3 {
		retryCount = 3
	}

	delay := (1 << uint(retryCount)) * (rand.Intn(30) + minTime)
	return time.Duration(delay) * time.Millisecond
}

// ShouldRetry returns true if the request should be retried.
func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
	if r.HTTPResponse.StatusCode >= 500 {
		return true
	}
	return r.IsErrorRetryable() || d.shouldThrottle(r)
}

// ShouldThrottle returns true if the request should be throttled.
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
	if r.HTTPResponse.StatusCode == 502 ||
		r.HTTPResponse.StatusCode == 503 ||
		r.HTTPResponse.StatusCode == 504 {
		return true
	}
	return r.IsErrorThrottle()
}
<commit_msg>Changing retry timer to be ~5 mins<commit_after>package client

import (
	"math/rand"
	"time"

	"github.com/aws/aws-sdk-go/aws/request"
)

// DefaultRetryer implements basic retry logic using exponential backoff for
// most services. If you want to implement custom retry logic, implement the
// request.Retryer interface or create a structure type that composes this
// struct and override the specific methods. For example, to override only
// the MaxRetries method:
//
//		type retryer struct {
//      service.DefaultRetryer
//    }
//
//    // This implementation always has 100 max retries
//    func (d retryer) MaxRetries() uint { return 100 }
type DefaultRetryer struct {
	NumMaxRetries int
}

// MaxRetries returns the number of maximum returns the service will use to make
// an individual API request.
func (d DefaultRetryer) MaxRetries() int {
	return d.NumMaxRetries
}

// RetryRules returns the delay duration before retrying this request again
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
	// Set the upper limit of delay in retrying at ~five minutes
	minTime := 30
	throttle := d.shouldThrottle(r)
	if throttle {
		minTime = 1000
	}

	retryCount := r.RetryCount
	if retryCount > 13 {
		retryCount = 13
	} else if throttle && retryCount > 8 {
		retryCount = 8
	}

	delay := (1 << uint(retryCount)) * (rand.Intn(30) + minTime)
	return time.Duration(delay) * time.Millisecond
}

// ShouldRetry returns true if the request should be retried.
func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
	if r.HTTPResponse.StatusCode >= 500 {
		return true
	}
	return r.IsErrorRetryable() || d.shouldThrottle(r)
}

// ShouldThrottle returns true if the request should be throttled.
func (d DefaultRetryer) shouldThrottle(r *request.Request) bool {
	if r.HTTPResponse.StatusCode == 502 ||
		r.HTTPResponse.StatusCode == 503 ||
		r.HTTPResponse.StatusCode == 504 {
		return true
	}
	return r.IsErrorThrottle()
}
<|endoftext|>


<commit_before>package builder

import (
	"errors"
	log "github.com/Sirupsen/logrus"
	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/blablacar/cnt/spec"
	"github.com/blablacar/cnt/utils"
	"os"
)

const PATH_POD_MANIFEST = "/pod-manifest.json"

func (p *Pod) Build() {
	log.Info("Building POD : ", p.manifest.Name)

	os.RemoveAll(p.target)
	os.MkdirAll(p.target, 0777)

	apps := p.processAci()

	p.writePodManifest(apps)
}

func (p *Pod) processAci() []schema.RuntimeApp {
	apps := []schema.RuntimeApp{}
	for _, e := range p.manifest.Pod.Apps {

		aciName := p.buildAciIfNeeded(e)

		name, _ := types.NewACName(e.Name)

		sum, err := utils.Sha512sum(p.path + "/" + e.Name + "/target/image.aci")
		if err != nil {
			panic(err)
		}

		tmp, _ := types.NewHash("sha512-" + sum)

		labels := types.Labels{}
		labels = append(labels, types.Label{Name: "version", Value: aciName.Version()})
		identifier, _ := types.NewACIdentifier(aciName.Name())
		ttmp := schema.RuntimeImage{Name: identifier, ID: *tmp, Labels: labels}

		if e.App.User == "" {
			e.App.User = "0"
		}
		if e.App.Group == "" {
			e.App.Group = "0"
		}

		apps = append(apps, schema.RuntimeApp{
			Name:  *name,
			Image: ttmp,
			App: &types.App{
				Exec:             e.App.Exec,
				User:             e.App.User,
				Group:            e.App.Group,
				WorkingDirectory: e.App.WorkingDirectory,
				Environment:      e.App.Environment,
				MountPoints:      e.App.MountPoints,
				Ports:            e.App.Ports,
				Isolators:        e.App.Isolators,
			},
			Mounts:      e.Mounts,
			Annotations: e.Annotations})
	}

	return apps
}

func (p *Pod) buildAciIfNeeded(e spec.RuntimeApp) *spec.ACFullname {
	if dir, err := os.Stat(p.path + "/" + e.Name); err == nil && dir.IsDir() {
		aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e), nil)
		if err != nil {
			panic(err)
		}
		aci.PodName = &p.manifest.Name
		aci.Build()
		return &aci.manifest.NameAndVersion
	}
	panic("Cannot found Pod's aci directory :" + p.path + "/" + e.Name)
	return nil
}

func (p *Pod) writePodManifest(apps []schema.RuntimeApp) {
	m := p.manifest.Pod
	ver, _ := types.NewSemVer("0.6.1")
	manifest := schema.PodManifest{
		ACKind:      "PodManifest",
		ACVersion:   *ver,
		Apps:        apps,
		Volumes:     m.Volumes,
		Isolators:   m.Isolators,
		Annotations: m.Annotations,
		Ports:       m.Ports}
	utils.WritePodManifest(&manifest, p.target+PATH_POD_MANIFEST)
}

const SYSTEMD_TEMPLATE = `[Unit]
Description={{ .Shortname }} %i

[Service]
ExecStartPre=/opt/bin/rkt gc --grace-period=0s --expire-prepared=0s
ExecStart=/opt/bin/rkt --insecure-skip-verify run \
{{range $i, $e := .Commands}}  {{$e}} \
{{end}}{{range $i, $e := .Acilist}}{{if $i}} \
{{end}}  {{$e}}{{end}}

[Install]
WantedBy=multi-user.target
`

type SystemdUnit struct {
	Shortname string
	Commands  []string
	Acilist   []string
}

func (p *Pod) getVolumeMountValue(mountName types.ACName) (*types.Volume, error) {
	for _, volume := range p.manifest.Pod.Volumes {
		if volume.Name.Equals(mountName) {
			return &volume, nil
		}
	}
	return nil, errors.New("Volume mount point not set :" + mountName.String())
}
<commit_msg>set generated version of pod if not set<commit_after>package builder

import (
	"errors"
	log "github.com/Sirupsen/logrus"
	"github.com/appc/spec/schema"
	"github.com/appc/spec/schema/types"
	"github.com/blablacar/cnt/spec"
	"github.com/blablacar/cnt/utils"
	"os"
)

const PATH_POD_MANIFEST = "/pod-manifest.json"

func (p *Pod) Build() {
	log.Info("Building POD : ", p.manifest.Name)

	os.RemoveAll(p.target)
	os.MkdirAll(p.target, 0777)

	p.preparePodVersion()
	apps := p.processAci()

	p.writePodManifest(apps)
}

func (p *Pod) preparePodVersion() {
	if p.manifest.Name.Version() == "" {
		p.manifest.Name = *spec.NewACFullName(p.manifest.Name.Name() + ":" + utils.GenerateVersion())
	}
}

func (p *Pod) processAci() []schema.RuntimeApp {
	apps := []schema.RuntimeApp{}
	for _, e := range p.manifest.Pod.Apps {

		aciName := p.buildAciIfNeeded(e)

		name, _ := types.NewACName(e.Name)

		sum, err := utils.Sha512sum(p.path + "/" + e.Name + "/target/image.aci")
		if err != nil {
			panic(err)
		}

		tmp, _ := types.NewHash("sha512-" + sum)

		labels := types.Labels{}
		labels = append(labels, types.Label{Name: "version", Value: aciName.Version()})
		identifier, _ := types.NewACIdentifier(aciName.Name())
		ttmp := schema.RuntimeImage{Name: identifier, ID: *tmp, Labels: labels}

		if e.App.User == "" {
			e.App.User = "0"
		}
		if e.App.Group == "" {
			e.App.Group = "0"
		}

		apps = append(apps, schema.RuntimeApp{
			Name:  *name,
			Image: ttmp,
			App: &types.App{
				Exec:             e.App.Exec,
				User:             e.App.User,
				Group:            e.App.Group,
				WorkingDirectory: e.App.WorkingDirectory,
				Environment:      e.App.Environment,
				MountPoints:      e.App.MountPoints,
				Ports:            e.App.Ports,
				Isolators:        e.App.Isolators,
			},
			Mounts:      e.Mounts,
			Annotations: e.Annotations})
	}

	return apps
}

func (p *Pod) buildAciIfNeeded(e spec.RuntimeApp) *spec.ACFullname {
	if dir, err := os.Stat(p.path + "/" + e.Name); err == nil && dir.IsDir() {
		aci, err := NewAciWithManifest(p.path+"/"+e.Name, p.args, p.toAciManifest(e), nil)
		if err != nil {
			panic(err)
		}
		aci.PodName = &p.manifest.Name
		aci.Build()
		return &aci.manifest.NameAndVersion
	}
	panic("Cannot found Pod's aci directory :" + p.path + "/" + e.Name)
	return nil
}

func (p *Pod) writePodManifest(apps []schema.RuntimeApp) {
	m := p.manifest.Pod
	ver, _ := types.NewSemVer("0.6.1")
	manifest := schema.PodManifest{
		ACKind:      "PodManifest",
		ACVersion:   *ver,
		Apps:        apps,
		Volumes:     m.Volumes,
		Isolators:   m.Isolators,
		Annotations: m.Annotations,
		Ports:       m.Ports}
	utils.WritePodManifest(&manifest, p.target+PATH_POD_MANIFEST)
}

const SYSTEMD_TEMPLATE = `[Unit]
Description={{ .Shortname }} %i

[Service]
ExecStartPre=/opt/bin/rkt gc --grace-period=0s --expire-prepared=0s
ExecStart=/opt/bin/rkt --insecure-skip-verify run \
{{range $i, $e := .Commands}}  {{$e}} \
{{end}}{{range $i, $e := .Acilist}}{{if $i}} \
{{end}}  {{$e}}{{end}}

[Install]
WantedBy=multi-user.target
`

type SystemdUnit struct {
	Shortname string
	Commands  []string
	Acilist   []string
}

func (p *Pod) getVolumeMountValue(mountName types.ACName) (*types.Volume, error) {
	for _, volume := range p.manifest.Pod.Volumes {
		if volume.Name.Equals(mountName) {
			return &volume, nil
		}
	}
	return nil, errors.New("Volume mount point not set :" + mountName.String())
}
<|endoftext|>