<commit_before>// Copyright 2017 tsuru 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 iaas provides interfaces that need to be satisfied in order to
// implement a new iaas on tsuru.
package iaas

import (
	"fmt"

	"github.com/pkg/errors"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/db/storage"
	"github.com/tsuru/tsuru/log"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

type Machine struct {
	Id             string `bson:"_id"`
	Iaas           string
	Status         string
	Address        string
	Port           int
	Protocol       string
	CreationParams map[string]string
	CustomData     map[string]interface{}
	CaCert         []byte
	ClientCert     []byte
	ClientKey      []byte
}

func CreateMachine(params map[string]string) (*Machine, error) {
	return CreateMachineForIaaS("", params)
}

func CreateMachineForIaaS(iaasName string, params map[string]string) (*Machine, error) {
	if iaasName == "" {
		iaasName, _ = params["iaas"]
	}
	if iaasName == "" {
		defaultIaaS, err := getDefaultIaasName()
		if err != nil {
			return nil, err
		}
		iaasName = defaultIaaS
	}
	params["iaas"] = iaasName
	iaas, err := getIaasProvider(iaasName)
	if err != nil {
		return nil, err
	}
	m, err := iaas.CreateMachine(params)
	if err != nil {
		return nil, err
	}
	params["iaas-id"] = m.Id
	m.Iaas = iaasName
	m.CreationParams = params
	err = m.saveToDB()
	if err != nil {
		m.Destroy()
		return nil, err
	}
	return m, nil
}

func ListMachines() ([]Machine, error) {
	coll, err := collection()
	if err != nil {
		return nil, err
	}
	defer coll.Close()
	var result []Machine
	err = coll.Find(nil).All(&result)
	return result, err
}

// Uses id or address, this is only used because previously we didn't have
// iaas-id in node metadata.
func FindMachineByIdOrAddress(id string, address string) (Machine, error) {
	coll, err := collection()
	if err != nil {
		return Machine{}, err
	}
	defer coll.Close()
	var result Machine
	query := bson.M{}
	if id != "" {
		query["_id"] = id
	} else {
		query["address"] = address
	}
	err = coll.Find(query).One(&result)
	return result, err
}

func FindMachineByAddress(address string) (Machine, error) {
	coll, err := collection()
	if err != nil {
		return Machine{}, err
	}
	defer coll.Close()
	var result Machine
	err = coll.Find(bson.M{"address": address}).One(&result)
	return result, err
}

func FindMachineById(id string) (Machine, error) {
	coll, err := collection()
	if err != nil {
		return Machine{}, err
	}
	defer coll.Close()
	var result Machine
	err = coll.FindId(id).One(&result)
	return result, err
}

func (m *Machine) Destroy() error {
	iaas, err := getIaasProvider(m.Iaas)
	if err != nil {
		return err
	}
	err = iaas.DeleteMachine(m)
	if err != nil {
		log.Errorf("failed to destroy machine in the IaaS: %s", err)
	}
	return m.removeFromDB()
}

func (m *Machine) FormatNodeAddress() string {
	protocol := m.Protocol
	if protocol == "" {
		protocol, _ = config.GetString("iaas:node-protocol")
	}
	if protocol == "" {
		protocol = "http"
	}
	port := m.Port
	if port == 0 {
		port, _ = config.GetInt("iaas:node-port")
	}
	if port == 0 {
		port = 2375
	}
	return fmt.Sprintf("%s://%s:%d", protocol, m.Address, port)
}

func (m *Machine) saveToDB() error {
	coll, err := collectionEnsureIdx()
	if err != nil {
		return err
	}
	defer coll.Close()
	_, err = coll.UpsertId(m.Id, m)
	return err
}

func (m *Machine) removeFromDB() error {
	coll, err := collection()
	if err != nil {
		return err
	}
	defer coll.Close()
	return coll.Remove(bson.M{"_id": m.Id})
}

func collection() (*storage.Collection, error) {
	name, err := config.GetString("iaas:collection")
	if err != nil {
		name = "iaas_machines"
	}
	conn, err := db.Conn()
	if err != nil {
		log.Errorf("Failed to connect to the database: %s", err)
		return nil, err
	}
	return conn.Collection(name), nil
}

func collectionEnsureIdx() (*storage.Collection, error) {
	coll, err := collection()
	if err != nil {
		return nil, err
	}
	index := mgo.Index{
		Key:    []string{"address"},
		Unique: true,
	}
	err = coll.EnsureIndex(index)
	if err != nil {
		coll.Close()
		return nil, errors.Errorf(`Could not create index on address for machines collection.
This can be caused by multiple machines with the same address, please run
"tsuru machine-list" to check for duplicated entries and "tsuru
machine-destroy" to remove them.
original error: %s`, err)
	}
	return coll, nil
}
<commit_msg>iaas: adds several prometheus metrics for machine create/destroy<commit_after>// Copyright 2017 tsuru 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 iaas provides interfaces that need to be satisfied in order to
// implement a new iaas on tsuru.
package iaas

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/tsuru/config"
	"github.com/tsuru/tsuru/db"
	"github.com/tsuru/tsuru/db/storage"
	"github.com/tsuru/tsuru/log"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

var (
	iaasDurationBuckets = append([]float64{10, 30}, prometheus.LinearBuckets(60, 60, 10)...)

	machineCreateDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Name:    "tsuru_iaas_create_histogram_seconds",
		Help:    "The machine creation latency distributions.",
		Buckets: iaasDurationBuckets,
	}, []string{"iaas"})

	machineDestroyDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
		Name:    "tsuru_iaas_destroy_histogram_seconds",
		Help:    "The machine destroy latency distributions.",
		Buckets: iaasDurationBuckets,
	}, []string{"iaas"})

	machineCreateErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "tsuru_iaas_create_errors_total",
		Help: "The total number of machine creation errors.",
	}, []string{"iaas"})

	machineDestroyErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
		Name: "tsuru_iaas_destroy_errors_total",
		Help: "The total number of machine destroy errors.",
	}, []string{"iaas"})
)

func init() {
	prometheus.MustRegister(machineCreateDuration)
	prometheus.MustRegister(machineDestroyDuration)
	prometheus.MustRegister(machineCreateErrors)
	prometheus.MustRegister(machineDestroyErrors)
}

type Machine struct {
	Id             string `bson:"_id"`
	Iaas           string
	Status         string
	Address        string
	Port           int
	Protocol       string
	CreationParams map[string]string
	CustomData     map[string]interface{}
	CaCert         []byte
	ClientCert     []byte
	ClientKey      []byte
}

func CreateMachine(params map[string]string) (*Machine, error) {
	return CreateMachineForIaaS("", params)
}

func CreateMachineForIaaS(iaasName string, params map[string]string) (*Machine, error) {
	if iaasName == "" {
		iaasName, _ = params["iaas"]
	}
	if iaasName == "" {
		defaultIaaS, err := getDefaultIaasName()
		if err != nil {
			return nil, err
		}
		iaasName = defaultIaaS
	}
	params["iaas"] = iaasName
	iaas, err := getIaasProvider(iaasName)
	if err != nil {
		return nil, err
	}
	t0 := time.Now()
	m, err := iaas.CreateMachine(params)
	machineCreateDuration.WithLabelValues(iaasName).Observe(time.Since(t0).Seconds())
	if err != nil {
		machineCreateErrors.WithLabelValues(iaasName).Inc()
		return nil, err
	}
	params["iaas-id"] = m.Id
	m.Iaas = iaasName
	m.CreationParams = params
	err = m.saveToDB()
	if err != nil {
		m.Destroy()
		return nil, err
	}
	return m, nil
}

func ListMachines() ([]Machine, error) {
	coll, err := collection()
	if err != nil {
		return nil, err
	}
	defer coll.Close()
	var result []Machine
	err = coll.Find(nil).All(&result)
	return result, err
}

// Uses id or address, this is only used because previously we didn't have
// iaas-id in node metadata.
func FindMachineByIdOrAddress(id string, address string) (Machine, error) {
	coll, err := collection()
	if err != nil {
		return Machine{}, err
	}
	defer coll.Close()
	var result Machine
	query := bson.M{}
	if id != "" {
		query["_id"] = id
	} else {
		query["address"] = address
	}
	err = coll.Find(query).One(&result)
	return result, err
}

func FindMachineByAddress(address string) (Machine, error) {
	coll, err := collection()
	if err != nil {
		return Machine{}, err
	}
	defer coll.Close()
	var result Machine
	err = coll.Find(bson.M{"address": address}).One(&result)
	return result, err
}

func FindMachineById(id string) (Machine, error) {
	coll, err := collection()
	if err != nil {
		return Machine{}, err
	}
	defer coll.Close()
	var result Machine
	err = coll.FindId(id).One(&result)
	return result, err
}

func (m *Machine) Destroy() error {
	iaas, err := getIaasProvider(m.Iaas)
	if err != nil {
		return err
	}
	t0 := time.Now()
	err = iaas.DeleteMachine(m)
	machineDestroyDuration.WithLabelValues(m.Iaas).Observe(time.Since(t0).Seconds())
	if err != nil {
		machineDestroyErrors.WithLabelValues(m.Iaas).Inc()
		log.Errorf("failed to destroy machine in the IaaS: %s", err)
	}
	return m.removeFromDB()
}

func (m *Machine) FormatNodeAddress() string {
	protocol := m.Protocol
	if protocol == "" {
		protocol, _ = config.GetString("iaas:node-protocol")
	}
	if protocol == "" {
		protocol = "http"
	}
	port := m.Port
	if port == 0 {
		port, _ = config.GetInt("iaas:node-port")
	}
	if port == 0 {
		port = 2375
	}
	return fmt.Sprintf("%s://%s:%d", protocol, m.Address, port)
}

func (m *Machine) saveToDB() error {
	coll, err := collectionEnsureIdx()
	if err != nil {
		return err
	}
	defer coll.Close()
	_, err = coll.UpsertId(m.Id, m)
	return err
}

func (m *Machine) removeFromDB() error {
	coll, err := collection()
	if err != nil {
		return err
	}
	defer coll.Close()
	return coll.Remove(bson.M{"_id": m.Id})
}

func collection() (*storage.Collection, error) {
	name, err := config.GetString("iaas:collection")
	if err != nil {
		name = "iaas_machines"
	}
	conn, err := db.Conn()
	if err != nil {
		log.Errorf("Failed to connect to the database: %s", err)
		return nil, err
	}
	return conn.Collection(name), nil
}

func collectionEnsureIdx() (*storage.Collection, error) {
	coll, err := collection()
	if err != nil {
		return nil, err
	}
	index := mgo.Index{
		Key:    []string{"address"},
		Unique: true,
	}
	err = coll.EnsureIndex(index)
	if err != nil {
		coll.Close()
		return nil, errors.Errorf(`Could not create index on address for machines collection.
This can be caused by multiple machines with the same address, please run
"tsuru machine-list" to check for duplicated entries and "tsuru
machine-destroy" to remove them.
original error: %s`, err)
	}
	return coll, nil
}
<|endoftext|>


<commit_before>package docker

import (
	"context"
	"github.com/docker/docker/api/types"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"net/http"
	"regexp"
)

var logWebsocketRequest = regexp.MustCompile(`/containers/([^/]+)/logs`)
var hostCheck = regexp.MustCompile(`vibioh\.fr$`)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return hostCheck.MatchString(r.Host)
	},
}

func logsContainerWebsocketHandler(w http.ResponseWriter, r *http.Request, containerID []byte) {
	logs, err := docker.ContainerLogs(context.Background(), string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true})
	if err != nil {
		log.Print(err)
		return
	}

	defer logs.Close()

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print(err)
		return
	}

	defer ws.Close()

	for {
		wsWriter, err := ws.NextWriter(websocket.TextMessage)
		if err != nil {
			log.Print(err)
			return
		}

		if _, err = io.Copy(wsWriter, logs); err != nil {
			log.Print(err)
			return
		}
	}
}

func handleWebsocket(w http.ResponseWriter, r *http.Request) {
	urlPath := []byte(r.URL.Path)

	if logWebsocketRequest.Match(urlPath) {
		logsContainerWebsocketHandler(w, r, logWebsocketRequest.FindSubmatch(urlPath)[1])
	}
}
<commit_msg>Update websocket.go<commit_after>package docker

import (
	"context"
	"github.com/docker/docker/api/types"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"net/http"
	"regexp"
)

var logWebsocketRequest = regexp.MustCompile(`/containers/([^/]+)/logs`)
var hostCheck = regexp.MustCompile(`vibioh\.fr$`)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return hostCheck.MatchString(r.Host)
	},
}

func logsContainerWebsocketHandler(w http.ResponseWriter, r *http.Request, containerID []byte) {
	logs, err := docker.ContainerLogs(context.Background(), string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true})
	if err != nil {
		log.Print(err)
		return
	}

	defer logs.Close()

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print(err)
		return
	}

	defer ws.Close()

	for {
		wsWriter, err := ws.NextWriter(websocket.BinaryMessage)
		if err != nil {
			log.Print(err)
			return
		}

		if _, err = io.Copy(wsWriter, logs); err != nil {
			log.Print(err)
			return
		}
	}
}

func handleWebsocket(w http.ResponseWriter, r *http.Request) {
	urlPath := []byte(r.URL.Path)

	if logWebsocketRequest.Match(urlPath) {
		logsContainerWebsocketHandler(w, r, logWebsocketRequest.FindSubmatch(urlPath)[1])
	}
}
<|endoftext|>


<commit_before>package docker

import (
    "bufio"
    "context"
    "encoding/json"
    "github.com/ViBiOh/dashboard/auth"
    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/filters"
    "github.com/gorilla/websocket"
    "log"
    "net/http"
    "regexp"
)

const ignoredByteLogSize = 8
const tailSize = `100`

var logWebsocketRequest = regexp.MustCompile(`containers/([^/]+)/logs`)
var statsWebsocketRequest = regexp.MustCompile(`containers/([^/]+)/stats`)
var eventsWebsocketRequest = regexp.MustCompile(`events`)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return hostCheck.MatchString(r.Host)
    },
}

func upgradeAndAuth(w http.ResponseWriter, r *http.Request) (*websocket.Conn, *auth.User, error) {
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        defer ws.Close()
        return nil, nil, err
    }

    _, basicAuth, err := ws.ReadMessage()
    if err != nil {
        defer ws.Close()
        return nil, nil, err
    }

    user, err := auth.IsAuthenticatedByAuth(string(basicAuth))
    if err != nil {
        ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))

        defer ws.Close()
        return nil, nil, err
    }

    return ws, user, nil
}

func logsContainerWebsocketHandler(w http.ResponseWriter, r *http.Request, containerID []byte) {
    ws, user, err := upgradeAndAuth(w, r)
    if err != nil {
        log.Print(err)
        return
    }
    defer ws.Close()

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    logs, err := docker.ContainerLogs(ctx, string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: tailSize})
    if err != nil {
        log.Print(err)
        return
    }
    defer logs.Close()

    go func() {
        defer cancel()

        scanner := bufio.NewScanner(logs)
        for scanner.Scan() {
            select {
            case <-ctx.Done():
                return

            default:
                logLine := scanner.Bytes()
                if len(logLine) > ignoredByteLogSize {
                    if err = ws.WriteMessage(websocket.TextMessage, logLine[ignoredByteLogSize:]); err != nil {
                        log.Printf(`[%s] Error while writing to logs socket: %v`, user.Username, err)
                        return
                    }
                }
            }
        }
    }()

    for {
        select {
        case <-ctx.Done():
            break

        default:
            messageType, _, err := ws.ReadMessage()

            if messageType == websocket.CloseMessage {
                return
            }

            if err != nil {
                log.Printf(`[%s] Error while reading from logs socket: %v`, user.Username, err)
                return
            }
        }
    }
}

func eventsWebsocketHandler(w http.ResponseWriter, r *http.Request) {
    ws, user, err := upgradeAndAuth(w, r)
    if err != nil {
        return
    }
    defer ws.Close()

    filtersArgs := filters.NewArgs()
    if labelFilters(&filtersArgs, user, nil) != nil {
        log.Printf(`[%s] Error while defining label filters: %v`, user.Username, err)
        return
    }
    if eventFilters(&filtersArgs) != nil {
        log.Printf(`[%s] Error while defining event filters: %v`, user.Username, err)
        return
    }

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    messages, errors := docker.Events(ctx, types.EventsOptions{Filters: filtersArgs})

    go func() {
        defer cancel()

        for {
            select {
            case <-ctx.Done():
                return

            case message := <-messages:
                messageJSON, err := json.Marshal(message)
                if err != nil {
                    log.Printf(`[%s] Error while marshalling event: %v`, user.Username, err)
                    return
                }

                if err = ws.WriteMessage(websocket.TextMessage, messageJSON); err != nil {
                    log.Printf(`[%s] Error while writing to events socket: %v`, user.Username, err)
                    return
                }

            case err := <-errors:
                log.Printf(`[%s] Error while reading events: %v`, user.Username, err)
                return
            }
        }
    }()

    for {
        select {
        case <-ctx.Done():
            break
        default:
            messageType, _, err := ws.ReadMessage()

            if messageType == websocket.CloseMessage {
                return
            }

            if err != nil {
                log.Printf(`[%s] Error while reading from events socket: %v`, user.Username, err)
                return
            }
        }
    }
}

func statsWebsocketHandler(w http.ResponseWriter, r *http.Request, containerID []byte) {
    ws, user, err := upgradeAndAuth(w, r)
    if err != nil {
        log.Print(err)
        return
    }
    defer ws.Close()

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    stats, err := docker.ContainerStats(ctx, string(containerID), true)
    if err != nil {
        log.Print(err)
        return
    }
    defer stats.Body.Close()

    go func() {
        defer cancel()

        scanner := bufio.NewScanner(stats.Body)
        for scanner.Scan() {
            select {
            case <-ctx.Done():
                log.Printf(`[%s] Stats context is over for writing`, user.Username)
                return

            default:
                if err = ws.WriteMessage(websocket.TextMessage, scanner.Bytes()); err != nil {
                    log.Printf(`[%s] Error while writing to stats socket: %v`, user.Username, err)
                    return
                }
            }
        }
    }()

    for {
        select {
        case <-ctx.Done():
            log.Printf(`[%s] Stats context is over for reading`, user.Username)
            return

        default:
            messageType, _, err := ws.ReadMessage()

            if messageType == websocket.CloseMessage {
                return
            }

            if err != nil && websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived, websocket.CloseAbnormalClosure){
                log.Printf(`[%s] Error while reading from stats socket: %v`, user.Username, err)
                return
            }
        }
    }
}

// WebsocketHandler for Docker Websocket request. Should be use with net/http
type WebsocketHandler struct {
}

func (handler WebsocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    urlPath := []byte(r.URL.Path)

    if logWebsocketRequest.Match(urlPath) {
        logsContainerWebsocketHandler(w, r, logWebsocketRequest.FindSubmatch(urlPath)[1])
    } else if eventsWebsocketRequest.Match((urlPath)) {
        eventsWebsocketHandler(w, r)
    } else if statsWebsocketRequest.Match(urlPath) {
        statsWebsocketHandler(w, r, statsWebsocketRequest.FindSubmatch(urlPath)[1])
    }
}
<commit_msg>Update websocket.go<commit_after>package docker

import (
    "bufio"
    "context"
    "encoding/json"
    "github.com/ViBiOh/dashboard/auth"
    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/filters"
    "github.com/gorilla/websocket"
    "log"
    "net/http"
    "regexp"
)

const ignoredByteLogSize = 8
const tailSize = `100`

var logWebsocketRequest = regexp.MustCompile(`containers/([^/]+)/logs`)
var statsWebsocketRequest = regexp.MustCompile(`containers/([^/]+)/stats`)
var eventsWebsocketRequest = regexp.MustCompile(`events`)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool {
        return hostCheck.MatchString(r.Host)
    },
}

func upgradeAndAuth(w http.ResponseWriter, r *http.Request) (*websocket.Conn, *auth.User, error) {
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        defer ws.Close()
        return nil, nil, err
    }

    _, basicAuth, err := ws.ReadMessage()
    if err != nil {
        defer ws.Close()
        return nil, nil, err
    }

    user, err := auth.IsAuthenticatedByAuth(string(basicAuth))
    if err != nil {
        ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))

        defer ws.Close()
        return nil, nil, err
    }

    return ws, user, nil
}

func logsContainerWebsocketHandler(w http.ResponseWriter, r *http.Request, containerID []byte) {
    ws, user, err := upgradeAndAuth(w, r)
    if err != nil {
        log.Print(err)
        return
    }
    defer ws.Close()

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    logs, err := docker.ContainerLogs(ctx, string(containerID), types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: tailSize})
    if err != nil {
        log.Print(err)
        return
    }
    defer logs.Close()

    go func() {
        defer cancel()

        scanner := bufio.NewScanner(logs)
        for scanner.Scan() {
            select {
            case <-ctx.Done():
                return

            default:
                logLine := scanner.Bytes()
                if len(logLine) > ignoredByteLogSize {
                    if err = ws.WriteMessage(websocket.TextMessage, logLine[ignoredByteLogSize:]); err != nil {
                        log.Printf(`[%s] Error while writing to logs socket: %v`, user.Username, err)
                        return
                    }
                }
            }
        }
    }()

    for {
        select {
        case <-ctx.Done():
            break

        default:
            messageType, _, err := ws.NextReader()

            if messageType == websocket.CloseMessage {
                return
            }

            if err != nil {
                log.Printf(`[%s] Error while reading from logs socket: %v`, user.Username, err)
                return
            }
        }
    }
}

func eventsWebsocketHandler(w http.ResponseWriter, r *http.Request) {
    ws, user, err := upgradeAndAuth(w, r)
    if err != nil {
        return
    }
    defer ws.Close()

    filtersArgs := filters.NewArgs()
    if labelFilters(&filtersArgs, user, nil) != nil {
        log.Printf(`[%s] Error while defining label filters: %v`, user.Username, err)
        return
    }
    if eventFilters(&filtersArgs) != nil {
        log.Printf(`[%s] Error while defining event filters: %v`, user.Username, err)
        return
    }

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    messages, errors := docker.Events(ctx, types.EventsOptions{Filters: filtersArgs})

    go func() {
        defer cancel()

        for {
            select {
            case <-ctx.Done():
                return

            case message := <-messages:
                messageJSON, err := json.Marshal(message)
                if err != nil {
                    log.Printf(`[%s] Error while marshalling event: %v`, user.Username, err)
                    return
                }

                if err = ws.WriteMessage(websocket.TextMessage, messageJSON); err != nil {
                    log.Printf(`[%s] Error while writing to events socket: %v`, user.Username, err)
                    return
                }

            case err := <-errors:
                log.Printf(`[%s] Error while reading events: %v`, user.Username, err)
                return
            }
        }
    }()

    for {
        select {
        case <-ctx.Done():
            break
        default:
            messageType, _, err := ws.NextReader()

            if messageType == websocket.CloseMessage {
                return
            }

            if err != nil {
                log.Printf(`[%s] Error while reading from events socket: %v`, user.Username, err)
                return
            }
        }
    }
}

func statsWebsocketHandler(w http.ResponseWriter, r *http.Request, containerID []byte) {
    ws, user, err := upgradeAndAuth(w, r)
    if err != nil {
        log.Print(err)
        return
    }
    defer ws.Close()

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    stats, err := docker.ContainerStats(ctx, string(containerID), true)
    if err != nil {
        log.Print(err)
        return
    }
    defer stats.Body.Close()

    go func() {
        defer cancel()

        scanner := bufio.NewScanner(stats.Body)
        for scanner.Scan() {
            select {
            case <-ctx.Done():
                log.Printf(`[%s] Stats context is over for writing`, user.Username)
                return

            default:
                if err = ws.WriteMessage(websocket.TextMessage, scanner.Bytes()); err != nil {
                    log.Printf(`[%s] Error while writing to stats socket: %v`, user.Username, err)
                    return
                }
            }
        }
    }()

    for {
        select {
        case <-ctx.Done():
            log.Printf(`[%s] Stats context is over for reading`, user.Username)
            return

        default:
            messageType, _, err := ws.NextReader()

            if messageType == websocket.CloseMessage {
                return
            }

            if err != nil && websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived, websocket.CloseAbnormalClosure){
                log.Printf(`[%s] Error while reading from stats socket: %v`, user.Username, err)
                return
            }
        }
    }
}

// WebsocketHandler for Docker Websocket request. Should be use with net/http
type WebsocketHandler struct {
}

func (handler WebsocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    urlPath := []byte(r.URL.Path)

    if logWebsocketRequest.Match(urlPath) {
        logsContainerWebsocketHandler(w, r, logWebsocketRequest.FindSubmatch(urlPath)[1])
    } else if eventsWebsocketRequest.Match((urlPath)) {
        eventsWebsocketHandler(w, r)
    } else if statsWebsocketRequest.Match(urlPath) {
        statsWebsocketHandler(w, r, statsWebsocketRequest.FindSubmatch(urlPath)[1])
    }
}
<|endoftext|>


<commit_before>package cloudflare

import (
	"encoding/json"
	"net/url"
	"strconv"
	"time"

	"github.com/pkg/errors"
)

// DNSRecord represents a DNS record in a zone.
type DNSRecord struct {
	ID         string      `json:"id,omitempty"`
	Type       string      `json:"type,omitempty"`
	Name       string      `json:"name,omitempty"`
	Content    string      `json:"content,omitempty"`
	Proxiable  bool        `json:"proxiable,omitempty"`
	Proxied    bool        `json:"proxied,omitempty"`
	TTL        int         `json:"ttl,omitempty"`
	Locked     bool        `json:"locked,omitempty"`
	ZoneID     string      `json:"zone_id,omitempty"`
	ZoneName   string      `json:"zone_name,omitempty"`
	CreatedOn  time.Time   `json:"created_on,omitempty"`
	ModifiedOn time.Time   `json:"modified_on,omitempty"`
	Data       interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
	Meta       interface{} `json:"meta,omitempty"`
	Priority   int         `json:"priority,omitempty"`
}

// DNSRecordResponse represents the response from the DNS endpoint.
type DNSRecordResponse struct {
	Result DNSRecord `json:"result"`
	Response
	ResultInfo `json:"result_info"`
}

// DNSListResponse represents the response from the list DNS records endpoint.
type DNSListResponse struct {
	Result []DNSRecord `json:"result"`
	Response
	ResultInfo `json:"result_info"`
}

// CreateDNSRecord creates a DNS record for the zone identifier.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (*DNSRecordResponse, error) {
	uri := "/zones/" + zoneID + "/dns_records"
	res, err := api.makeRequest("POST", uri, rr)
	if err != nil {
		return nil, errors.Wrap(err, errMakeRequestError)
	}

	var recordResp *DNSRecordResponse
	err = json.Unmarshal(res, &recordResp)
	if err != nil {
		return nil, errors.Wrap(err, errUnmarshalError)
	}

	return recordResp, nil
}

// DNSRecords returns a slice of DNS records for the given zone identifier.
//
// This takes a DNSRecord to allow filtering of the results returned.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
	// Construct a query string
	v := url.Values{}
	// Request as many records as possible per page - API max is 100
	v.Set("per_page", "100")
	if rr.Name != "" {
		v.Set("name", rr.Name)
	}
	if rr.Type != "" {
		v.Set("type", rr.Type)
	}
	if rr.Content != "" {
		v.Set("content", rr.Content)
	}

	var query string
	var records []DNSRecord
	page := 1

	// Loop over makeRequest until what we've fetched all records
	for {
		v.Set("page", strconv.Itoa(page))
		query = "?" + v.Encode()
		uri := "/zones/" + zoneID + "/dns_records" + query
		res, err := api.makeRequest("GET", uri, nil)
		if err != nil {
			return []DNSRecord{}, errors.Wrap(err, errMakeRequestError)
		}
		var r DNSListResponse
		err = json.Unmarshal(res, &r)
		if err != nil {
			return []DNSRecord{}, errors.Wrap(err, errUnmarshalError)
		}
		records = append(records, r.Result...)
		if r.ResultInfo.Page >= r.ResultInfo.TotalPages {
			break
		}
		// Loop around and fetch the next page
		page++
	}
	return records, nil
}

// DNSRecord returns a single DNS record for the given zone & record
// identifiers.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
	uri := "/zones/" + zoneID + "/dns_records/" + recordID
	res, err := api.makeRequest("GET", uri, nil)
	if err != nil {
		return DNSRecord{}, errors.Wrap(err, errMakeRequestError)
	}
	var r DNSRecordResponse
	err = json.Unmarshal(res, &r)
	if err != nil {
		return DNSRecord{}, errors.Wrap(err, errUnmarshalError)
	}
	return r.Result, nil
}

// UpdateDNSRecord updates a single DNS record for the given zone & record
// identifiers.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
	rec, err := api.DNSRecord(zoneID, recordID)
	if err != nil {
		return err
	}
	// Populate the record name from the existing one if the update didn't
	// specify it.
	if rr.Name == "" {
		rr.Name = rec.Name
	}
	if rr.Type == "" {
		rr.Type = rec.Type
	}
	uri := "/zones/" + zoneID + "/dns_records/" + recordID
	res, err := api.makeRequest("PATCH", uri, rr)
	if err != nil {
		return errors.Wrap(err, errMakeRequestError)
	}
	var r DNSRecordResponse
	err = json.Unmarshal(res, &r)
	if err != nil {
		return errors.Wrap(err, errUnmarshalError)
	}
	return nil
}

// DeleteDNSRecord deletes a single DNS record for the given zone & record
// identifiers.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
func (api *API) DeleteDNSRecord(zoneID, recordID string) error {
	uri := "/zones/" + zoneID + "/dns_records/" + recordID
	res, err := api.makeRequest("DELETE", uri, nil)
	if err != nil {
		return errors.Wrap(err, errMakeRequestError)
	}
	var r DNSRecordResponse
	err = json.Unmarshal(res, &r)
	if err != nil {
		return errors.Wrap(err, errUnmarshalError)
	}
	return nil
}
<commit_msg>dns: `Proxied` to become a boolean pointer<commit_after>package cloudflare

import (
	"encoding/json"
	"net/url"
	"strconv"
	"time"

	"github.com/pkg/errors"
)

// DNSRecord represents a DNS record in a zone.
type DNSRecord struct {
	ID         string      `json:"id,omitempty"`
	Type       string      `json:"type,omitempty"`
	Name       string      `json:"name,omitempty"`
	Content    string      `json:"content,omitempty"`
	Proxiable  bool        `json:"proxiable,omitempty"`
	Proxied    *bool       `json:"proxied,omitempty"`
	TTL        int         `json:"ttl,omitempty"`
	Locked     bool        `json:"locked,omitempty"`
	ZoneID     string      `json:"zone_id,omitempty"`
	ZoneName   string      `json:"zone_name,omitempty"`
	CreatedOn  time.Time   `json:"created_on,omitempty"`
	ModifiedOn time.Time   `json:"modified_on,omitempty"`
	Data       interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
	Meta       interface{} `json:"meta,omitempty"`
	Priority   int         `json:"priority,omitempty"`
}

// DNSRecordResponse represents the response from the DNS endpoint.
type DNSRecordResponse struct {
	Result DNSRecord `json:"result"`
	Response
	ResultInfo `json:"result_info"`
}

// DNSListResponse represents the response from the list DNS records endpoint.
type DNSListResponse struct {
	Result []DNSRecord `json:"result"`
	Response
	ResultInfo `json:"result_info"`
}

// CreateDNSRecord creates a DNS record for the zone identifier.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (*DNSRecordResponse, error) {
	uri := "/zones/" + zoneID + "/dns_records"
	res, err := api.makeRequest("POST", uri, rr)
	if err != nil {
		return nil, errors.Wrap(err, errMakeRequestError)
	}

	var recordResp *DNSRecordResponse
	err = json.Unmarshal(res, &recordResp)
	if err != nil {
		return nil, errors.Wrap(err, errUnmarshalError)
	}

	return recordResp, nil
}

// DNSRecords returns a slice of DNS records for the given zone identifier.
//
// This takes a DNSRecord to allow filtering of the results returned.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
	// Construct a query string
	v := url.Values{}
	// Request as many records as possible per page - API max is 100
	v.Set("per_page", "100")
	if rr.Name != "" {
		v.Set("name", rr.Name)
	}
	if rr.Type != "" {
		v.Set("type", rr.Type)
	}
	if rr.Content != "" {
		v.Set("content", rr.Content)
	}

	var query string
	var records []DNSRecord
	page := 1

	// Loop over makeRequest until what we've fetched all records
	for {
		v.Set("page", strconv.Itoa(page))
		query = "?" + v.Encode()
		uri := "/zones/" + zoneID + "/dns_records" + query
		res, err := api.makeRequest("GET", uri, nil)
		if err != nil {
			return []DNSRecord{}, errors.Wrap(err, errMakeRequestError)
		}
		var r DNSListResponse
		err = json.Unmarshal(res, &r)
		if err != nil {
			return []DNSRecord{}, errors.Wrap(err, errUnmarshalError)
		}
		records = append(records, r.Result...)
		if r.ResultInfo.Page >= r.ResultInfo.TotalPages {
			break
		}
		// Loop around and fetch the next page
		page++
	}
	return records, nil
}

// DNSRecord returns a single DNS record for the given zone & record
// identifiers.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
	uri := "/zones/" + zoneID + "/dns_records/" + recordID
	res, err := api.makeRequest("GET", uri, nil)
	if err != nil {
		return DNSRecord{}, errors.Wrap(err, errMakeRequestError)
	}
	var r DNSRecordResponse
	err = json.Unmarshal(res, &r)
	if err != nil {
		return DNSRecord{}, errors.Wrap(err, errUnmarshalError)
	}
	return r.Result, nil
}

// UpdateDNSRecord updates a single DNS record for the given zone & record
// identifiers.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
	rec, err := api.DNSRecord(zoneID, recordID)
	if err != nil {
		return err
	}
	// Populate the record name from the existing one if the update didn't
	// specify it.
	if rr.Name == "" {
		rr.Name = rec.Name
	}
	if rr.Type == "" {
		rr.Type = rec.Type
	}
	uri := "/zones/" + zoneID + "/dns_records/" + recordID
	res, err := api.makeRequest("PATCH", uri, rr)
	if err != nil {
		return errors.Wrap(err, errMakeRequestError)
	}
	var r DNSRecordResponse
	err = json.Unmarshal(res, &r)
	if err != nil {
		return errors.Wrap(err, errUnmarshalError)
	}
	return nil
}

// DeleteDNSRecord deletes a single DNS record for the given zone & record
// identifiers.
//
// API reference: https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
func (api *API) DeleteDNSRecord(zoneID, recordID string) error {
	uri := "/zones/" + zoneID + "/dns_records/" + recordID
	res, err := api.makeRequest("DELETE", uri, nil)
	if err != nil {
		return errors.Wrap(err, errMakeRequestError)
	}
	var r DNSRecordResponse
	err = json.Unmarshal(res, &r)
	if err != nil {
		return errors.Wrap(err, errUnmarshalError)
	}
	return nil
}
<|endoftext|>


<commit_before>//
//agent_check opens a listen port that responds with the CPU idle % and a command port that accepts management commands
//
//Inspired by http://blog.loadbalancer.org/open-source-windows-service-for-reporting-server-load-back-to-haproxy-load-balancer-feedback-agent/
//
//Responds to telnet request with CPU Idle %.

//Also opens up a command channel on localhost that will accept

//management commands (i.e. Drain, Stop, Ready) Can be used with [HAProxy’s](http://www.haproxy.org/)

//agent-check to weight traffic based on CPU load.

//Note: The agent check functionality was added as of version 1.5
//
//  [user@aServer ~]$ nc localhost 5309
//  UP 99%
//  [user@aServer ~]$ echo "DRAIN" | nc localhost 8675
//  DRAIN OK
//  [user@aServer ~]$ nc localhost 5309
//  DRAIN 99%
//
//  user@aServer ~]$ echo "READY" | nc localhost 8675
//  READY OK
//  [user@aServer ~]$ nc localhost 5309
//  READY 100%
//
//agent_check can be run from the command line or with supervisord and supervisord-like utilities.
package main
<commit_msg>more doc changes<commit_after>//
//haproxy agent-check utility
//
//Inspired by http://blog.loadbalancer.org/open-source-windows-service-for-reporting-server-load-back-to-haproxy-load-balancer-feedback-agent/
//
//Responds to telnet request with CPU Idle %.
//
//Also opens up a command channel on localhost that will accept
//management commands (i.e. Drain, Stop, Ready) Can be used with [HAProxy’s](http://www.haproxy.org/)
//agent-check to weight traffic based on CPU load.
//Note: The agent check functionality was added as of version 1.5
//
//  [user@aServer ~]$ nc localhost 5309
//  UP 99%
//  [user@aServer ~]$ echo "DRAIN" | nc localhost 8675
//  DRAIN OK
//  [user@aServer ~]$ nc localhost 5309
//  DRAIN 99%
//
//  user@aServer ~]$ echo "READY" | nc localhost 8675
//  READY OK
//  [user@aServer ~]$ nc localhost 5309
//  READY 100%
//
//agent_check can be run from the command line or with supervisord and supervisord-like utilities.
package main
<|endoftext|>


<commit_before>/*
Package dbapi provides access to the Deutsche Bank API
(https://developer.db.com).
The Deutsche Bank API provides developers with plausible costumer and bank data
to let them build great, highly connected apps.

In order to use the Deutsche Bank API you need to create an account at the
developer portal (https://developer.db.com) and follow the instructions there.
Short version: Create a new application, a new test user and authorize your
application to get the access token. Authentication isn't handled by this
package since there are great packages out there.
If you have a valid access token you can start to use this package.

    // Create a new client.
    AccessToken := "1234567890abcdefghijklmnopqrstuvwxyz"
    api, err := dbapi.New(
        SetToken(AccessToken),
    )
    if err != nil {
        fmt.Fatalln(err)
    }

    // Start to access the Deutsche Bank API (retrieve and print user accounts).
    accounts, response, err := api.Accounts.GetAll()
    if err != nil {
        fmt.Println(response)
        fmt.Fatalln(err)
    }
    fmt.Printf("%v", accounts)

It is also possible to use a custom http client instead of http.DefaultClient:

    // Create your custom http client.
    client := &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyFromEnvironment,
            Dial: (&net.Dialer{
                Timeout:   3 * time.Second,
                KeepAlive: 30 * time.Second,
            }).Dial,
            ExpectContinueTimeout: 1 * time.Second,
            ResponseHeaderTimeout: 3 * time.Second,
            TLSHandshakeTimeout:   3 * time.Second,
        },
    }

    // Use your custom http client.
    api, err := dbapi.New(
        AccessToken,
        dbapi.SetClient(client),
   )
   // ...
*/
package dbapi
<commit_msg>Updated documentation<commit_after>/*
Package dbapi provides access to the Deutsche Bank API
(https://developer.db.com).
The Deutsche Bank API provides developers with plausible costumer and bank data
to let them build great, highly connected apps.

In order to use the Deutsche Bank API you need to create an account at the
developer portal (https://developer.db.com) and follow the instructions there.
Short version: Create a new application, a new test user and authorize your
application to get the access token. Authentication isn't handled by this
package since there are great packages out there.
If you have a valid access token you can start to use this package.

    // Create a new client.
    AccessToken := "1234567890abcdefghijklmnopqrstuvwxyz"
    api, err := dbapi.New(
        dbapi.SetToken(AccessToken),
    )
    if err != nil {
        fmt.Fatalln(err)
    }

    // Start to access the Deutsche Bank API (retrieve and print user accounts).
    accounts, response, err := api.Accounts.GetAll()
    if err != nil {
        fmt.Println(response)
        fmt.Fatalln(err)
    }
    fmt.Printf("%v", accounts)

It is also possible to use a custom http client instead of http.DefaultClient:

    // Create your custom http client.
    client := &http.Client{
        Transport: &http.Transport{
            Proxy: http.ProxyFromEnvironment,
            Dial: (&net.Dialer{
                Timeout:   3 * time.Second,
                KeepAlive: 30 * time.Second,
            }).Dial,
            ExpectContinueTimeout: 1 * time.Second,
            ResponseHeaderTimeout: 3 * time.Second,
            TLSHandshakeTimeout:   3 * time.Second,
        },
    }

    // Use your custom http client.
    api, err := dbapi.New(
        dbapi.SetToken(AccessToken),
        dbapi.SetClient(client),
   )
   // ...
*/
package dbapi
<|endoftext|>


<commit_before>package fix

import (
	"reflect"
	"testing"
)

func TestFixerAmazonPrivateIP_Impl(t *testing.T) {
	var _ Fixer = new(FixerAmazonPrivateIP)
}

func TestFixerAmazonPrivateIP(t *testing.T) {
	cases := []struct {
		Input    map[string]interface{}
		Expected map[string]interface{}
	}{
		// Attach field == false
		{
			Input: map[string]interface{}{
				"type":           "amazon-ebs",
				"ssh_private_ip": false,
			},

			Expected: map[string]interface{}{
				"type":          "amazon-ebs",
				"ssh_interface": "public_ip",
			},
		},

		// Attach field == true
		{
			Input: map[string]interface{}{
				"type":           "amazon-ebs",
				"ssh_private_ip": true,
			},

			Expected: map[string]interface{}{
				"type":          "amazon-ebs",
				"ssh_interface": "private_ip",
			},
		},

		// ssh_private_ip specified as string
		{
			Input: map[string]interface{}{
				"type":           "amazon-ebs",
				"ssh_private_ip": "true",
			},

			Expected: map[string]interface{}{
				"type":          "amazon-ebs",
				"ssh_interface": "private_ip",
			},
		},
	}

	for _, tc := range cases {
		var f FixerAmazonPrivateIP

		input := map[string]interface{}{
			"builders": []map[string]interface{}{tc.Input},
		}

		expected := map[string]interface{}{
			"builders": []map[string]interface{}{tc.Expected},
		}

		output, err := f.Fix(input)
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		if !reflect.DeepEqual(output, expected) {
			t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected)
		}
	}
}

func TestFixerAmazonPrivateIPNonBoolean(t *testing.T) {
	var f FixerAmazonPrivateIP

	input := map[string]interface{}{
		"builders": []map[string]interface{}{map[string]interface{}{
			"type":           "amazon-ebs",
			"ssh_private_ip": "not-a-boolean-value",
		}},
	}

	_, err := f.Fix(input)
	if err == nil {
		t.Fatal("should have errored")
	}
}
<commit_msg>gofix<commit_after>package fix

import (
	"reflect"
	"testing"
)

func TestFixerAmazonPrivateIP_Impl(t *testing.T) {
	var _ Fixer = new(FixerAmazonPrivateIP)
}

func TestFixerAmazonPrivateIP(t *testing.T) {
	cases := []struct {
		Input    map[string]interface{}
		Expected map[string]interface{}
	}{
		// Attach field == false
		{
			Input: map[string]interface{}{
				"type":           "amazon-ebs",
				"ssh_private_ip": false,
			},

			Expected: map[string]interface{}{
				"type":          "amazon-ebs",
				"ssh_interface": "public_ip",
			},
		},

		// Attach field == true
		{
			Input: map[string]interface{}{
				"type":           "amazon-ebs",
				"ssh_private_ip": true,
			},

			Expected: map[string]interface{}{
				"type":          "amazon-ebs",
				"ssh_interface": "private_ip",
			},
		},

		// ssh_private_ip specified as string
		{
			Input: map[string]interface{}{
				"type":           "amazon-ebs",
				"ssh_private_ip": "true",
			},

			Expected: map[string]interface{}{
				"type":          "amazon-ebs",
				"ssh_interface": "private_ip",
			},
		},
	}

	for _, tc := range cases {
		var f FixerAmazonPrivateIP

		input := map[string]interface{}{
			"builders": []map[string]interface{}{tc.Input},
		}

		expected := map[string]interface{}{
			"builders": []map[string]interface{}{tc.Expected},
		}

		output, err := f.Fix(input)
		if err != nil {
			t.Fatalf("err: %s", err)
		}

		if !reflect.DeepEqual(output, expected) {
			t.Fatalf("unexpected: %#v\nexpected: %#v\n", output, expected)
		}
	}
}

func TestFixerAmazonPrivateIPNonBoolean(t *testing.T) {
	var f FixerAmazonPrivateIP

	input := map[string]interface{}{
		"builders": []map[string]interface{}{{
			"type":           "amazon-ebs",
			"ssh_private_ip": "not-a-boolean-value",
		}},
	}

	_, err := f.Fix(input)
	if err == nil {
		t.Fatal("should have errored")
	}
}
<|endoftext|>


<commit_before>/*
Package rx provides Reactive Extensions (ReactiveX) for Go, an API for
asynchronous programming with observable streams (Observables).

Heterogeneous

Heterogeneous simply means that you can mix types in function and method calls.
The implementation in this package is generated by expanding templates from the
"generic" subdirectory on the interface{} type. A function or method parameter
of type interface{} accepts mixed types.

	From(1,"hi",2.3).Println()

Creating Observables

Functions to create new observables from lists, slices and channels.
	From          http://reactivex.io/documentation/operators/from.html
	FromChan
	FromSlice

Combining Observables

Functions and methods on observable that allow combining multiple observables.
	Concat        http://reactivex.io/documentation/operators/concat.html

Transforming Observables

Functions and methods to transform observables to same or other types.
	Filter        http://reactivex.io/documentation/operators/filter.html
	MergeMap      http://reactivex.io/documentation/operators/flatmap.html
	Map           http://reactivex.io/documentation/operators/map.html
	Scan          http://reactivex.io/documentation/operators/scan.html

Side Effects triggered by Observables

Methods on observables to trigger side effects.
	Do            http://reactivex.io/documentation/operators/do.html
	DoOnError
	DoOnComplete
	Finally

For an overview of all implemented operators, see
https://github.com/reactivego/rx

Generics for Go

You don't need Generics for Go in order to use this package. If you are however
interested in regenerating this package, then read on.

The implementation in this package is generated from a generic implementation
found in the subdirectory "generic" inside this package. It works by replacing
the place-holder types in the templates with interface{}. To regenerate this
implementation, run jig inside this package directory as follows:

	go get -d github.com/reactivego/jig
	go run github.com/reactivego/jig -rv
*/
package rx

import _ "github.com/reactivego/rx/generic"

// In this package we have defined a non-exported alias 'any' for 'interface{}'.
// So in the examples, instead of 'interface{}' you will find 'any' being used.
// If you choose to use this package in your own code, you can decide for yourself
// how to call the interface{} type, this is not enforced by this package.
type any = interface{}
<commit_msg>Improve documentation.<commit_after>/*
Package rx provides Reactive Extensions (ReactiveX) for Go, an API for
asynchronous programming with observable streams (Observables).

What is rx?

Observables are the main focus of rx and they are (sort of) sets of events.
They represent values that changes over time and you get notified when they do.
- They assume zero to many values over time.
- They push values.
- They can take any amount of time to complete (or may never).
- They are cancellable.
- They are lazy; they don't do anything until you subscribe.

This implementation of rx not strongly typed. It uses `interface{}` for value
types, so you can mix different types of values in function and method calls:

	From(1,"hi",2.3).Println()

The call above creates an observable from ints and strings and then prints
them.

Creating Observables

Functions to create new observables from lists, slices and channels.
	From          http://reactivex.io/documentation/operators/from.html
	FromChan
	FromSlice

Combining Observables

Functions and methods on observable that allow combining multiple observables.
	Concat        http://reactivex.io/documentation/operators/concat.html

Transforming Observables

Functions and methods to transform observables to same or other types.
	Filter        http://reactivex.io/documentation/operators/filter.html
	MergeMap      http://reactivex.io/documentation/operators/flatmap.html
	Map           http://reactivex.io/documentation/operators/map.html
	Scan          http://reactivex.io/documentation/operators/scan.html

Side Effects triggered by Observables

Methods on observables to trigger side effects.
	Do            http://reactivex.io/documentation/operators/do.html
	DoOnError
	DoOnComplete
	Finally

For an overview of all implemented operators, see
https://github.com/reactivego/rx

Generics for Go

You don't need Generics for Go in order to use this package. If you are however
interested in regenerating this package, then read on.

The implementation in this package is generated from a generic implementation
found in the subdirectory "generic" inside this package. It works by replacing
the place-holder types in the templates with interface{}. To regenerate this
implementation, run jig inside this package directory as follows:

	go get -d github.com/reactivego/jig
	go run github.com/reactivego/jig -rv
*/
package rx

import _ "github.com/reactivego/rx/generic"

// In this package we have defined a non-exported alias 'any' for 'interface{}'.
// So in the examples, instead of 'interface{}' you will find 'any' being used.
// If you choose to use this package in your own code, you can decide for yourself
// how to call the interface{} type, this is not enforced by this package.
type any = interface{}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

/*
Package btcchain implements bitcoin block handling and chain selection rules.

The bitcoin block handling and chain selection rules are an integral, and quite
likely the most important, part of bitcoin.  Unfortunately, at the time of
this writing, these rules are also largely undocumented and had to be
ascertained from the bitcoind source code.  At its core, bitcoin is a
distributed consensus of which blocks are valid and which ones will comprise the
main block chain (public ledger) that ultimately determines accepted
transactions, so it is extremely important that fully validating nodes agree on
all rules.

At a high level, this package provides support for inserting new blocks into
the block chain according to the aforementioned rules.  It includes
functionality such as rejecting duplicate blocks, ensuring blocks and
transactions follow all rules, orphan handling, and best chain selection along
with reorganization.

Since this package does not deal with other bitcoin specifics such as network
communication or wallets, it provides a notification system which gives the
caller a high level of flexibility in how they want to react to certain events
such as orphan blocks which need their parents requested and newly connected
main chain blocks which might result in wallet updates.

Bitcoin Chain Processing Overview

Before a block is allowed into the block chain, it must go through an intensive
series of validation rules.  The following list serves as a general outline of
those rules to provide some intuition into what is going on under the hood, but
is by no means exhaustive:

 - Reject duplicate blocks
 - Perform a series of sanity checks on the block and its transactions such as
   verifying proof of work, timestamps, number and character of transactions,
   transaction amounts, script complexity, and merkle root calculations
 - Compare the block against predetermined checkpoints for expected timestamps
   and difficulty based on elapsed time since the checkpoint
 - Save the most recent orphan blocks for a limited time in case their parent
   blocks become available
 - Stop processing if the block is an orphan as the rest of the processing
   depends on the block's position within the block chain
 - Perform a series of more thorough checks that depend on the block's position
   within the block chain such as verifying block difficulties adhere to
   difficulty retarget rules, timestamps are after the median of the last
   several blocks, all transactions are finalized, checkpoint blocks match, and
   block versions are in line with the previous blocks
 - Determine how the block fits into the chain and perform different actions
   accordingly in order to ensure any side chains which have higher difficulty
   than the main chain become the new main chain
 - When a block is being connected to the main chain (either through
   reorganization of a side chain to the main chain or just extending the
   main chain), perform further checks on the block's transactions such as
   verifying transaction duplicates, script complexity for the combination of
   connected scripts, coinbase maturity, double spends, and connected
   transaction values
 - Run the transaction scripts to verify the spender is allowed to spend the
   coins
 - Insert the block into the block database

Block Processing Example

The following example program demonstrates processing a block.  This example
intentionally causes an error by attempting to process a duplicate block.

	package main

	import (
		"fmt"
		"github.com/conformal/btcchain"
		"github.com/conformal/btcdb"
		_ "github.com/conformal/btcdb/sqlite3"
		"github.com/conformal/btcutil"
		"github.com/conformal/btcwire"
		"os"
	)

	func main() {
		// Create a new database to store the accepted blocks into.  Typically
		// this would be opening an existing database, but we create a new db
		// here so this is a complete working example.  Also, typically the
		// calls to os.Remove would not be used either, but again, we want
		// a complete working example here, so we make sure to remove the
		// database.
		dbName := "example.db"
		_ = os.Remove(dbName)
		db, err := btcdb.CreateDB("sqlite", dbName)
		if err != nil {
			fmt.Printf("Failed to create database: %v\n", err)
			return
		}
		defer os.Remove(dbName) // Ignore error.
		defer db.Close()

		// Insert the main network genesis block.  This is part of the initial
		// database setup.  Like above, this typically would not be needed when
		// opening an existing database.
		pver := btcwire.ProtocolVersion
		genesisBlock := btcutil.NewBlock(&btcwire.GenesisBlock, pver)
		_, err = db.InsertBlock(genesisBlock)
		if err != nil {
			fmt.Printf("Failed to insert genesis block: %v\n", err)
			return
		}

		// Create a new BlockChain instance using the underlying database for
		// the main bitcoin network and ignore notifications.
		chain := btcchain.New(db, btcwire.MainNet, nil)

		// Process a block.  For this example, we are going to intentionally
		// cause an error by trying to process the genesis block which already
		// exists.
		err = chain.ProcessBlock(genesisBlock)
		if err != nil {
			fmt.Printf("Failed to process block: %v\n", err)
			return
		}
	}

Errors

Errors returned by this package are either the raw errors provided by underlying
calls or of type btcchain.RuleError.  This allows the caller to differentiate
between unexpected errors, such as database errors, versus errors due to rule
violations through type assertions.

Bitcoin Improvement Proposals

This package includes spec changes outlined by the following BIPs:

		BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
		BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
		BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)

Other important information

This package does not yet implement all of the unique rules for testnet.
*/
package btcchain
<commit_msg>Remove tesnet specific rules unsupported blurb.<commit_after>// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

/*
Package btcchain implements bitcoin block handling and chain selection rules.

The bitcoin block handling and chain selection rules are an integral, and quite
likely the most important, part of bitcoin.  Unfortunately, at the time of
this writing, these rules are also largely undocumented and had to be
ascertained from the bitcoind source code.  At its core, bitcoin is a
distributed consensus of which blocks are valid and which ones will comprise the
main block chain (public ledger) that ultimately determines accepted
transactions, so it is extremely important that fully validating nodes agree on
all rules.

At a high level, this package provides support for inserting new blocks into
the block chain according to the aforementioned rules.  It includes
functionality such as rejecting duplicate blocks, ensuring blocks and
transactions follow all rules, orphan handling, and best chain selection along
with reorganization.

Since this package does not deal with other bitcoin specifics such as network
communication or wallets, it provides a notification system which gives the
caller a high level of flexibility in how they want to react to certain events
such as orphan blocks which need their parents requested and newly connected
main chain blocks which might result in wallet updates.

Bitcoin Chain Processing Overview

Before a block is allowed into the block chain, it must go through an intensive
series of validation rules.  The following list serves as a general outline of
those rules to provide some intuition into what is going on under the hood, but
is by no means exhaustive:

 - Reject duplicate blocks
 - Perform a series of sanity checks on the block and its transactions such as
   verifying proof of work, timestamps, number and character of transactions,
   transaction amounts, script complexity, and merkle root calculations
 - Compare the block against predetermined checkpoints for expected timestamps
   and difficulty based on elapsed time since the checkpoint
 - Save the most recent orphan blocks for a limited time in case their parent
   blocks become available
 - Stop processing if the block is an orphan as the rest of the processing
   depends on the block's position within the block chain
 - Perform a series of more thorough checks that depend on the block's position
   within the block chain such as verifying block difficulties adhere to
   difficulty retarget rules, timestamps are after the median of the last
   several blocks, all transactions are finalized, checkpoint blocks match, and
   block versions are in line with the previous blocks
 - Determine how the block fits into the chain and perform different actions
   accordingly in order to ensure any side chains which have higher difficulty
   than the main chain become the new main chain
 - When a block is being connected to the main chain (either through
   reorganization of a side chain to the main chain or just extending the
   main chain), perform further checks on the block's transactions such as
   verifying transaction duplicates, script complexity for the combination of
   connected scripts, coinbase maturity, double spends, and connected
   transaction values
 - Run the transaction scripts to verify the spender is allowed to spend the
   coins
 - Insert the block into the block database

Block Processing Example

The following example program demonstrates processing a block.  This example
intentionally causes an error by attempting to process a duplicate block.

	package main

	import (
		"fmt"
		"github.com/conformal/btcchain"
		"github.com/conformal/btcdb"
		_ "github.com/conformal/btcdb/sqlite3"
		"github.com/conformal/btcutil"
		"github.com/conformal/btcwire"
		"os"
	)

	func main() {
		// Create a new database to store the accepted blocks into.  Typically
		// this would be opening an existing database, but we create a new db
		// here so this is a complete working example.  Also, typically the
		// calls to os.Remove would not be used either, but again, we want
		// a complete working example here, so we make sure to remove the
		// database.
		dbName := "example.db"
		_ = os.Remove(dbName)
		db, err := btcdb.CreateDB("sqlite", dbName)
		if err != nil {
			fmt.Printf("Failed to create database: %v\n", err)
			return
		}
		defer os.Remove(dbName) // Ignore error.
		defer db.Close()

		// Insert the main network genesis block.  This is part of the initial
		// database setup.  Like above, this typically would not be needed when
		// opening an existing database.
		pver := btcwire.ProtocolVersion
		genesisBlock := btcutil.NewBlock(&btcwire.GenesisBlock, pver)
		_, err = db.InsertBlock(genesisBlock)
		if err != nil {
			fmt.Printf("Failed to insert genesis block: %v\n", err)
			return
		}

		// Create a new BlockChain instance using the underlying database for
		// the main bitcoin network and ignore notifications.
		chain := btcchain.New(db, btcwire.MainNet, nil)

		// Process a block.  For this example, we are going to intentionally
		// cause an error by trying to process the genesis block which already
		// exists.
		err = chain.ProcessBlock(genesisBlock)
		if err != nil {
			fmt.Printf("Failed to process block: %v\n", err)
			return
		}
	}

Errors

Errors returned by this package are either the raw errors provided by underlying
calls or of type btcchain.RuleError.  This allows the caller to differentiate
between unexpected errors, such as database errors, versus errors due to rule
violations through type assertions.

Bitcoin Improvement Proposals

This package includes spec changes outlined by the following BIPs:

		BIP0016 (https://en.bitcoin.it/wiki/BIP_0016)
		BIP0030 (https://en.bitcoin.it/wiki/BIP_0030)
		BIP0034 (https://en.bitcoin.it/wiki/BIP_0034)
*/
package btcchain
<|endoftext|>


<commit_before>/*
Package form parses url.Values and fills a struct with values, creating objects as necessary.

It has the following features:

    - Primitives types cause zero allocations.
    - Supports map of almost all types.
    - Supports both Numbered and Normal arrays i.e. "Array[0]" and just "Array" with multiple values passed.
    - Allows for Custom Type registration.
    - Handles time.Time using RFC3339 time format by default, but can easily be changes usings registering a Custom Type.

Common Questions

Questions

    Does it support encoding.TextUnmarshaler?
    No because TextUnmarshaler only accepts []byte but posted values can have multiple values, so is not suitable.

Supported Types

out of the box supported types

    - string
    - bool
    - int, int8, int16, int32, int64
    - uint, uint8, uint16, uint32, uint64
    - float32, float64
    - struct and anonymous struct
    - interface{}
    - time.Time` - by default using RFC3339
    - a `pointer` to one of the above types
    - slice, array
    - map
    - `custom types` can override any of the above types
    - many other types may be supported inherently (i.e. bson.ObjectId is type ObjectId string,
      which will get populated by the string type

    **NOTE**: map, struct and slice nesting are ad infinitum.

Usage

symbols

    - Use symbol `.` for separating fields/structs. (i.e, `structfield.field`)
    - Use `[index or key]` for access to index of a slice/array or key for map.
      (i.e, `arrayfield[0]`, `mapfield[keyvalue]`)

html

    <form method="POST">
        <input type="text" name="Name" value="joeybloggs"/>
        <input type="text" name="Age" value="3"/>
        <input type="text" name="Gender" value="Male"/>
        <input type="text" name="Address[0].Name" value="26 Here Blvd."/>
        <input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
        <input type="text" name="Address[1].Name" value="26 There Blvd."/>
        <input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
        <input type="text" name="active" value="true"/>
        <input type="text" name="MapExample[key]" value="value"/>
        <input type="text" name="NestedMap[key][key]" value="value"/>
        <input type="text" name="NestedArray[0][0]" value="value"/>
        <input type="submit"/>
    </form>

Example

example parsing the above HTML

    package main

    import (
        "fmt"
        "log"
        "net/url"

        "github.com/go-playground/form"
    )

    // Address contains address information
    type Address struct {
        Name  string
        Phone string
    }

    // User contains user information
    type User struct {
        Name        string
        Age         uint8
        Gender      string
        Address     []Address
        Active      bool `form:"active"`
        MapExample  map[string]string
        NestedMap   map[string]map[string]string
        NestedArray [][]string
    }

    // use a single instance of Decoder, it caches struct info
    var decoder *form.Decoder

    func main() {
        decoder = form.NewDecoder()

        // this simulates the results of http.Request's ParseForm() function
        values := parseForm()

        var user User

        // must pass a pointer
        err := decoder.Decode(&user, values)
        if err != nil {
            log.Panic(err)
        }

        fmt.Printf("%#v\n", user)
    }

    // this simulates the results of http.Request's ParseForm() function
    func parseForm() url.Values {
        return url.Values{
            "Name":                []string{"joeybloggs"},
            "Age":                 []string{"3"},
            "Gender":              []string{"Male"},
            "Address[0].Name":     []string{"26 Here Blvd."},
            "Address[0].Phone":    []string{"9(999)999-9999"},
            "Address[1].Name":     []string{"26 There Blvd."},
            "Address[1].Phone":    []string{"1(111)111-1111"},
            "active":              []string{"true"},
            "MapExample[key]":     []string{"value"},
            "NestedMap[key][key]": []string{"value"},
            "NestedArray[0][0]":   []string{"value"},
        }
    }

Registering Custom Types

can easily register custom types.

    decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
            return time.Parse("2006-01-02", vals[0])
        }, time.Time{})
*/
package form
<commit_msg>update good alignment<commit_after>/*
Package form parses url.Values and fills a struct with values, creating objects as necessary.

It has the following features:

    - Primitives types cause zero allocations.
    - Supports map of almost all types.
    - Supports both Numbered and Normal arrays i.e. "Array[0]" and just "Array"
      with multiple values passed.
    - Allows for Custom Type registration.
    - Handles time.Time using RFC3339 time format by default,
      but can easily be changes usings registering a Custom Type.

Common Questions

Questions

    Does it support encoding.TextUnmarshaler?
    No because TextUnmarshaler only accepts []byte but posted values can have
    multiple values, so is not suitable.

Supported Types

out of the box supported types

    - string
    - bool
    - int, int8, int16, int32, int64
    - uint, uint8, uint16, uint32, uint64
    - float32, float64
    - struct and anonymous struct
    - interface{}
    - time.Time` - by default using RFC3339
    - a `pointer` to one of the above types
    - slice, array
    - map
    - `custom types` can override any of the above types
    - many other types may be supported inherently (i.e. bson.ObjectId is
      type ObjectId string, which will get populated by the string type

    **NOTE**: map, struct and slice nesting are ad infinitum.

Usage

symbols

    - Use symbol `.` for separating fields/structs. (i.e, `structfield.field`)
    - Use `[index or key]` for access to index of a slice/array or key for map.
      (i.e, `arrayfield[0]`, `mapfield[keyvalue]`)

html

    <form method="POST">
        <input type="text" name="Name" value="joeybloggs"/>
        <input type="text" name="Age" value="3"/>
        <input type="text" name="Gender" value="Male"/>
        <input type="text" name="Address[0].Name" value="26 Here Blvd."/>
        <input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
        <input type="text" name="Address[1].Name" value="26 There Blvd."/>
        <input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
        <input type="text" name="active" value="true"/>
        <input type="text" name="MapExample[key]" value="value"/>
        <input type="text" name="NestedMap[key][key]" value="value"/>
        <input type="text" name="NestedArray[0][0]" value="value"/>
        <input type="submit"/>
    </form>

Example

example parsing the above HTML

    package main

    import (
        "fmt"
        "log"
        "net/url"

        "github.com/go-playground/form"
    )

    // Address contains address information
    type Address struct {
        Name  string
        Phone string
    }

    // User contains user information
    type User struct {
        Name        string
        Age         uint8
        Gender      string
        Address     []Address
        Active      bool `form:"active"`
        MapExample  map[string]string
        NestedMap   map[string]map[string]string
        NestedArray [][]string
    }

    // use a single instance of Decoder, it caches struct info
    var decoder *form.Decoder

    func main() {
        decoder = form.NewDecoder()

        // this simulates the results of http.Request's ParseForm() function
        values := parseForm()

        var user User

        // must pass a pointer
        err := decoder.Decode(&user, values)
        if err != nil {
            log.Panic(err)
        }

        fmt.Printf("%#v\n", user)
    }

    // this simulates the results of http.Request's ParseForm() function
    func parseForm() url.Values {
        return url.Values{
            "Name":                []string{"joeybloggs"},
            "Age":                 []string{"3"},
            "Gender":              []string{"Male"},
            "Address[0].Name":     []string{"26 Here Blvd."},
            "Address[0].Phone":    []string{"9(999)999-9999"},
            "Address[1].Name":     []string{"26 There Blvd."},
            "Address[1].Phone":    []string{"1(111)111-1111"},
            "active":              []string{"true"},
            "MapExample[key]":     []string{"value"},
            "NestedMap[key][key]": []string{"value"},
            "NestedArray[0][0]":   []string{"value"},
        }
    }

Registering Custom Types

can easily register custom types.

    decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
            return time.Parse("2006-01-02", vals[0])
        }, time.Time{})
*/
package form
<|endoftext|>


<commit_before>/*
Package sqlite3 provides interface to SQLite3 databases.

This works as a driver for database/sql.

Installation

    go get github.com/mattn/go-sqlite3

Supported Types

Currently, go-sqlite3 supports the following data types.

    +------------------------------+
    |go        | sqlite3           |
    |----------|-------------------|
    |nil       | null              |
    |int       | integer           |
    |int64     | integer           |
    |float64   | float             |
    |bool      | integer           |
    |[]byte    | blob              |
    |string    | text              |
    |time.Time | timestamp/datetime|
    +------------------------------+

SQLite3 Extension

You can write your own extension module for sqlite3. For example, below is an
extension for a Regexp matcher operation.

    #include <pcre.h>
    #include <string.h>
    #include <stdio.h>
    #include <sqlite3ext.h>

    SQLITE_EXTENSION_INIT1
    static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
      if (argc >= 2) {
        const char *target  = (const char *)sqlite3_value_text(argv[1]);
        const char *pattern = (const char *)sqlite3_value_text(argv[0]);
        const char* errstr = NULL;
        int erroff = 0;
        int vec[500];
        int n, rc;
        pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
        rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
        if (rc <= 0) {
          sqlite3_result_error(context, errstr, 0);
          return;
        }
        sqlite3_result_int(context, 1);
      }
    }

    #ifdef _WIN32
    __declspec(dllexport)
    #endif
    int sqlite3_extension_init(sqlite3 *db, char **errmsg,
          const sqlite3_api_routines *api) {
      SQLITE_EXTENSION_INIT2(api);
      return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8,
          (void*)db, regexp_func, NULL, NULL);
    }

It needs to be built as a so/dll shared library. And you need to register
the extension module like below.

	sql.Register("sqlite3_with_extensions",
		&sqlite3.SQLiteDriver{
			Extensions: []string{
				"sqlite3_mod_regexp",
			},
		})

Then, you can use this extension.

	rows, err := db.Query("select text from mytable where name regexp '^golang'")

Connection Hook

You can hook and inject your code when the connection is established. database/sql
doesn't provide a way to get native go-sqlite3 interfaces. So if you want,
you need to set ConnectHook and get the SQLiteConn.

	sql.Register("sqlite3_with_hook_example",
			&sqlite3.SQLiteDriver{
					ConnectHook: func(conn *sqlite3.SQLiteConn) error {
						sqlite3conn = append(sqlite3conn, conn)
						return nil
					},
			})

Go SQlite3 Extensions

If you want to register Go functions as SQLite extension functions,
call RegisterFunction from ConnectHook.

	regex = func(re, s string) (bool, error) {
		return regexp.MatchString(re, s)
	}
	sql.Register("sqlite3_with_go_func",
			&sqlite3.SQLiteDriver{
					ConnectHook: func(conn *sqlite3.SQLiteConn) error {
						return conn.RegisterFunc("regexp", regex, true)
					},
			})

See the documentation of RegisterFunc for more details.

*/
package sqlite3
<commit_msg>Make Go 1.7 fail compilation<commit_after>/*
Package sqlite3 provides interface to SQLite3 databases.

This works as a driver for database/sql.

Installation

    go get github.com/mattn/go-sqlite3

Supported Types

Currently, go-sqlite3 supports the following data types.

    +------------------------------+
    |go        | sqlite3           |
    |----------|-------------------|
    |nil       | null              |
    |int       | integer           |
    |int64     | integer           |
    |float64   | float             |
    |bool      | integer           |
    |[]byte    | blob              |
    |string    | text              |
    |time.Time | timestamp/datetime|
    +------------------------------+

SQLite3 Extension

You can write your own extension module for sqlite3. For example, below is an
extension for a Regexp matcher operation.

    #include <pcre.h>
    #include <string.h>
    #include <stdio.h>
    #include <sqlite3ext.h>

    SQLITE_EXTENSION_INIT1
    static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
      if (argc >= 2) {
        const char *target  = (const char *)sqlite3_value_text(argv[1]);
        const char *pattern = (const char *)sqlite3_value_text(argv[0]);
        const char* errstr = NULL;
        int erroff = 0;
        int vec[500];
        int n, rc;
        pcre* re = pcre_compile(pattern, 0, &errstr, &erroff, NULL);
        rc = pcre_exec(re, NULL, target, strlen(target), 0, 0, vec, 500);
        if (rc <= 0) {
          sqlite3_result_error(context, errstr, 0);
          return;
        }
        sqlite3_result_int(context, 1);
      }
    }

    #ifdef _WIN32
    __declspec(dllexport)
    #endif
    int sqlite3_extension_init(sqlite3 *db, char **errmsg,
          const sqlite3_api_routines *api) {
      SQLITE_EXTENSION_INIT2(api);
      return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8,
          (void*)db, regexp_func, NULL, NULL);
    }

It needs to be built as a so/dll shared library. And you need to register
the extension module like below.

	sql.Register("sqlite3_with_extensions",
		&sqlite3.SQLiteDriver{
			Extensions: []string{
				"sqlite3_mod_regexp",
			},
		})

Then, you can use this extension.

	rows, err := db.Query("select text from mytable where name regexp '^golang'")

Connection Hook

You can hook and inject your code when the connection is established. database/sql
doesn't provide a way to get native go-sqlite3 interfaces. So if you want,
you need to set ConnectHook and get the SQLiteConn.

	sql.Register("sqlite3_with_hook_example",
			&sqlite3.SQLiteDriver{
					ConnectHook: func(conn *sqlite3.SQLiteConn) error {
						sqlite3conn = append(sqlite3conn, conn)
						return nil
					},
			})

Go SQlite3 Extensions

If you want to register Go functions as SQLite extension functions,
call RegisterFunction from ConnectHook.

	regex = func(re, s string) (bool, error) {
		return regexp.MatchString(re, s)
	}
	sql.Register("sqlite3_with_go_func",
			&sqlite3.SQLiteDriver{
					ConnectHook: func(conn *sqlite3.SQLiteConn) error {
						return conn.RegisterFunc("regexp", regex, true)
					},
			})

See the documentation of RegisterFunc for more details.

*/
package sqlite3

import "C"
<|endoftext|>


<commit_before>// General use authentication package for Go.
package gomniauth
<commit_msg>added link to doc<commit_after>// General use authentication package for Go.
//
// To get started, visit the Gomniauth GitHub project
// homepage: https://github.com/stretchr/gomniauth
package gomniauth
<|endoftext|>


<commit_before>// Hanayo is the Ripple front-end web server.
package main

// version is the current version of hanayo
const version = "v1.3.7"
<commit_msg>⬆ v1.4.0 ⬆<commit_after>// Hanayo is the Ripple front-end web server.
package main

// version is the current version of hanayo
const version = "v1.4.0"
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"runtime"
	"time"
)

type email struct {
	from    string
	to      string
	current int
}

func (e *email) Current(i int) {
	e.current = i
}

func (e *email) From(s string) {
	e.from = s
}

func (e *email) To(s string) {
	e.to = s
}

func (e *email) Send(i int) {
	if e.current != i {
		fmt.Printf("[Wrong] step %d, from: %s, to: %s\n", i, e.from, e.to)
	} else {
		fmt.Printf("step %d, from: %s, to: %s\n", i, e.from, e.to)
	}
}

func (e email) Current2(i int) email {
	e.current = i

	return e
}

func (e email) From2(s string) email {
	e.from = s

	return e
}

func (e email) To2(s string) email {
	e.to = s

	return e
}

func (e email) Send2(i int) {
	if e.current != i {
		fmt.Printf("[Wrong] step %d, from: %s, to: %s\n", i, e.from, e.to)
	} else {
		fmt.Printf("step %d, from: %s, to: %s\n", i, e.from, e.to)
	}
}

func main() {
	fmt.Println("CPU:", runtime.NumCPU())
	e := &email{}
	fmt.Println("==============================")

	for i := 0; i < 10; i++ {
		e.Current(i)
		e.From(fmt.Sprintf("example%02d@gmail.com", i))
		e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
		e.Send(i)
	}

	fmt.Println("==============================")
	fmt.Println("Wrong Result")
	for i := 0; i < 10; i++ {
		go func(i int) {
			e.Current(i)
			e.From(fmt.Sprintf("example%02d@gmail.com", i))
			e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
			e.Send(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	fmt.Println("==============================")

	fmt.Println("Fix Result 01")
	for i := 0; i < 10; i++ {
		go func(i int) {
			e := &email{}
			e.Current(i)
			e.From(fmt.Sprintf("example%02d@gmail.com", i))
			e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
			e.Send(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	fmt.Println("==============================")

	fmt.Println("Fix Result 02")
	for i := 0; i < 10; i++ {
		go func(i int) {
			e.Current2(i).
				From2(fmt.Sprintf("example%02d@gmail.com", i)).
				To2(fmt.Sprintf("example%02d@gmail.com", i+1)).
				Send2(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	fmt.Println("==============================")
}
<commit_msg>try resolve runtime GOMAXPROCS<commit_after>package main

import (
	"fmt"
	"runtime"
	"time"
)

type email struct {
	from    string
	to      string
	current int
}

func (e *email) Current(i int) {
	e.current = i
}

func (e *email) From(s string) {
	e.from = s
}

func (e *email) To(s string) {
	e.to = s
}

func (e *email) Send(i int) {
	if e.current != i {
		fmt.Printf("[Wrong] step %d, from: %s, to: %s\n", i, e.from, e.to)
	} else {
		fmt.Printf("step %d, from: %s, to: %s\n", i, e.from, e.to)
	}
}

func (e email) Current2(i int) email {
	e.current = i

	return e
}

func (e email) From2(s string) email {
	e.from = s

	return e
}

func (e email) To2(s string) email {
	e.to = s

	return e
}

func (e email) Send2(i int) {
	if e.current != i {
		fmt.Printf("[Wrong] step %d, from: %s, to: %s\n", i, e.from, e.to)
	} else {
		fmt.Printf("step %d, from: %s, to: %s\n", i, e.from, e.to)
	}
}

func main() {
	fmt.Println("CPU:", runtime.NumCPU())
	e := &email{}
	fmt.Println("==============================")

	for i := 0; i < 10; i++ {
		e.Current(i)
		e.From(fmt.Sprintf("example%02d@gmail.com", i))
		e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
		e.Send(i)
	}

	fmt.Println("==============================")
	fmt.Println("Wrong Result")
	for i := 0; i < 10; i++ {
		go func(i int) {
			e.Current(i)
			e.From(fmt.Sprintf("example%02d@gmail.com", i))
			e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
			e.Send(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	fmt.Println("==============================")

	fmt.Println("Fix GOMAXPROCS")
	runtime.GOMAXPROCS(1)
	for i := 0; i < 10; i++ {
		go func(i int) {
			e.Current(i)
			e.From(fmt.Sprintf("example%02d@gmail.com", i))
			e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
			e.Send(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	runtime.GOMAXPROCS(runtime.NumCPU())
	fmt.Println("==============================")

	fmt.Println("Fix Result 01")
	for i := 0; i < 10; i++ {
		go func(i int) {
			e := &email{}
			e.Current(i)
			e.From(fmt.Sprintf("example%02d@gmail.com", i))
			e.To(fmt.Sprintf("example%02d@gmail.com", i+1))
			e.Send(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	fmt.Println("==============================")

	fmt.Println("Fix Result 02")
	for i := 0; i < 10; i++ {
		go func(i int) {
			e.Current2(i).
				From2(fmt.Sprintf("example%02d@gmail.com", i)).
				To2(fmt.Sprintf("example%02d@gmail.com", i+1)).
				Send2(i)
		}(i)
	}
	time.Sleep(1 * time.Second)
	fmt.Println("==============================")
}
<|endoftext|>


<commit_before>package microservicecore

import (
	"log"
	"os"
)

// GetEnvOrFail - Get an environment variable by name.
//
// Or if the requested variable does not exist, throw a fatal error.
//
// Params:
//     name string - The name of the environment variable to get.
//
// Return:
//     string - The value of the requested environment variable.
func GetEnvOrFail(name string) string {
	envVar := os.Getenv(name)
	if envVar == "" {
		log.Fatalf("Environment variable (%s) has not been set.", name)
	}

	return envVar
}
<commit_msg>distinguish between empty and unset env var (#8)<commit_after>package microservicecore

import (
	"log"
	"os"
)

// GetEnvOrFail - Get an environment variable by name.
//
// Or if the requested variable does not exist, throw a fatal error.
//
// Params:
//     name string - The name of the environment variable to get.
//
// Return:
//     string - The value of the requested environment variable.
func GetEnvOrFail(name string) string {
	envVar, ok := os.LookupEnv(name)
	if !ok {
		log.Fatalf("environment variable (%s) has not been set", name)
	}
	if envVar == "" {
		log.Fatalf("environment variable (%s) is empty", name)
	}
	return envVar
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"strings"
)

const (
	VERSION                   = "0.0.1"
	defaultPlaceholder        = "{{}}"
	keyBackspace              = 8
	keyDelete                 = 127
	keyEndOfTransmission      = 4
	keyLineFeed               = 10
	keyCarriageReturn         = 13
	keyEndOfTransmissionBlock = 23
)

var placeholder string

var usage = `fzz allows you to run a command interactively.

Usage:

	fzz command

The command MUST include the placeholder '{{}}'.

Arguments:

	-v		Print version and exit
`

func printUsage() {
	fmt.Printf(usage)
}

func isPipe(f *os.File) bool {
	s, err := f.Stat()
	if err != nil {
		return false
	}

	return s.Mode()&os.ModeNamedPipe != 0
}

func containsPlaceholder(s []string, ph string) bool {
	for _, v := range s {
		if strings.Contains(v, ph) {
			return true
		}
	}
	return false
}

func validPlaceholder(p string) bool {
	return len(p)%2 == 0
}

func removeLastWord(s []byte) []byte {
	fields := bytes.Fields(s)
	if len(fields) > 0 {
		r := bytes.Join(fields[:len(fields)-1], []byte{' '})
		if len(r) > 1 {
			r = append(r, ' ')
		}
		return r
	}
	return []byte{}
}

func main() {
	flVersion := flag.Bool("v", false, "Print fzz version and quit")
	flag.Usage = printUsage
	flag.Parse()

	if *flVersion {
		fmt.Printf("fzz %s\n", VERSION)
		os.Exit(0)
	}

	if len(flag.Args()) < 2 {
		fmt.Fprintf(os.Stderr, usage)
		os.Exit(1)
	}

	if placeholder = os.Getenv("FZZ_PLACEHOLDER"); placeholder == "" {
		placeholder = defaultPlaceholder
	}

	if !validPlaceholder(placeholder) {
		fmt.Fprintln(os.Stderr, "Placeholder is not valid, needs even number of characters")
		os.Exit(1)
	}

	if !containsPlaceholder(flag.Args(), placeholder) {
		fmt.Fprintln(os.Stderr, "No placeholder in arguments")
		os.Exit(1)
	}

	tty, err := NewTTY()
	if err != nil {
		log.Fatal(err)
	}
	defer tty.resetState()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		tty.resetState()
		os.Exit(1)
	}()
	tty.setSttyState("cbreak", "-echo")

	printer := NewPrinter(tty, tty.cols, tty.rows-1) // prompt is one row
	runner := &Runner{
		printer:     printer,
		template:    flag.Args(),
		placeholder: placeholder,
	}

	if isPipe(os.Stdin) {
		runner.stdinbuf = new(bytes.Buffer)
		io.Copy(runner.stdinbuf, os.Stdin)
	}

	input := make([]byte, 0)
	b := make([]byte, 1)

	for {
		tty.resetScreen()
		tty.printPrompt(input[:len(input)])

		if len(input) > 0 {
			runner.killCurrent()

			go func() {
				runner.runWithInput(input[:len(input)])
				tty.cursorAfterPrompt(len(input))
			}()
		}

		tty.Read(b)
		switch b[0] {
		case keyBackspace, keyDelete:
			if len(input) > 1 {
				input = input[:len(input)-1]
			} else if len(input) == 1 {
				input = nil
			}
		case keyEndOfTransmission, keyLineFeed, keyCarriageReturn:
			tty.resetScreen()
			runner.writeCmdStdout(os.Stdout)
			return
		case keyEndOfTransmissionBlock:
			input = removeLastWord(input)
		default:
			// TODO: Default is wrong here. Only append printable characters to
			// input
			input = append(input, b...)
		}
	}
}
<commit_msg>Fix cursor position on utf8 input<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"strings"
	"unicode/utf8"
)

const (
	VERSION                   = "0.0.1"
	defaultPlaceholder        = "{{}}"
	keyBackspace              = 8
	keyDelete                 = 127
	keyEndOfTransmission      = 4
	keyLineFeed               = 10
	keyCarriageReturn         = 13
	keyEndOfTransmissionBlock = 23
)

var placeholder string

var usage = `fzz allows you to run a command interactively.

Usage:

	fzz command

The command MUST include the placeholder '{{}}'.

Arguments:

	-v		Print version and exit
`

func printUsage() {
	fmt.Printf(usage)
}

func isPipe(f *os.File) bool {
	s, err := f.Stat()
	if err != nil {
		return false
	}

	return s.Mode()&os.ModeNamedPipe != 0
}

func containsPlaceholder(s []string, ph string) bool {
	for _, v := range s {
		if strings.Contains(v, ph) {
			return true
		}
	}
	return false
}

func validPlaceholder(p string) bool {
	return len(p)%2 == 0
}

func removeLastWord(s []byte) []byte {
	fields := bytes.Fields(s)
	if len(fields) > 0 {
		r := bytes.Join(fields[:len(fields)-1], []byte{' '})
		if len(r) > 1 {
			r = append(r, ' ')
		}
		return r
	}
	return []byte{}
}

func main() {
	flVersion := flag.Bool("v", false, "Print fzz version and quit")
	flag.Usage = printUsage
	flag.Parse()

	if *flVersion {
		fmt.Printf("fzz %s\n", VERSION)
		os.Exit(0)
	}

	if len(flag.Args()) < 2 {
		fmt.Fprintf(os.Stderr, usage)
		os.Exit(1)
	}

	if placeholder = os.Getenv("FZZ_PLACEHOLDER"); placeholder == "" {
		placeholder = defaultPlaceholder
	}

	if !validPlaceholder(placeholder) {
		fmt.Fprintln(os.Stderr, "Placeholder is not valid, needs even number of characters")
		os.Exit(1)
	}

	if !containsPlaceholder(flag.Args(), placeholder) {
		fmt.Fprintln(os.Stderr, "No placeholder in arguments")
		os.Exit(1)
	}

	tty, err := NewTTY()
	if err != nil {
		log.Fatal(err)
	}
	defer tty.resetState()

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		<-c
		tty.resetState()
		os.Exit(1)
	}()
	tty.setSttyState("cbreak", "-echo")

	printer := NewPrinter(tty, tty.cols, tty.rows-1) // prompt is one row
	runner := &Runner{
		printer:     printer,
		template:    flag.Args(),
		placeholder: placeholder,
	}

	if isPipe(os.Stdin) {
		runner.stdinbuf = new(bytes.Buffer)
		io.Copy(runner.stdinbuf, os.Stdin)
	}

	input := make([]byte, 0)
	b := make([]byte, 1)

	for {
		tty.resetScreen()
		tty.printPrompt(input[:len(input)])

		if len(input) > 0 {
			runner.killCurrent()

			go func() {
				runner.runWithInput(input[:len(input)])
				tty.cursorAfterPrompt(utf8.RuneCount(input))
			}()
		}

		tty.Read(b)
		switch b[0] {
		case keyBackspace, keyDelete:
			if len(input) > 1 {
				input = input[:len(input)-1]
			} else if len(input) == 1 {
				input = nil
			}
		case keyEndOfTransmission, keyLineFeed, keyCarriageReturn:
			tty.resetScreen()
			runner.writeCmdStdout(os.Stdout)
			return
		case keyEndOfTransmissionBlock:
			input = removeLastWord(input)
		default:
			// TODO: Default is wrong here. Only append printable characters to
			// input
			input = append(input, b...)
		}
	}
}
<|endoftext|>


<commit_before>package privatemessage

import (
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/api/modules/helpers"

	"github.com/koding/bongo"
)

func Send(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	if req.AccountId == 0 {
		return helpers.NewBadRequestResponse(errors.New("AcccountId is not defined"))
	}

	if len(req.Recepients) == 0 {
		return helpers.NewBadRequestResponse(errors.New("You should define your Recepients"))
	}

	if req.GroupName == "" {
		req.GroupName = models.Channel_KODING_NAME
	}

	//// first create the channel
	c := models.NewPrivateMessageChannel(req.AccountId, req.GroupName)
	if err := c.Create(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	cm := models.NewChannelMessage()
	cm.Body = req.Body
	cm.TypeConstant = models.ChannelMessage_TYPE_PRIVATE_MESSAGE
	cm.AccountId = req.AccountId
	cm.InitialChannelId = c.Id
	if err := cm.Create(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	_, err := c.AddMessage(cm.Id)
	if err != nil {
		// todo this should be internal server error
		return helpers.NewBadRequestResponse(err)
	}

	// append creator to the recepients
	req.Recepients = append(req.Recepients, req.AccountId)
	for _, participantId := range req.Recepients {
		_, err := c.AddParticipant(participantId)
		if err != nil {
			return helpers.NewBadRequestResponse(err)
		}
	}

	cmc := models.NewChannelContainer()
	cmc.Channel = *c
	cmc.IsParticipant = true
	cmc.LastMessage = cm
	cmc.ParticipantCount = len(req.Recepients)
	cmc.ParticipantsPreview = req.Recepients

	return helpers.NewOKResponse(cmc)
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	q := helpers.GetQuery(u)

	channels, err := getPrivateMessageChannels(q)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	populatedChannels := models.PopulateChannelContainers(channels, q.AccountId)

	for i, populatedChannel := range populatedChannels {
		cp := models.NewChannelParticipant()
		cp.ChannelId = populatedChannel.Channel.Id

		// add participant preview
		cpList, err := cp.ListAccountIds(5)
		if err != nil {
			return helpers.NewBadRequestResponse(err)
		}
		populatedChannels[i].ParticipantsPreview = cpList

		// add last message of the channel
		cm, err := populatedChannel.Channel.FetchLastMessage()
		if err != nil {
			return helpers.NewBadRequestResponse(err)
		}
		populatedChannels[i].LastMessage = cm
	}

	return helpers.NewOKResponse(populatedChannels)

}

func getPrivateMessageChannels(q *models.Query) ([]models.Channel, error) {
	// build query for
	c := models.NewChannel()
	channelIds := make([]int64, 0)
	rows, err := bongo.B.DB.Table(c.TableName()).
		Select("api.channel_participant.channel_id").
		Joins("left join api.channel_participant on api.channel_participant.channel_id = api.channel.id").
		Where("api.channel_participant.account_id = ? and "+
		"api.channel.group_name = ? and "+
		"api.channel.type_constant = ? and "+
		"api.channel_participant.status_constant = ?",
		q.AccountId,
		q.GroupName,
		models.Channel_TYPE_PRIVATE_MESSAGE,
		models.ChannelParticipant_STATUS_ACTIVE).
		Limit(q.Limit).
		Offset(q.Skip).
		Rows()
	defer rows.Close()
	if err != nil {
		return nil, err
	}

	var channelId int64
	for rows.Next() {
		rows.Scan(&channelId)
		channelIds = append(channelIds, channelId)
	}

	channels, err := c.FetchByIds(channelIds)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<commit_msg>Socail: fix typo<commit_after>package privatemessage

import (
	"errors"
	"net/http"
	"net/url"
	"socialapi/models"
	"socialapi/workers/api/modules/helpers"

	"github.com/koding/bongo"
)

func Send(u *url.URL, h http.Header, req *models.PrivateMessageRequest) (int, http.Header, interface{}, error) {
	if req.AccountId == 0 {
		return helpers.NewBadRequestResponse(errors.New("AcccountId is not defined"))
	}

	if len(req.Recipients) == 0 {
		return helpers.NewBadRequestResponse(errors.New("You should define your recipients"))
	}

	if req.GroupName == "" {
		req.GroupName = models.Channel_KODING_NAME
	}

	//// first create the channel
	c := models.NewPrivateMessageChannel(req.AccountId, req.GroupName)
	if err := c.Create(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	cm := models.NewChannelMessage()
	cm.Body = req.Body
	cm.TypeConstant = models.ChannelMessage_TYPE_PRIVATE_MESSAGE
	cm.AccountId = req.AccountId
	cm.InitialChannelId = c.Id
	if err := cm.Create(); err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	_, err := c.AddMessage(cm.Id)
	if err != nil {
		// todo this should be internal server error
		return helpers.NewBadRequestResponse(err)
	}

	// append creator to the recipients
	req.Recipients = append(req.Recipients, req.AccountId)
	for _, participantId := range req.Recipients {
		_, err := c.AddParticipant(participantId)
		if err != nil {
			return helpers.NewBadRequestResponse(err)
		}
	}

	cmc := models.NewChannelContainer()
	cmc.Channel = *c
	cmc.IsParticipant = true
	cmc.LastMessage = cm
	cmc.ParticipantCount = len(req.Recipients)
	cmc.ParticipantsPreview = req.Recipients

	return helpers.NewOKResponse(cmc)
}

func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	q := helpers.GetQuery(u)

	channels, err := getPrivateMessageChannels(q)
	if err != nil {
		return helpers.NewBadRequestResponse(err)
	}

	populatedChannels := models.PopulateChannelContainers(channels, q.AccountId)

	for i, populatedChannel := range populatedChannels {
		cp := models.NewChannelParticipant()
		cp.ChannelId = populatedChannel.Channel.Id

		// add participant preview
		cpList, err := cp.ListAccountIds(5)
		if err != nil {
			return helpers.NewBadRequestResponse(err)
		}
		populatedChannels[i].ParticipantsPreview = cpList

		// add last message of the channel
		cm, err := populatedChannel.Channel.FetchLastMessage()
		if err != nil {
			return helpers.NewBadRequestResponse(err)
		}
		populatedChannels[i].LastMessage = cm
	}

	return helpers.NewOKResponse(populatedChannels)

}

func getPrivateMessageChannels(q *models.Query) ([]models.Channel, error) {
	// build query for
	c := models.NewChannel()
	channelIds := make([]int64, 0)
	rows, err := bongo.B.DB.Table(c.TableName()).
		Select("api.channel_participant.channel_id").
		Joins("left join api.channel_participant on api.channel_participant.channel_id = api.channel.id").
		Where("api.channel_participant.account_id = ? and "+
		"api.channel.group_name = ? and "+
		"api.channel.type_constant = ? and "+
		"api.channel_participant.status_constant = ?",
		q.AccountId,
		q.GroupName,
		models.Channel_TYPE_PRIVATE_MESSAGE,
		models.ChannelParticipant_STATUS_ACTIVE).
		Limit(q.Limit).
		Offset(q.Skip).
		Rows()
	defer rows.Close()
	if err != nil {
		return nil, err
	}

	var channelId int64
	for rows.Next() {
		rows.Scan(&channelId)
		channelIds = append(channelIds, channelId)
	}

	channels, err := c.FetchByIds(channelIds)
	if err != nil {
		return nil, err
	}

	return channels, nil
}
<|endoftext|>