<commit_before>package dnotifier

import (
	"log"

	"github.com/fsnotify/fsnotify"
)

// Watcher is watcher
type Watcher struct {
	Event <-chan EventItem
}

// EventItem has information of Event
type EventItem struct {
	Path string
	Diff string
}

// Watch is watch specified paths
func Watch(paths ...string) (*Watcher, error) {
	event := make(chan EventItem)
	err := watch(paths, event)
	if err != nil {
		return nil, err
	}

	return &Watcher{
		Event: event,
	}, nil
}

func watch(paths []string, event chan<- EventItem) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	for _, p := range paths {
		err = watcher.Add(p)
		if err != nil {
			return err
		}
		err = storeInCache(p)
		if err != nil {
			return err
		}
	}

	go func() {
		defer watcher.Close()
		for {
			select {
			case ev := <-watcher.Events:
				// write or rename event
				if ev.Op&fsnotify.Write > 0 || ev.Op&fsnotify.Rename > 0 {
					e, err := diff(ev.Name)
					if err != nil {
						log.Fatal(err)
					}
					event <- *e
				}
			case err := <-watcher.Errors:
				log.Println("error: ", err)
			}
		}
	}()
	return nil
}
<commit_msg>add error handle<commit_after>package dnotifier

import (
	"log"

	"github.com/fsnotify/fsnotify"
)

// Watcher is watcher
type Watcher struct {
	Event <-chan EventItem
}

// EventItem has information of Event
type EventItem struct {
	Path string
	Diff string
}

// Watch is watch specified paths
func Watch(paths ...string) (*Watcher, error) {
	event := make(chan EventItem)
	err := watch(paths, event)
	if err != nil {
		return nil, err
	}

	return &Watcher{
		Event: event,
	}, nil
}

func watch(paths []string, event chan<- EventItem) error {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return err
	}

	for _, p := range paths {
		err = watcher.Add(p)
		if err != nil {
			return err
		}
		err = storeInCache(p)
		if err != nil {
			return err
		}
	}

	go func() {
		defer watcher.Close()
		for {
			select {
			case ev := <-watcher.Events:
				// write or rename event
				if ev.Op&fsnotify.Write > 0 || ev.Op&fsnotify.Rename > 0 {
					e, err := diff(ev.Name)
					if err != nil {
						log.Fatal(err, ev)
					}
					event <- *e
				}
			case err := <-watcher.Errors:
				log.Fatal(err)
			}
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy

import (
    "fmt"
    "net"
    "os"
    "strconv"
    "syscall"
    "time"

    "sippy/conf"
    "sippy/log"
    "sippy/time"
    "sippy/utils"
)

type UdpPacketReceiver func(data []byte, addr *sippy_conf.HostPort, server *udpServer, rtime *sippy_time.MonoTime)

type write_req struct {
    address     net.Addr
    data        []byte
}

type resolv_req struct {
    hostport    string
    data        []byte
}

type asyncResolver struct {
    sem         chan int
    logger      sippy_log.ErrorLogger
}

func NewAsyncResolver(userv *udpServer, logger sippy_log.ErrorLogger) *asyncResolver {
    self := &asyncResolver{
        sem     : make(chan int, 2),
        logger  : logger,
    }
    go self.run(userv)
    return self
}

func (self *asyncResolver) run(userv *udpServer) {
    var wi *resolv_req
LOOP:
    for {
        wi = <-userv.wi_resolv
        if wi == nil {
            // Shutdown request, relay it further
            userv.wi_resolv <- nil
            break LOOP
        }
        start, _ := sippy_time.NewMonoTime()
        addr, err := net.ResolveUDPAddr("udp", wi.hostport)
        delay, _ := start.OffsetFromNow()
        if err != nil {
            self.logger.Error(fmt.Sprintf("Udp_server: Cannot resolve '%s', dropping outgoing SIP message. Delay %s", wi.hostport, delay.String()))
            continue
        }
        if delay > time.Duration(.5 * float64(time.Second)) {
            self.logger.Error("Udp_server: DNS resolve time for '%s' is too big: %s", wi.hostport, delay.String())
        }
        userv._send_to(wi.data, addr)
    }
    self.sem <- 1
}

type asyncSender struct {
    sem     chan int
}

func NewAsyncSender(userv *udpServer) *asyncSender {
    self := &asyncSender{
        sem     : make(chan int, 2),
    }
    go self.run(userv)
    return self
}

func (self *asyncSender) run(userv *udpServer) {
    var wi *write_req
LOOP:
    for {
        wi = <-userv.wi
        if wi == nil { // shutdown req
            userv.wi <- nil
            break LOOP
        }
SEND_LOOP:
        for wi != nil {
            for i := 0; i < 20; i++ {
                if _, err := userv.skt.WriteTo(wi.data, wi.address); err == nil {
                    break SEND_LOOP
                }
            }
            time.Sleep(time.Duration(0.01 * float64(time.Second)))
        }
    }
    self.sem <- 1
}

type asyncReceiver struct {
    sem             chan int
    logger          sippy_log.ErrorLogger
}

func NewAsyncReciever(userv *udpServer, logger sippy_log.ErrorLogger) *asyncReceiver {
    self := &asyncReceiver{
        sem     : make(chan int, 2),
        logger  : logger,
    }
    go self.run(userv)
    return self
}

func (self *asyncReceiver) run(userv *udpServer) {
    buf := make([]byte, 8192)
    for {
        n, address, err := userv.skt.ReadFrom(buf)
        if err != nil {
            break
        }
        rtime, err := sippy_time.NewMonoTime()
        if err != nil {
            self.logger.Error("Cannot create MonoTime object")
            continue
        }
        sippy_utils.SafeCall(func() { userv.handle_read(buf[:n], address, rtime) }, nil, self.logger)
    }
    self.sem <- 1
}

type udpServerOpts struct {
    laddress        *sippy_conf.HostPort
    data_callback   UdpPacketReceiver
    shut_down       bool
    nworkers        int
}

func NewUdpServerOpts(laddress *sippy_conf.HostPort, data_callback UdpPacketReceiver) *udpServerOpts {
    self := &udpServerOpts{
        laddress        : laddress,
        data_callback   : data_callback,
        nworkers        : 10,
        shut_down       : false,
    }
    return self
}

type udpServer struct {
    uopts           udpServerOpts
    //skt             *net.UDPConn
    skt             net.PacketConn
    wi              chan *write_req
    wi_resolv       chan *resolv_req
    asenders        []*asyncSender
    areceivers      []*asyncReceiver
    aresolvers      []*asyncResolver
    packets_recvd int
    packets_sent int
    packets_queued int
}

func zoneToUint32(zone string) uint32 {
    if zone == "" {
        return 0
    }
    if ifi, err := net.InterfaceByName(zone); err == nil {
        return uint32(ifi.Index)
    }
    n, err := strconv.Atoi(zone)
    if err != nil {
        return 0
    }
    return uint32(n)
}

func NewUdpServer(config sippy_conf.Config, uopts *udpServerOpts) (*udpServer, error) {
    var laddress *net.UDPAddr
    var err error

    if uopts.laddress != nil {
        laddress, err = net.ResolveUDPAddr("udp", uopts.laddress.String())
    } else {
        laddress, err = net.ResolveUDPAddr("udp", "127.0.0.1:0")
    }
    if err != nil { return nil, err }
    s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
    if err != nil { return nil, err }
    for _, opt := range []int{ syscall.SO_REUSEPORT, syscall.SO_REUSEADDR } {
        if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, opt, 1); err != nil {
            syscall.Close(s)
            return nil, err
        }
    }
    ip4 := laddress.IP.To4()
    var sockaddr syscall.Sockaddr
    if ip4 != nil {
        sockaddr = &syscall.SockaddrInet4{
            Port : laddress.Port,
            Addr : [4]byte{ ip4[0], ip4[1], ip4[2], ip4[3] },
        }
    } else {
        sa6 := &syscall.SockaddrInet6{
            Port : laddress.Port,
            ZoneId : zoneToUint32(laddress.Zone),
        }
        for i := 0; i < 16; i++ {
            sa6.Addr[i] = laddress.IP[i]
        }
        sockaddr = sa6
    }
    if err := syscall.Bind(s, sockaddr); err != nil {
        syscall.Close(s)
        return nil, err
    }
    f := os.NewFile(uintptr(s), "")
    skt, err := net.FilePacketConn(f)
    f.Close()
    if err != nil {
        return nil, err
    }
    /*
    skt, err := net.ListenUDP("udp", laddress)
    if err != nil { return nil, err }
    */
    self := &udpServer{
        uopts       : *uopts,
        skt         : skt,
        wi          : make(chan *write_req, 1000),
        wi_resolv   : make(chan *resolv_req, 1000),
        asenders    : make([]*asyncSender, 0, uopts.nworkers),
        areceivers  : make([]*asyncReceiver, 0, uopts.nworkers),
        aresolvers  : make([]*asyncResolver, 0, uopts.nworkers),
    }
    for n := 0; n < uopts.nworkers; n++ {
        self.asenders = append(self.asenders, NewAsyncSender(self))
        self.areceivers = append(self.areceivers, NewAsyncReciever(self, config.ErrorLogger()))
    }
    for n:= 0; n < uopts.nworkers; n++ {
        self.aresolvers = append(self.aresolvers, NewAsyncResolver(self, config.ErrorLogger()))
    }
    return self, nil
}

func (self *udpServer) SendTo(data []byte, host, port string) {
    hostport := net.JoinHostPort(host, port)
    ip := net.ParseIP(host)
    if ip == nil {
        self.wi_resolv <- &resolv_req{ data : data, hostport : hostport }
        return
    }
    address, err := net.ResolveUDPAddr("udp", hostport) // in fact no resolving is done here
    if err != nil {
        return // not reached
    }
    self._send_to(data, address)
}

func (self *udpServer) _send_to(data []byte, address net.Addr) {
    self.wi <- &write_req{ data : data, address : address }
}

func (self *udpServer) handle_read(data []byte, address net.Addr, rtime *sippy_time.MonoTime) {
    if len(data) > 0 {
        self.packets_recvd++
        host, port, _ := net.SplitHostPort(address.String())
        self.uopts.data_callback(data, sippy_conf.NewHostPort(host, port), self, rtime)
    }
}

func (self *udpServer) Shutdown() {
    // shutdown the senders and resolvers first
    self.wi <- nil
    self.wi_resolv <- nil
    for _, worker := range self.asenders { <-worker.sem }
    for _, worker := range self.aresolvers { <-worker.sem }
    self.skt.Close()

    self.uopts.shut_down = true // self.uopts.data_callback = None
    for _, worker := range self.areceivers { <-worker.sem }
    self.asenders = make([]*asyncSender, 0)
    self.areceivers = make([]*asyncReceiver, 0)
    self.aresolvers = make([]*asyncResolver, 0)
}

func (self *udpServer) GetLaddress() *sippy_conf.HostPort {
    return self.uopts.laddress
}
<commit_msg>Autoconfigure the number of workers.<commit_after>// Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
// Copyright (c) 2006-2015 Sippy Software, Inc. All rights reserved.
// Copyright (c) 2015 Andrii Pylypenko. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package sippy

import (
    "fmt"
    "net"
    "os"
    "runtime"
    "strconv"
    "syscall"
    "time"

    "sippy/conf"
    "sippy/log"
    "sippy/time"
    "sippy/utils"
)

type UdpPacketReceiver func(data []byte, addr *sippy_conf.HostPort, server *udpServer, rtime *sippy_time.MonoTime)

type write_req struct {
    address     net.Addr
    data        []byte
}

type resolv_req struct {
    hostport    string
    data        []byte
}

type asyncResolver struct {
    sem         chan int
    logger      sippy_log.ErrorLogger
}

func NewAsyncResolver(userv *udpServer, logger sippy_log.ErrorLogger) *asyncResolver {
    self := &asyncResolver{
        sem     : make(chan int, 2),
        logger  : logger,
    }
    go self.run(userv)
    return self
}

func (self *asyncResolver) run(userv *udpServer) {
    var wi *resolv_req
LOOP:
    for {
        wi = <-userv.wi_resolv
        if wi == nil {
            // Shutdown request, relay it further
            userv.wi_resolv <- nil
            break LOOP
        }
        start, _ := sippy_time.NewMonoTime()
        addr, err := net.ResolveUDPAddr("udp", wi.hostport)
        delay, _ := start.OffsetFromNow()
        if err != nil {
            self.logger.Error(fmt.Sprintf("Udp_server: Cannot resolve '%s', dropping outgoing SIP message. Delay %s", wi.hostport, delay.String()))
            continue
        }
        if delay > time.Duration(.5 * float64(time.Second)) {
            self.logger.Error("Udp_server: DNS resolve time for '%s' is too big: %s", wi.hostport, delay.String())
        }
        userv._send_to(wi.data, addr)
    }
    self.sem <- 1
}

type asyncSender struct {
    sem     chan int
}

func NewAsyncSender(userv *udpServer) *asyncSender {
    self := &asyncSender{
        sem     : make(chan int, 2),
    }
    go self.run(userv)
    return self
}

func (self *asyncSender) run(userv *udpServer) {
    var wi *write_req
LOOP:
    for {
        wi = <-userv.wi
        if wi == nil { // shutdown req
            userv.wi <- nil
            break LOOP
        }
SEND_LOOP:
        for wi != nil {
            for i := 0; i < 20; i++ {
                if _, err := userv.skt.WriteTo(wi.data, wi.address); err == nil {
                    break SEND_LOOP
                }
            }
            time.Sleep(time.Duration(0.01 * float64(time.Second)))
        }
    }
    self.sem <- 1
}

type asyncReceiver struct {
    sem             chan int
    logger          sippy_log.ErrorLogger
}

func NewAsyncReciever(userv *udpServer, logger sippy_log.ErrorLogger) *asyncReceiver {
    self := &asyncReceiver{
        sem     : make(chan int, 2),
        logger  : logger,
    }
    go self.run(userv)
    return self
}

func (self *asyncReceiver) run(userv *udpServer) {
    buf := make([]byte, 8192)
    for {
        n, address, err := userv.skt.ReadFrom(buf)
        if err != nil {
            break
        }
        rtime, err := sippy_time.NewMonoTime()
        if err != nil {
            self.logger.Error("Cannot create MonoTime object")
            continue
        }
        sippy_utils.SafeCall(func() { userv.handle_read(buf[:n], address, rtime) }, nil, self.logger)
    }
    self.sem <- 1
}

type udpServerOpts struct {
    laddress        *sippy_conf.HostPort
    data_callback   UdpPacketReceiver
    shut_down       bool
    nworkers        int
}

func NewUdpServerOpts(laddress *sippy_conf.HostPort, data_callback UdpPacketReceiver) *udpServerOpts {
    self := &udpServerOpts{
        laddress        : laddress,
        data_callback   : data_callback,
        nworkers        : runtime.NumCPU() * 2,
        shut_down       : false,
    }
    return self
}

type udpServer struct {
    uopts           udpServerOpts
    //skt             *net.UDPConn
    skt             net.PacketConn
    wi              chan *write_req
    wi_resolv       chan *resolv_req
    asenders        []*asyncSender
    areceivers      []*asyncReceiver
    aresolvers      []*asyncResolver
    packets_recvd int
    packets_sent int
    packets_queued int
}

func zoneToUint32(zone string) uint32 {
    if zone == "" {
        return 0
    }
    if ifi, err := net.InterfaceByName(zone); err == nil {
        return uint32(ifi.Index)
    }
    n, err := strconv.Atoi(zone)
    if err != nil {
        return 0
    }
    return uint32(n)
}

func NewUdpServer(config sippy_conf.Config, uopts *udpServerOpts) (*udpServer, error) {
    var laddress *net.UDPAddr
    var err error

    if uopts.laddress != nil {
        laddress, err = net.ResolveUDPAddr("udp", uopts.laddress.String())
    } else {
        laddress, err = net.ResolveUDPAddr("udp", "127.0.0.1:0")
    }
    if err != nil { return nil, err }
    s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, 0)
    if err != nil { return nil, err }
    for _, opt := range []int{ syscall.SO_REUSEPORT, syscall.SO_REUSEADDR } {
        if err := syscall.SetsockoptInt(s, syscall.SOL_SOCKET, opt, 1); err != nil {
            syscall.Close(s)
            return nil, err
        }
    }
    ip4 := laddress.IP.To4()
    var sockaddr syscall.Sockaddr
    if ip4 != nil {
        sockaddr = &syscall.SockaddrInet4{
            Port : laddress.Port,
            Addr : [4]byte{ ip4[0], ip4[1], ip4[2], ip4[3] },
        }
    } else {
        sa6 := &syscall.SockaddrInet6{
            Port : laddress.Port,
            ZoneId : zoneToUint32(laddress.Zone),
        }
        for i := 0; i < 16; i++ {
            sa6.Addr[i] = laddress.IP[i]
        }
        sockaddr = sa6
    }
    if err := syscall.Bind(s, sockaddr); err != nil {
        syscall.Close(s)
        return nil, err
    }
    f := os.NewFile(uintptr(s), "")
    skt, err := net.FilePacketConn(f)
    f.Close()
    if err != nil {
        return nil, err
    }
    /*
    skt, err := net.ListenUDP("udp", laddress)
    if err != nil { return nil, err }
    */
    self := &udpServer{
        uopts       : *uopts,
        skt         : skt,
        wi          : make(chan *write_req, 1000),
        wi_resolv   : make(chan *resolv_req, 1000),
        asenders    : make([]*asyncSender, 0, uopts.nworkers),
        areceivers  : make([]*asyncReceiver, 0, uopts.nworkers),
        aresolvers  : make([]*asyncResolver, 0, uopts.nworkers),
    }
    for n := 0; n < uopts.nworkers; n++ {
        self.asenders = append(self.asenders, NewAsyncSender(self))
        self.areceivers = append(self.areceivers, NewAsyncReciever(self, config.ErrorLogger()))
    }
    for n:= 0; n < uopts.nworkers; n++ {
        self.aresolvers = append(self.aresolvers, NewAsyncResolver(self, config.ErrorLogger()))
    }
    return self, nil
}

func (self *udpServer) SendTo(data []byte, host, port string) {
    hostport := net.JoinHostPort(host, port)
    ip := net.ParseIP(host)
    if ip == nil {
        self.wi_resolv <- &resolv_req{ data : data, hostport : hostport }
        return
    }
    address, err := net.ResolveUDPAddr("udp", hostport) // in fact no resolving is done here
    if err != nil {
        return // not reached
    }
    self._send_to(data, address)
}

func (self *udpServer) _send_to(data []byte, address net.Addr) {
    self.wi <- &write_req{ data : data, address : address }
}

func (self *udpServer) handle_read(data []byte, address net.Addr, rtime *sippy_time.MonoTime) {
    if len(data) > 0 {
        self.packets_recvd++
        host, port, _ := net.SplitHostPort(address.String())
        self.uopts.data_callback(data, sippy_conf.NewHostPort(host, port), self, rtime)
    }
}

func (self *udpServer) Shutdown() {
    // shutdown the senders and resolvers first
    self.wi <- nil
    self.wi_resolv <- nil
    for _, worker := range self.asenders { <-worker.sem }
    for _, worker := range self.aresolvers { <-worker.sem }
    self.skt.Close()

    self.uopts.shut_down = true // self.uopts.data_callback = None
    for _, worker := range self.areceivers { <-worker.sem }
    self.asenders = make([]*asyncSender, 0)
    self.areceivers = make([]*asyncReceiver, 0)
    self.aresolvers = make([]*asyncResolver, 0)
}

func (self *udpServer) GetLaddress() *sippy_conf.HostPort {
    return self.uopts.laddress
}
<|endoftext|>


<commit_before>package appId

import (
	"crypto/sha1"
	"crypto/subtle"
	"encoding/hex"
	"fmt"
	"net"
	"reflect"
	"sort"
	"strings"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

func pathLogin(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "login",
		Fields: map[string]*framework.FieldSchema{
			"app_id": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "The unique app ID",
			},

			"user_id": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "The unique user ID",
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathLogin,
		},

		HelpSynopsis:    pathLoginSyn,
		HelpDescription: pathLoginDesc,
	}
}

func (b *backend) pathLogin(
	req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	appId := data.Get("app_id").(string)
	userId := data.Get("user_id").(string)

	var displayName string
	if dispName, resp, err := b.verifyCredentials(req, appId, userId, true); err != nil {
		return nil, err
	} else if resp != nil {
		return resp, nil
	} else {
		displayName = dispName
	}

	// Get the policies associated with the app
	policies, err := b.MapAppId.Policies(req.Storage, appId)
	if err != nil {
		return nil, err
	}

	// Store hashes of the app ID and user ID for the metadata
	appIdHash := sha1.Sum([]byte(appId))
	userIdHash := sha1.Sum([]byte(userId))
	metadata := map[string]string{
		"app-id":  "sha1:" + hex.EncodeToString(appIdHash[:]),
		"user-id": "sha1:" + hex.EncodeToString(userIdHash[:]),
	}

	return &logical.Response{
		Auth: &logical.Auth{
			InternalData: map[string]interface{}{
				"app-id":  appId,
				"user-id": userId,
			},
			DisplayName: displayName,
			Policies:    policies,
			Metadata:    metadata,
			LeaseOptions: logical.LeaseOptions{
				Renewable: true,
			},
		},
	}, nil
}

func (b *backend) pathLoginRenew(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	appId := req.Auth.InternalData["app-id"].(string)
	userId := req.Auth.InternalData["user-id"].(string)

	// Skipping CIDR verification to enable renewal from machines other than
	// the ones encompassed by CIDR block.
	if _, resp, err := b.verifyCredentials(req, appId, userId, false); err != nil {
		return nil, err
	} else if resp != nil {
		return resp, nil
	}

	// Get the policies associated with the app
	policies, err := b.MapAppId.Policies(req.Storage, appId)
	if err != nil {
		return nil, err
	}
	sort.Strings(req.Auth.Policies)
	if !reflect.DeepEqual(policies, req.Auth.Policies) {
		return logical.ErrorResponse("policies do not match"), nil
	}

	return framework.LeaseExtend(0, 0, b.System())(req, d)
}

func (b *backend) verifyCredentials(req *logical.Request, appId, userId string, verifyCIDR bool) (string, *logical.Response, error) {
	// Ensure both appId and userId are provided
	if appId == "" || userId == "" {
		return "", logical.ErrorResponse("missing 'app_id' or 'user_id'"), nil
	}

	// Look up the apps that this user is allowed to access
	appsMap, err := b.MapUserId.Get(req.Storage, userId)
	if err != nil {
		return "", nil, err
	}
	if appsMap == nil {
		return "", logical.ErrorResponse("invalid user ID or app ID"), nil
	}

	// If there is a CIDR block restriction, check that
	if raw, ok := appsMap["cidr_block"]; ok && verifyCIDR {
		_, cidr, err := net.ParseCIDR(raw.(string))
		if err != nil {
			return "", nil, fmt.Errorf("invalid restriction cidr: %s", err)
		}

		var addr string
		if req.Connection != nil {
			addr = req.Connection.RemoteAddr
		}
		if addr == "" || !cidr.Contains(net.ParseIP(addr)) {
			return "", logical.ErrorResponse("unauthorized source address"), nil
		}
	}

	appsRaw, ok := appsMap["value"]
	if !ok {
		appsRaw = ""
	}

	apps, ok := appsRaw.(string)
	if !ok {
		return "", nil, fmt.Errorf("internal error: mapping is not a string")
	}

	// Verify that the app is in the list
	found := false
	appIdBytes := []byte(appId)
	for _, app := range strings.Split(apps, ",") {
		match := []byte(strings.TrimSpace(app))
		// Protect against a timing attack with the app_id comparison
		if subtle.ConstantTimeCompare(match, appIdBytes) == 1 {
			found = true
		}
	}
	if !found {
		return "", logical.ErrorResponse("invalid user ID or app ID"), nil
	}

	// Get the raw data associated with the app
	appRaw, err := b.MapAppId.Get(req.Storage, appId)
	if err != nil {
		return "", nil, err
	}
	if appRaw == nil {
		return "", logical.ErrorResponse("invalid user ID or app ID"), nil
	}
	var displayName string
	if raw, ok := appRaw["display_name"]; ok {
		displayName = raw.(string)
	}

	return displayName, nil, nil
}

const pathLoginSyn = `
Log in with an App ID and User ID.
`

const pathLoginDesc = `
This endpoint authenticates using an application ID, user ID and potential the IP address of the connecting client.
`
<commit_msg>check CIDR block for renewal as well<commit_after>package appId

import (
	"crypto/sha1"
	"crypto/subtle"
	"encoding/hex"
	"fmt"
	"net"
	"reflect"
	"sort"
	"strings"

	"github.com/hashicorp/vault/logical"
	"github.com/hashicorp/vault/logical/framework"
)

func pathLogin(b *backend) *framework.Path {
	return &framework.Path{
		Pattern: "login",
		Fields: map[string]*framework.FieldSchema{
			"app_id": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "The unique app ID",
			},

			"user_id": &framework.FieldSchema{
				Type:        framework.TypeString,
				Description: "The unique user ID",
			},
		},

		Callbacks: map[logical.Operation]framework.OperationFunc{
			logical.UpdateOperation: b.pathLogin,
		},

		HelpSynopsis:    pathLoginSyn,
		HelpDescription: pathLoginDesc,
	}
}

func (b *backend) pathLogin(
	req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
	appId := data.Get("app_id").(string)
	userId := data.Get("user_id").(string)

	var displayName string
	if dispName, resp, err := b.verifyCredentials(req, appId, userId); err != nil {
		return nil, err
	} else if resp != nil {
		return resp, nil
	} else {
		displayName = dispName
	}

	// Get the policies associated with the app
	policies, err := b.MapAppId.Policies(req.Storage, appId)
	if err != nil {
		return nil, err
	}

	// Store hashes of the app ID and user ID for the metadata
	appIdHash := sha1.Sum([]byte(appId))
	userIdHash := sha1.Sum([]byte(userId))
	metadata := map[string]string{
		"app-id":  "sha1:" + hex.EncodeToString(appIdHash[:]),
		"user-id": "sha1:" + hex.EncodeToString(userIdHash[:]),
	}

	return &logical.Response{
		Auth: &logical.Auth{
			InternalData: map[string]interface{}{
				"app-id":  appId,
				"user-id": userId,
			},
			DisplayName: displayName,
			Policies:    policies,
			Metadata:    metadata,
			LeaseOptions: logical.LeaseOptions{
				Renewable: true,
			},
		},
	}, nil
}

func (b *backend) pathLoginRenew(
	req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
	appId := req.Auth.InternalData["app-id"].(string)
	userId := req.Auth.InternalData["user-id"].(string)

	// Skipping CIDR verification to enable renewal from machines other than
	// the ones encompassed by CIDR block.
	if _, resp, err := b.verifyCredentials(req, appId, userId); err != nil {
		return nil, err
	} else if resp != nil {
		return resp, nil
	}

	// Get the policies associated with the app
	policies, err := b.MapAppId.Policies(req.Storage, appId)
	if err != nil {
		return nil, err
	}
	sort.Strings(req.Auth.Policies)
	if !reflect.DeepEqual(policies, req.Auth.Policies) {
		return logical.ErrorResponse("policies do not match"), nil
	}

	return framework.LeaseExtend(0, 0, b.System())(req, d)
}

func (b *backend) verifyCredentials(req *logical.Request, appId, userId string) (string, *logical.Response, error) {
	// Ensure both appId and userId are provided
	if appId == "" || userId == "" {
		return "", logical.ErrorResponse("missing 'app_id' or 'user_id'"), nil
	}

	// Look up the apps that this user is allowed to access
	appsMap, err := b.MapUserId.Get(req.Storage, userId)
	if err != nil {
		return "", nil, err
	}
	if appsMap == nil {
		return "", logical.ErrorResponse("invalid user ID or app ID"), nil
	}

	// If there is a CIDR block restriction, check that
	if raw, ok := appsMap["cidr_block"]; ok {
		_, cidr, err := net.ParseCIDR(raw.(string))
		if err != nil {
			return "", nil, fmt.Errorf("invalid restriction cidr: %s", err)
		}

		var addr string
		if req.Connection != nil {
			addr = req.Connection.RemoteAddr
		}
		if addr == "" || !cidr.Contains(net.ParseIP(addr)) {
			return "", logical.ErrorResponse("unauthorized source address"), nil
		}
	}

	appsRaw, ok := appsMap["value"]
	if !ok {
		appsRaw = ""
	}

	apps, ok := appsRaw.(string)
	if !ok {
		return "", nil, fmt.Errorf("internal error: mapping is not a string")
	}

	// Verify that the app is in the list
	found := false
	appIdBytes := []byte(appId)
	for _, app := range strings.Split(apps, ",") {
		match := []byte(strings.TrimSpace(app))
		// Protect against a timing attack with the app_id comparison
		if subtle.ConstantTimeCompare(match, appIdBytes) == 1 {
			found = true
		}
	}
	if !found {
		return "", logical.ErrorResponse("invalid user ID or app ID"), nil
	}

	// Get the raw data associated with the app
	appRaw, err := b.MapAppId.Get(req.Storage, appId)
	if err != nil {
		return "", nil, err
	}
	if appRaw == nil {
		return "", logical.ErrorResponse("invalid user ID or app ID"), nil
	}
	var displayName string
	if raw, ok := appRaw["display_name"]; ok {
		displayName = raw.(string)
	}

	return displayName, nil, nil
}

const pathLoginSyn = `
Log in with an App ID and User ID.
`

const pathLoginDesc = `
This endpoint authenticates using an application ID, user ID and potential the IP address of the connecting client.
`
<|endoftext|>


<commit_before>package kitsu

import (
	"fmt"
)

// The possible library entry statuses. They are convenient when creating a
// LibraryEntry or for making comparisons with LibraryEntry.Status.
const (
	LibraryEntryStatusCurrent   = "current"
	LibraryEntryStatusPlanned   = "planned"
	LibraryEntryStatusCompleted = "completed"
	LibraryEntryStatusOnHold    = "on_hold"
	LibraryEntryStatusDropped   = "dropped"
)

// LibraryService handles communication with the library entry related methods
// of the Kitsu API.
type LibraryService service

// LibraryEntry represents a Kitsu user's library entry.
type LibraryEntry struct {
	ID             string `jsonapi:"primary,libraryEntries"`
	Status         string `jsonapi:"attr,status,omitempty"`         // Status for related media. Can be compared with LibraryEntryStatus constants.
	Progress       int    `jsonapi:"attr,progress,omitempty"`       // How many episodes/chapters have been consumed, e.g. 22.
	Reconsuming    bool   `jsonapi:"attr,reconsuming,omitempty"`    // Whether the media is being reconsumed, e.g. false.
	ReconsumeCount int    `jsonapi:"attr,reconsumeCount,omitempty"` // How many times the media has been reconsumed, e.g. 0.
	Notes          string `jsonapi:"attr,notes,omitempty"`          // Note attached to this entry, e.g. Very Interesting!
	Private        bool   `jsonapi:"attr,private,omitempty"`        // Whether this entry is hidden from the public, e.g. false.
	Rating         string `jsonapi:"attr,rating,omitempty"`         // User rating out of 5.0.
	UpdatedAt      string `jsonapi:"attr,updatedAt,omitempty"`      // When the entry was last updated, e.g. 2016-11-12T03:35:00.064Z.

	// Relationships.

	User  *User       `jsonapi:"relation,user,omitempty"`
	Anime *Anime      `jsonapi:"relation,anime,omitempty"`
	Media interface{} `jsonapi:"relation,media,omitempty"`
}

// Show returns details for a specific LibraryEntry by providing a unique identifier
// of the library entry, e.g. 5269457.
func (s *LibraryService) Show(libraryEntryID string, opts ...URLOption) (*LibraryEntry, *Response, error) {
	u := fmt.Sprintf(defaultAPIVersion+"library-entries/%s", libraryEntryID)

	req, err := s.client.NewRequest("GET", u, nil, opts...)
	if err != nil {
		return nil, nil, err
	}

	e := new(LibraryEntry)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, nil
}

// List returns a list of Library entries. Optional parameters can be specified
// to filter the search results and control pagination, sorting etc.
func (s *LibraryService) List(opts ...URLOption) ([]*LibraryEntry, *Response, error) {
	u := defaultAPIVersion + "library-entries"

	req, err := s.client.NewRequest("GET", u, nil, opts...)
	if err != nil {
		return nil, nil, err
	}

	var entries []*LibraryEntry
	resp, err := s.client.Do(req, &entries)
	if err != nil {
		return nil, resp, err
	}

	return entries, resp, nil
}

// Create creates a library entry. This method needs authentication.
func (s *LibraryService) Create(e *LibraryEntry, opts ...URLOption) (*LibraryEntry, *Response, error) {
	u := defaultAPIVersion + "library-entries"

	req, err := s.client.NewRequest("POST", u, e, opts...)
	if err != nil {
		return nil, nil, err
	}

	var entry = new(LibraryEntry)
	resp, err := s.client.Do(req, entry)
	if err != nil {
		return nil, resp, err
	}

	return entry, resp, nil
}

// Delete deletes a library entry. This method needs authentication.
func (s *LibraryService) Delete(id string, opts ...URLOption) (*Response, error) {
	u := defaultAPIVersion + "library-entries/" + id

	req, err := s.client.NewRequest("DELETE", u, nil, opts...)
	if err != nil {
		return nil, err
	}

	resp, err := s.client.Do(req, nil)
	if err != nil {
		return resp, err
	}

	return resp, nil
}
<commit_msg>Simplify library delete<commit_after>package kitsu

import (
	"fmt"
)

// The possible library entry statuses. They are convenient when creating a
// LibraryEntry or for making comparisons with LibraryEntry.Status.
const (
	LibraryEntryStatusCurrent   = "current"
	LibraryEntryStatusPlanned   = "planned"
	LibraryEntryStatusCompleted = "completed"
	LibraryEntryStatusOnHold    = "on_hold"
	LibraryEntryStatusDropped   = "dropped"
)

// LibraryService handles communication with the library entry related methods
// of the Kitsu API.
type LibraryService service

// LibraryEntry represents a Kitsu user's library entry.
type LibraryEntry struct {
	ID             string `jsonapi:"primary,libraryEntries"`
	Status         string `jsonapi:"attr,status,omitempty"`         // Status for related media. Can be compared with LibraryEntryStatus constants.
	Progress       int    `jsonapi:"attr,progress,omitempty"`       // How many episodes/chapters have been consumed, e.g. 22.
	Reconsuming    bool   `jsonapi:"attr,reconsuming,omitempty"`    // Whether the media is being reconsumed, e.g. false.
	ReconsumeCount int    `jsonapi:"attr,reconsumeCount,omitempty"` // How many times the media has been reconsumed, e.g. 0.
	Notes          string `jsonapi:"attr,notes,omitempty"`          // Note attached to this entry, e.g. Very Interesting!
	Private        bool   `jsonapi:"attr,private,omitempty"`        // Whether this entry is hidden from the public, e.g. false.
	Rating         string `jsonapi:"attr,rating,omitempty"`         // User rating out of 5.0.
	UpdatedAt      string `jsonapi:"attr,updatedAt,omitempty"`      // When the entry was last updated, e.g. 2016-11-12T03:35:00.064Z.

	// Relationships.

	User  *User       `jsonapi:"relation,user,omitempty"`
	Anime *Anime      `jsonapi:"relation,anime,omitempty"`
	Media interface{} `jsonapi:"relation,media,omitempty"`
}

// Show returns details for a specific LibraryEntry by providing a unique identifier
// of the library entry, e.g. 5269457.
func (s *LibraryService) Show(libraryEntryID string, opts ...URLOption) (*LibraryEntry, *Response, error) {
	u := fmt.Sprintf(defaultAPIVersion+"library-entries/%s", libraryEntryID)

	req, err := s.client.NewRequest("GET", u, nil, opts...)
	if err != nil {
		return nil, nil, err
	}

	e := new(LibraryEntry)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, nil
}

// List returns a list of Library entries. Optional parameters can be specified
// to filter the search results and control pagination, sorting etc.
func (s *LibraryService) List(opts ...URLOption) ([]*LibraryEntry, *Response, error) {
	u := defaultAPIVersion + "library-entries"

	req, err := s.client.NewRequest("GET", u, nil, opts...)
	if err != nil {
		return nil, nil, err
	}

	var entries []*LibraryEntry
	resp, err := s.client.Do(req, &entries)
	if err != nil {
		return nil, resp, err
	}

	return entries, resp, nil
}

// Create creates a library entry. This method needs authentication.
func (s *LibraryService) Create(e *LibraryEntry, opts ...URLOption) (*LibraryEntry, *Response, error) {
	u := defaultAPIVersion + "library-entries"

	req, err := s.client.NewRequest("POST", u, e, opts...)
	if err != nil {
		return nil, nil, err
	}

	var entry = new(LibraryEntry)
	resp, err := s.client.Do(req, entry)
	if err != nil {
		return nil, resp, err
	}

	return entry, resp, nil
}

// Delete deletes a library entry. This method needs authentication.
func (s *LibraryService) Delete(id string, opts ...URLOption) (*Response, error) {
	u := defaultAPIVersion + "library-entries/" + id

	req, err := s.client.NewRequest("DELETE", u, nil, opts...)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package push

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"
	"time"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const (
	CFEventuallyTimeout   = 300 * time.Second
	CFConsistentlyTimeout = 500 * time.Millisecond
	RealIsolationSegment  = "persistent_isolation_segment"
	PushCommandName       = "push"
	PublicDockerImage     = "cloudfoundry/diego-docker-app-custom"
)

var (
	// Suite Level
	organization string
	space        string
	realDir      string

	// Per Test Level
	homeDir string
)

func TestPush(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Push Integration Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
	GinkgoWriter.Write([]byte("==============================Global FIRST Node Synchronized Before Each=============================="))
	SetDefaultEventuallyTimeout(CFEventuallyTimeout)
	SetDefaultConsistentlyDuration(CFConsistentlyTimeout)

	helpers.SetupSynchronizedSuite(func() {
		helpers.EnableFeatureFlag("diego_docker")
		helpers.EnableFeatureFlag("service_instance_sharing")
	})

	GinkgoWriter.Write([]byte("==============================End of Global FIRST Node Synchronized Before Each=============================="))

	return nil
}, func(_ []byte) {
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================Global Node %d Synchronized Before Each==============================", GinkgoParallelNode())))
	// Ginkgo Globals
	SetDefaultEventuallyTimeout(CFEventuallyTimeout)
	SetDefaultConsistentlyDuration(CFConsistentlyTimeout)

	// Setup common environment variables
	helpers.TurnOffColors()

	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
	helpers.LoginCF()

	organization = helpers.NewOrgName()
	helpers.CreateOrg(organization)
	helpers.TargetOrg(organization)
	helpers.CreateSpace("empty-space")
	helpers.DestroyHomeDir(homeDir)

	var err error
	realDir, err = ioutil.TempDir("", "push-real-dir")
	Expect(err).ToNot(HaveOccurred())
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================End of Global Node %d Synchronized Before Each==============================", GinkgoParallelNode())))
})

var _ = SynchronizedAfterSuite(func() {
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================Global Node %d Synchronized After Each==============================", GinkgoParallelNode())))
	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
	helpers.LoginCF()
	helpers.QuickDeleteOrg(organization)
	Expect(os.RemoveAll(realDir)).ToNot(HaveOccurred())
	helpers.DestroyHomeDir(homeDir)
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================End of Global Node %d Synchronized After Each==============================", GinkgoParallelNode())))
}, func() {})

var _ = BeforeEach(func() {
	GinkgoWriter.Write([]byte("==============================Global Before Each=============================="))
	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
	space = helpers.NewSpaceName()
	helpers.SetupCF(organization, space)
	GinkgoWriter.Write([]byte("==============================End of Global Before Each=============================="))
})

var _ = AfterEach(func() {
	GinkgoWriter.Write([]byte("==============================Global After Each=============================="))
	helpers.SetAPI()
	helpers.SetupCF(organization, space)
	helpers.QuickDeleteSpace(space)
	helpers.DestroyHomeDir(homeDir)
})
<commit_msg>Revert push suite change<commit_after>package push

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"
	"time"

	"code.cloudfoundry.org/cli/integration/helpers/fakeservicebroker"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const (
	CFEventuallyTimeout   = 300 * time.Second
	CFConsistentlyTimeout = 500 * time.Millisecond
	RealIsolationSegment  = "persistent_isolation_segment"
	PushCommandName       = "push"
	PublicDockerImage     = "cloudfoundry/diego-docker-app-custom"
)

var (
	// Suite Level
	organization string
	space        string
	realDir      string

	// Per Test Level
	homeDir string
)

func TestPush(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Push Integration Suite")
}

var _ = SynchronizedBeforeSuite(func() []byte {
	GinkgoWriter.Write([]byte("==============================Global FIRST Node Synchronized Before Each=============================="))
	SetDefaultEventuallyTimeout(CFEventuallyTimeout)
	SetDefaultConsistentlyDuration(CFConsistentlyTimeout)

	helpers.SetupSynchronizedSuite(func() {
		helpers.EnableFeatureFlag("diego_docker")
		helpers.EnableFeatureFlag("service_instance_sharing")
	})

	fakeservicebroker.Setup()

	GinkgoWriter.Write([]byte("==============================End of Global FIRST Node Synchronized Before Each=============================="))

	return nil
}, func(_ []byte) {
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================Global Node %d Synchronized Before Each==============================", GinkgoParallelNode())))
	// Ginkgo Globals
	SetDefaultEventuallyTimeout(CFEventuallyTimeout)
	SetDefaultConsistentlyDuration(CFConsistentlyTimeout)

	// Setup common environment variables
	helpers.TurnOffColors()

	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
	helpers.LoginCF()

	organization = helpers.NewOrgName()
	helpers.CreateOrg(organization)
	helpers.TargetOrg(organization)
	helpers.CreateSpace("empty-space")
	helpers.DestroyHomeDir(homeDir)

	var err error
	realDir, err = ioutil.TempDir("", "push-real-dir")
	Expect(err).ToNot(HaveOccurred())
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================End of Global Node %d Synchronized Before Each==============================", GinkgoParallelNode())))
})

var _ = SynchronizedAfterSuite(func() {
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================Global Node %d Synchronized After Each==============================", GinkgoParallelNode())))
	fakeservicebroker.Cleanup()
	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
	helpers.LoginCF()
	helpers.QuickDeleteOrg(organization)
	Expect(os.RemoveAll(realDir)).ToNot(HaveOccurred())
	helpers.DestroyHomeDir(homeDir)
	GinkgoWriter.Write([]byte(fmt.Sprintf("==============================End of Global Node %d Synchronized After Each==============================", GinkgoParallelNode())))
}, func() {})

var _ = BeforeEach(func() {
	GinkgoWriter.Write([]byte("==============================Global Before Each=============================="))
	homeDir = helpers.SetHomeDir()
	helpers.SetAPI()
	space = helpers.NewSpaceName()
	helpers.SetupCF(organization, space)
	GinkgoWriter.Write([]byte("==============================End of Global Before Each=============================="))
})

var _ = AfterEach(func() {
	GinkgoWriter.Write([]byte("==============================Global After Each=============================="))
	helpers.SetAPI()
	helpers.SetupCF(organization, space)
	helpers.QuickDeleteSpace(space)
	helpers.DestroyHomeDir(homeDir)
})
<|endoftext|>


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

package web

import (
	"flag"
	"fmt"
	"html/template"
	"net/http"
	_ "net/http/pprof"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/prometheus/alertmanager/web/api"
	"github.com/prometheus/alertmanager/web/blob"
)

// Commandline flags.
var (
	listenAddress  = flag.String("web.listen-address", ":9093", "Address to listen on for the web interface and API.")
	useLocalAssets = flag.Bool("web.use-local-assets", false, "Serve assets and templates from local files instead of from the binary.")
)

type WebService struct {
	AlertManagerService *api.AlertManagerService
	AlertsHandler       *AlertsHandler
	SilencesHandler     *SilencesHandler
	StatusHandler       *StatusHandler
}

func (w WebService) ServeForever(pathPrefix string) error {

	http.Handle(pathPrefix + "favicon.ico", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "", 404)
	}))

	http.HandleFunc("/", prometheus.InstrumentHandlerFunc("index", func(rw http.ResponseWriter, req *http.Request) {
		// The "/" pattern matches everything, so we need to check
		// that we're at the root here.
		if req.URL.Path == pathPrefix {
			w.AlertsHandler.ServeHTTP(rw, req)
		} else if req.URL.Path == "/" {
			// We're running under a prefix but the user requested "/".
			http.Redirect(rw, req, pathPrefix, http.StatusFound)
		} else {
			http.NotFound(rw, req)
		}
	}))

	http.Handle(pathPrefix + "alerts", prometheus.InstrumentHandler("alerts", w.AlertsHandler))
	http.Handle(pathPrefix + "silences", prometheus.InstrumentHandler("silences", w.SilencesHandler))
	http.Handle(pathPrefix + "status", prometheus.InstrumentHandler("status", w.StatusHandler))

	http.Handle(pathPrefix + "metrics", prometheus.Handler())
	if *useLocalAssets {
		http.Handle(pathPrefix + "static/", http.StripPrefix(pathPrefix + "static/", http.FileServer(http.Dir("web/static"))))
	} else {
		http.Handle(pathPrefix + "static/", http.StripPrefix(pathPrefix + "static/", new(blob.Handler)))
	}
	http.Handle(pathPrefix + "api/", w.AlertManagerService.Handler())

	glog.Info("listening on ", *listenAddress)

	return http.ListenAndServe(*listenAddress, nil)
}

func getLocalTemplate(name string, pathPrefix string) (*template.Template, error) {
	t := template.New("_base.html")
	t.Funcs(webHelpers)
	t.Funcs(template.FuncMap{"pathPrefix": func() string { return pathPrefix }})

	return t.ParseFiles(
		"web/templates/_base.html",
		fmt.Sprintf("web/templates/%s.html", name),
	)
}

func getEmbeddedTemplate(name string, pathPrefix string) (*template.Template, error) {
	t := template.New("_base.html")
	t.Funcs(webHelpers)
	t.Funcs(template.FuncMap{"pathPrefix": func() string { return pathPrefix }})

	file, err := blob.GetFile(blob.TemplateFiles, "_base.html")
	if err != nil {
		glog.Error("Could not read base template: ", err)
		return nil, err
	}
	t.Parse(string(file))

	file, err = blob.GetFile(blob.TemplateFiles, name+".html")
	if err != nil {
		glog.Errorf("Could not read %s template: %s", name, err)
		return nil, err
	}
	t.Parse(string(file))

	return t, nil
}

func getTemplate(name string, pathPrefix string) (t *template.Template, err error) {
	if *useLocalAssets {
		t, err = getLocalTemplate(name, pathPrefix)
	} else {
		t, err = getEmbeddedTemplate(name, pathPrefix)
	}

	if err != nil {
		return nil, err
	}

	return t, nil
}

func executeTemplate(w http.ResponseWriter, name string, data interface{}, pathPrefix string) {
	tpl, err := getTemplate(name, pathPrefix)
	if err != nil {
		glog.Error("Error preparing layout template: ", err)
		return
	}
	err = tpl.Execute(w, data)
	if err != nil {
		glog.Error("Error executing template: ", err)
	}
}
<commit_msg>Improve web redirection and 404 behavior.<commit_after>// Copyright 2013 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package web

import (
	"flag"
	"fmt"
	"html/template"
	"net/http"
	_ "net/http/pprof"
	"strings"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"

	"github.com/prometheus/alertmanager/web/api"
	"github.com/prometheus/alertmanager/web/blob"
)

// Commandline flags.
var (
	listenAddress  = flag.String("web.listen-address", ":9093", "Address to listen on for the web interface and API.")
	useLocalAssets = flag.Bool("web.use-local-assets", false, "Serve assets and templates from local files instead of from the binary.")
)

type WebService struct {
	AlertManagerService *api.AlertManagerService
	AlertsHandler       *AlertsHandler
	SilencesHandler     *SilencesHandler
	StatusHandler       *StatusHandler
}

func (w WebService) ServeForever(pathPrefix string) error {

	http.Handle(pathPrefix+"favicon.ico", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "", 404)
	}))

	http.HandleFunc("/", prometheus.InstrumentHandlerFunc("index", func(rw http.ResponseWriter, req *http.Request) {
		// The "/" pattern matches everything, so we need to check
		// that we're at the root here.
		if req.URL.Path == pathPrefix {
			w.AlertsHandler.ServeHTTP(rw, req)
		} else if req.URL.Path == strings.TrimRight(pathPrefix, "/") {
			http.Redirect(rw, req, pathPrefix, http.StatusFound)
		} else if !strings.HasPrefix(req.URL.Path, pathPrefix) {
			// We're running under a prefix but the user requested something
			// outside of it. Let's see if this page exists under the prefix.
			http.Redirect(rw, req, pathPrefix+strings.TrimLeft(req.URL.Path, "/"), http.StatusFound)
		} else {
			http.NotFound(rw, req)
		}
	}))

	http.Handle(pathPrefix+"alerts", prometheus.InstrumentHandler("alerts", w.AlertsHandler))
	http.Handle(pathPrefix+"silences", prometheus.InstrumentHandler("silences", w.SilencesHandler))
	http.Handle(pathPrefix+"status", prometheus.InstrumentHandler("status", w.StatusHandler))

	http.Handle(pathPrefix+"metrics", prometheus.Handler())
	if *useLocalAssets {
		http.Handle(pathPrefix+"static/", http.StripPrefix(pathPrefix+"static/", http.FileServer(http.Dir("web/static"))))
	} else {
		http.Handle(pathPrefix+"static/", http.StripPrefix(pathPrefix+"static/", new(blob.Handler)))
	}
	http.Handle(pathPrefix+"api/", w.AlertManagerService.Handler())

	glog.Info("listening on ", *listenAddress)

	return http.ListenAndServe(*listenAddress, nil)
}

func getLocalTemplate(name string, pathPrefix string) (*template.Template, error) {
	t := template.New("_base.html")
	t.Funcs(webHelpers)
	t.Funcs(template.FuncMap{"pathPrefix": func() string { return pathPrefix }})

	return t.ParseFiles(
		"web/templates/_base.html",
		fmt.Sprintf("web/templates/%s.html", name),
	)
}

func getEmbeddedTemplate(name string, pathPrefix string) (*template.Template, error) {
	t := template.New("_base.html")
	t.Funcs(webHelpers)
	t.Funcs(template.FuncMap{"pathPrefix": func() string { return pathPrefix }})

	file, err := blob.GetFile(blob.TemplateFiles, "_base.html")
	if err != nil {
		glog.Error("Could not read base template: ", err)
		return nil, err
	}
	t.Parse(string(file))

	file, err = blob.GetFile(blob.TemplateFiles, name+".html")
	if err != nil {
		glog.Errorf("Could not read %s template: %s", name, err)
		return nil, err
	}
	t.Parse(string(file))

	return t, nil
}

func getTemplate(name string, pathPrefix string) (t *template.Template, err error) {
	if *useLocalAssets {
		t, err = getLocalTemplate(name, pathPrefix)
	} else {
		t, err = getEmbeddedTemplate(name, pathPrefix)
	}

	if err != nil {
		return nil, err
	}

	return t, nil
}

func executeTemplate(w http.ResponseWriter, name string, data interface{}, pathPrefix string) {
	tpl, err := getTemplate(name, pathPrefix)
	if err != nil {
		glog.Error("Error preparing layout template: ", err)
		return
	}
	err = tpl.Execute(w, data)
	if err != nil {
		glog.Error("Error executing template: ", err)
	}
}
<|endoftext|>


<commit_before>package multicast

import (
	"context"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/pkg/errors"

	"github.com/brocaar/chirpstack-network-server/v3/internal/gps"
	"github.com/brocaar/chirpstack-network-server/v3/internal/helpers/classb"
	"github.com/brocaar/chirpstack-network-server/v3/internal/storage"
)

// EnqueueQueueItem selects the gateways that must be used to cover all devices
// within the multicast-group and creates a queue-item for each individial
// gateway.
// Note that an enqueue action increments the frame-counter of the multicast-group.
func EnqueueQueueItem(ctx context.Context, db sqlx.Ext, qi storage.MulticastQueueItem) error {
	// Get multicast-group and lock it.
	mg, err := storage.GetMulticastGroup(ctx, db, qi.MulticastGroupID, true)
	if err != nil {
		return errors.Wrap(err, "get multicast-group error")
	}

	if qi.FCnt < mg.FCnt {
		return ErrInvalidFCnt
	}

	mg.FCnt = qi.FCnt + 1
	if err := storage.UpdateMulticastGroup(ctx, db, &mg); err != nil {
		return errors.Wrap(err, "update multicast-group error")
	}

	// get DevEUIs within the multicast-group.
	devEUIs, err := storage.GetDevEUIsForMulticastGroup(ctx, db, qi.MulticastGroupID)
	if err != nil {
		return errors.Wrap(err, "get deveuis for multicast-group error")
	}

	rxInfoSets, err := storage.GetDeviceGatewayRXInfoSetForDevEUIs(ctx, devEUIs)
	if err != nil {
		return errors.Wrap(err, "get device gateway rx-info set for deveuis errors")
	}

	gatewayIDs, err := GetMinimumGatewaySet(rxInfoSets)
	if err != nil {
		return errors.Wrap(err, "get minimum gateway set error")
	}

	// for each gateway we increment the schedule_at timestamp with one second
	// to avoid colissions.
	if mg.GroupType == storage.MulticastGroupC {
		ts, err := storage.GetMaxScheduleAtForMulticastGroup(ctx, db, mg.ID)
		if err != nil {
			return errors.Wrap(err, "get maximum schedule at error")
		}

		if ts.IsZero() {
			ts = time.Now()
		}

		for _, gatewayID := range gatewayIDs {
			ts = ts.Add(multicastGatewayDelay)
			qi.GatewayID = gatewayID
			qi.ScheduleAt = ts
			if err = storage.CreateMulticastQueueItem(ctx, db, &qi); err != nil {
				return errors.Wrap(err, "create multicast queue-item error")
			}
		}
	}

	// for each gateway the use the next ping-slot
	if mg.GroupType == storage.MulticastGroupB {
		var pingSlotNb int
		if mg.PingSlotPeriod != 0 {
			pingSlotNb = (1 << 12) / mg.PingSlotPeriod
		}

		scheduleTS, err := storage.GetMaxEmitAtTimeSinceGPSEpochForMulticastGroup(ctx, db, mg.ID)
		if err != nil {
			return errors.Wrap(err, "get maximum emit at time since gps epoch error")
		}

		if scheduleTS == 0 {
			scheduleTS = gps.Time(time.Now().Add(classBEnqueueMargin)).TimeSinceGPSEpoch()
		}

		for _, gatewayID := range gatewayIDs {
			scheduleTS, err = classb.GetNextPingSlotAfter(scheduleTS, mg.MCAddr, pingSlotNb)
			if err != nil {
				return errors.Wrap(err, "get next ping-slot after error")
			}

			qi.EmitAtTimeSinceGPSEpoch = &scheduleTS
			qi.ScheduleAt = time.Time(gps.NewFromTimeSinceGPSEpoch(scheduleTS)).Add(-2 * schedulerInterval)
			qi.GatewayID = gatewayID

			if err = storage.CreateMulticastQueueItem(ctx, db, &qi); err != nil {
				return errors.Wrap(err, "create multicast queue-item error")
			}
		}
	}

	return nil
}
<commit_msg>Increment by multicast gateway delay after first item.<commit_after>package multicast

import (
	"context"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/pkg/errors"

	"github.com/brocaar/chirpstack-network-server/v3/internal/gps"
	"github.com/brocaar/chirpstack-network-server/v3/internal/helpers/classb"
	"github.com/brocaar/chirpstack-network-server/v3/internal/storage"
)

// EnqueueQueueItem selects the gateways that must be used to cover all devices
// within the multicast-group and creates a queue-item for each individial
// gateway.
// Note that an enqueue action increments the frame-counter of the multicast-group.
func EnqueueQueueItem(ctx context.Context, db sqlx.Ext, qi storage.MulticastQueueItem) error {
	// Get multicast-group and lock it.
	mg, err := storage.GetMulticastGroup(ctx, db, qi.MulticastGroupID, true)
	if err != nil {
		return errors.Wrap(err, "get multicast-group error")
	}

	if qi.FCnt < mg.FCnt {
		return ErrInvalidFCnt
	}

	mg.FCnt = qi.FCnt + 1
	if err := storage.UpdateMulticastGroup(ctx, db, &mg); err != nil {
		return errors.Wrap(err, "update multicast-group error")
	}

	// get DevEUIs within the multicast-group.
	devEUIs, err := storage.GetDevEUIsForMulticastGroup(ctx, db, qi.MulticastGroupID)
	if err != nil {
		return errors.Wrap(err, "get deveuis for multicast-group error")
	}

	rxInfoSets, err := storage.GetDeviceGatewayRXInfoSetForDevEUIs(ctx, devEUIs)
	if err != nil {
		return errors.Wrap(err, "get device gateway rx-info set for deveuis errors")
	}

	gatewayIDs, err := GetMinimumGatewaySet(rxInfoSets)
	if err != nil {
		return errors.Wrap(err, "get minimum gateway set error")
	}

	// for each gateway we increment the schedule_at timestamp with one second
	// to avoid colissions.
	if mg.GroupType == storage.MulticastGroupC {
		ts, err := storage.GetMaxScheduleAtForMulticastGroup(ctx, db, mg.ID)
		if err != nil {
			return errors.Wrap(err, "get maximum schedule at error")
		}

		if ts.IsZero() {
			ts = time.Now()
		}

		for _, gatewayID := range gatewayIDs {
			qi.GatewayID = gatewayID
			qi.ScheduleAt = ts
			if err = storage.CreateMulticastQueueItem(ctx, db, &qi); err != nil {
				return errors.Wrap(err, "create multicast queue-item error")
			}

			// The ts increment is added after scheduling the first item, as we don't
			// need to increment the first queue item.
			ts = ts.Add(multicastGatewayDelay)
		}
	}

	// for each gateway the use the next ping-slot
	if mg.GroupType == storage.MulticastGroupB {
		var pingSlotNb int
		if mg.PingSlotPeriod != 0 {
			pingSlotNb = (1 << 12) / mg.PingSlotPeriod
		}

		scheduleTS, err := storage.GetMaxEmitAtTimeSinceGPSEpochForMulticastGroup(ctx, db, mg.ID)
		if err != nil {
			return errors.Wrap(err, "get maximum emit at time since gps epoch error")
		}

		if scheduleTS == 0 {
			scheduleTS = gps.Time(time.Now().Add(classBEnqueueMargin)).TimeSinceGPSEpoch()
		}

		for _, gatewayID := range gatewayIDs {
			scheduleTS, err = classb.GetNextPingSlotAfter(scheduleTS, mg.MCAddr, pingSlotNb)
			if err != nil {
				return errors.Wrap(err, "get next ping-slot after error")
			}

			qi.EmitAtTimeSinceGPSEpoch = &scheduleTS
			qi.ScheduleAt = time.Time(gps.NewFromTimeSinceGPSEpoch(scheduleTS)).Add(-2 * schedulerInterval)
			qi.GatewayID = gatewayID

			if err = storage.CreateMulticastQueueItem(ctx, db, &qi); err != nil {
				return errors.Wrap(err, "create multicast queue-item error")
			}
		}
	}

	return nil
}
<|endoftext|>


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

// +build ebitendebug

package graphics

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

// +build ebitendebug

package graphics

func recordLog() bool {
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"strings"

	"github.com/adnanh/webhook/hook"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"

	fsnotify "gopkg.in/fsnotify.v1"
)

const (
	version = "2.3.1"
)

var (
	ip             = flag.String("ip", "", "ip the webhook should serve hooks on")
	port           = flag.Int("port", 9000, "port the webhook should serve hooks on")
	verbose        = flag.Bool("verbose", false, "show verbose output")
	hotReload      = flag.Bool("hotreload", false, "watch hooks file for changes and reload them automatically")
	hooksFilePath  = flag.String("hooks", "hooks.json", "path to the json file containing defined hooks the webhook should serve")
	hooksURLPrefix = flag.String("urlprefix", "hooks", "url prefix to use for served hooks (protocol://yourserver:port/PREFIX/:hook-id)")
	secure         = flag.Bool("secure", false, "use HTTPS instead of HTTP")
	cert           = flag.String("cert", "cert.pem", "path to the HTTPS certificate pem file")
	key            = flag.String("key", "key.pem", "path to the HTTPS certificate private key pem file")

	watcher *fsnotify.Watcher

	hooks hook.Hooks
)

func init() {
	hooks = hook.Hooks{}

	flag.Parse()

	log.SetPrefix("[webhook] ")
	log.SetFlags(log.Ldate | log.Ltime)

	if !*verbose {
		log.SetOutput(ioutil.Discard)
	}

	log.Println("version " + version + " starting")

	// load and parse hooks
	log.Printf("attempting to load hooks from %s\n", *hooksFilePath)

	err := hooks.LoadFromFile(*hooksFilePath)

	if err != nil {
		log.Printf("couldn't load hooks from file! %+v\n", err)
	} else {
		log.Printf("loaded %d hook(s) from file\n", len(hooks))

		for _, hook := range hooks {
			log.Printf("\t> %s\n", hook.ID)
		}
	}
}

func main() {
	if *hotReload {
		// set up file watcher
		log.Printf("setting up file watcher for %s\n", *hooksFilePath)

		var err error

		watcher, err = fsnotify.NewWatcher()
		if err != nil {
			log.Fatal("error creating file watcher instance", err)
		}

		defer watcher.Close()

		go watchForFileChange()

		err = watcher.Add(*hooksFilePath)
		if err != nil {
			log.Fatal("error adding hooks file to the watcher", err)
		}
	}

	l := negroni.NewLogger()
	l.Logger = log.New(os.Stdout, "[webhook] ", log.Ldate|log.Ltime)

	negroniRecovery := &negroni.Recovery{
		Logger:     l.Logger,
		PrintStack: true,
		StackAll:   false,
		StackSize:  1024 * 8,
	}

	n := negroni.New(negroniRecovery, l)

	router := mux.NewRouter()

	var hooksURL string

	if *hooksURLPrefix == "" {
		hooksURL = "/{id}"
	} else {
		hooksURL = "/" + *hooksURLPrefix + "/{id}"
	}

	router.HandleFunc(hooksURL, hookHandler)

	n.UseHandler(router)

	if *secure {
		log.Printf("starting secure (https) webhook on %s:%d", *ip, *port)
		log.Fatal(http.ListenAndServeTLS(fmt.Sprintf("%s:%d", *ip, *port), *cert, *key, n))
	} else {
		log.Printf("starting insecure (http) webhook on %s:%d", *ip, *port)
		log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", *ip, *port), n))
	}

}

func hookHandler(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]

	hook := hooks.Match(id)

	if hook != nil {
		log.Printf("%s got matched\n", id)

		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			log.Printf("error reading the request body. %+v\n", err)
		}

		// parse headers
		headers := valuesToMap(r.Header)

		// parse query variables
		query := valuesToMap(r.URL.Query())

		// parse body
		var payload map[string]interface{}

		contentType := r.Header.Get("Content-Type")

		if strings.HasPrefix(contentType, "application/json") {
			decoder := json.NewDecoder(strings.NewReader(string(body)))
			decoder.UseNumber()

			err := decoder.Decode(&payload)

			if err != nil {
				log.Printf("error parsing JSON payload %+v\n", err)
			}
		} else if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") {
			fd, err := url.ParseQuery(string(body))
			if err != nil {
				log.Printf("error parsing form payload %+v\n", err)
			} else {
				payload = valuesToMap(fd)
			}
		}

		hook.ParseJSONParameters(&headers, &query, &payload)

		// handle hook
		go handleHook(hook, &headers, &query, &payload, &body)

		// send the hook defined response message
		fmt.Fprintf(w, hook.ResponseMessage)
	} else {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(w, "Hook not found.")
	}
}

func handleHook(hook *hook.Hook, headers, query, payload *map[string]interface{}, body *[]byte) {
	if hook.TriggerRule == nil || hook.TriggerRule != nil && hook.TriggerRule.Evaluate(headers, query, payload, body) {
		log.Printf("%s hook triggered successfully\n", hook.ID)

		cmd := exec.Command(hook.ExecuteCommand)
		cmd.Args = hook.ExtractCommandArguments(headers, query, payload)
		cmd.Dir = hook.CommandWorkingDirectory

		log.Printf("executing %s (%s) with arguments %s using %s as cwd\n", hook.ExecuteCommand, cmd.Path, cmd.Args, cmd.Dir)

		out, err := cmd.Output()

		log.Printf("stdout: %s\n", out)

		if err != nil {
			log.Printf("stderr: %+v\n", err)
		}
		log.Printf("finished handling %s\n", hook.ID)
	} else {
		log.Printf("%s hook did not get triggered\n", hook.ID)
	}
}

func watchForFileChange() {
	for {
		select {
		case event := <-(*watcher).Events:
			if event.Op&fsnotify.Write == fsnotify.Write {
				log.Println("hooks file modified")

				newHooks := hook.Hooks{}

				// parse and swap
				log.Printf("attempting to reload hooks from %s\n", *hooksFilePath)

				err := newHooks.LoadFromFile(*hooksFilePath)

				if err != nil {
					log.Printf("couldn't load hooks from file! %+v\n", err)
				} else {
					log.Printf("loaded %d hook(s) from file\n", len(hooks))

					for _, hook := range hooks {
						log.Printf("\t> %s\n", hook.ID)
					}

					hooks = newHooks
				}
			}
		case err := <-(*watcher).Errors:
			log.Println("watcher error:", err)
		}
	}
}

// valuesToMap converts map[string][]string to a map[string]string object
func valuesToMap(values map[string][]string) map[string]interface{} {
	ret := make(map[string]interface{})

	for key, value := range values {
		if len(value) > 0 {
			ret[key] = value[0]
		}
	}

	return ret
}
<commit_msg>added hook reload on USR1 signal<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"os/signal"
	"strings"
	"syscall"

	"github.com/adnanh/webhook/hook"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"

	fsnotify "gopkg.in/fsnotify.v1"
)

const (
	version = "2.3.2"
)

var (
	ip             = flag.String("ip", "", "ip the webhook should serve hooks on")
	port           = flag.Int("port", 9000, "port the webhook should serve hooks on")
	verbose        = flag.Bool("verbose", false, "show verbose output")
	hotReload      = flag.Bool("hotreload", false, "watch hooks file for changes and reload them automatically")
	hooksFilePath  = flag.String("hooks", "hooks.json", "path to the json file containing defined hooks the webhook should serve")
	hooksURLPrefix = flag.String("urlprefix", "hooks", "url prefix to use for served hooks (protocol://yourserver:port/PREFIX/:hook-id)")
	secure         = flag.Bool("secure", false, "use HTTPS instead of HTTP")
	cert           = flag.String("cert", "cert.pem", "path to the HTTPS certificate pem file")
	key            = flag.String("key", "key.pem", "path to the HTTPS certificate private key pem file")

	watcher *fsnotify.Watcher
	signals chan os.Signal

	hooks hook.Hooks
)

func init() {
	hooks = hook.Hooks{}

	flag.Parse()

	log.SetPrefix("[webhook] ")
	log.SetFlags(log.Ldate | log.Ltime)

	if !*verbose {
		log.SetOutput(ioutil.Discard)
	}

	log.Println("version " + version + " starting")

	// set os signal watcher
	log.Printf("setting up os signal watcher\n")

	signals = make(chan os.Signal, 1)
	signal.Notify(signals, syscall.Signal(0xa))

	go watchForSignals()

	// load and parse hooks
	log.Printf("attempting to load hooks from %s\n", *hooksFilePath)

	err := hooks.LoadFromFile(*hooksFilePath)

	if err != nil {
		log.Printf("couldn't load hooks from file! %+v\n", err)
	} else {
		log.Printf("loaded %d hook(s) from file\n", len(hooks))

		for _, hook := range hooks {
			log.Printf("\t> %s\n", hook.ID)
		}
	}
}

func main() {
	if *hotReload {
		// set up file watcher
		log.Printf("setting up file watcher for %s\n", *hooksFilePath)

		var err error

		watcher, err = fsnotify.NewWatcher()
		if err != nil {
			log.Fatal("error creating file watcher instance", err)
		}

		defer watcher.Close()

		go watchForFileChange()

		err = watcher.Add(*hooksFilePath)
		if err != nil {
			log.Fatal("error adding hooks file to the watcher", err)
		}
	}

	l := negroni.NewLogger()
	l.Logger = log.New(os.Stdout, "[webhook] ", log.Ldate|log.Ltime)

	negroniRecovery := &negroni.Recovery{
		Logger:     l.Logger,
		PrintStack: true,
		StackAll:   false,
		StackSize:  1024 * 8,
	}

	n := negroni.New(negroniRecovery, l)

	router := mux.NewRouter()

	var hooksURL string

	if *hooksURLPrefix == "" {
		hooksURL = "/{id}"
	} else {
		hooksURL = "/" + *hooksURLPrefix + "/{id}"
	}

	router.HandleFunc(hooksURL, hookHandler)

	n.UseHandler(router)

	if *secure {
		log.Printf("starting secure (https) webhook on %s:%d", *ip, *port)
		log.Fatal(http.ListenAndServeTLS(fmt.Sprintf("%s:%d", *ip, *port), *cert, *key, n))
	} else {
		log.Printf("starting insecure (http) webhook on %s:%d", *ip, *port)
		log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", *ip, *port), n))
	}

}

func hookHandler(w http.ResponseWriter, r *http.Request) {
	id := mux.Vars(r)["id"]

	hook := hooks.Match(id)

	if hook != nil {
		log.Printf("%s got matched\n", id)

		body, err := ioutil.ReadAll(r.Body)
		if err != nil {
			log.Printf("error reading the request body. %+v\n", err)
		}

		// parse headers
		headers := valuesToMap(r.Header)

		// parse query variables
		query := valuesToMap(r.URL.Query())

		// parse body
		var payload map[string]interface{}

		contentType := r.Header.Get("Content-Type")

		if strings.HasPrefix(contentType, "application/json") {
			decoder := json.NewDecoder(strings.NewReader(string(body)))
			decoder.UseNumber()

			err := decoder.Decode(&payload)

			if err != nil {
				log.Printf("error parsing JSON payload %+v\n", err)
			}
		} else if strings.HasPrefix(contentType, "application/x-www-form-urlencoded") {
			fd, err := url.ParseQuery(string(body))
			if err != nil {
				log.Printf("error parsing form payload %+v\n", err)
			} else {
				payload = valuesToMap(fd)
			}
		}

		hook.ParseJSONParameters(&headers, &query, &payload)

		// handle hook
		go handleHook(hook, &headers, &query, &payload, &body)

		// send the hook defined response message
		fmt.Fprintf(w, hook.ResponseMessage)
	} else {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(w, "Hook not found.")
	}
}

func handleHook(hook *hook.Hook, headers, query, payload *map[string]interface{}, body *[]byte) {
	if hook.TriggerRule == nil || hook.TriggerRule != nil && hook.TriggerRule.Evaluate(headers, query, payload, body) {
		log.Printf("%s hook triggered successfully\n", hook.ID)

		cmd := exec.Command(hook.ExecuteCommand)
		cmd.Args = hook.ExtractCommandArguments(headers, query, payload)
		cmd.Dir = hook.CommandWorkingDirectory

		log.Printf("executing %s (%s) with arguments %s using %s as cwd\n", hook.ExecuteCommand, cmd.Path, cmd.Args, cmd.Dir)

		out, err := cmd.Output()

		log.Printf("stdout: %s\n", out)

		if err != nil {
			log.Printf("stderr: %+v\n", err)
		}
		log.Printf("finished handling %s\n", hook.ID)
	} else {
		log.Printf("%s hook did not get triggered\n", hook.ID)
	}
}

func reloadHooks() {
	newHooks := hook.Hooks{}

	// parse and swap
	log.Printf("attempting to reload hooks from %s\n", *hooksFilePath)

	err := newHooks.LoadFromFile(*hooksFilePath)

	if err != nil {
		log.Printf("couldn't load hooks from file! %+v\n", err)
	} else {
		log.Printf("loaded %d hook(s) from file\n", len(hooks))

		for _, hook := range hooks {
			log.Printf("\t> %s\n", hook.ID)
		}

		hooks = newHooks
	}
}

func watchForFileChange() {
	for {
		select {
		case event := <-(*watcher).Events:
			if event.Op&fsnotify.Write == fsnotify.Write {
				log.Println("hooks file modified")

				reloadHooks()
			}
		case err := <-(*watcher).Errors:
			log.Println("watcher error:", err)
		}
	}
}

func watchForSignals() {
	log.Println("os signal watcher ready")

	for {
		sig := <-signals
		if sig == syscall.Signal(0xa) {
			log.Println("caught USR1 signal")

			reloadHooks()
		} else {
			log.Printf("caught unhandled signal %+v\n", sig)
		}
	}
}

// valuesToMap converts map[string][]string to a map[string]string object
func valuesToMap(values map[string][]string) map[string]interface{} {
	ret := make(map[string]interface{})

	for key, value := range values {
		if len(value) > 0 {
			ret[key] = value[0]
		}
	}

	return ret
}
<|endoftext|>


<commit_before>package wp

import (
  "log"
  "fmt"
  "io/ioutil"
  "encoding/json"
  "strings"
  "html"
  "html/template"
  "errors"
  "github.com/valyala/fasthttp"
)

type wpResponse struct {
  Errors []string `json:"errors"`
  Warning []string `json:"warnings"`
  Version string  `json:"version"`
  Hash string  `json:"hash"`
  PublicPath string  `json:"publicPath"`
  AssetsByChunkName map[string]*json.RawMessage `json:"assetsByChunkName"`
  Assets []*json.RawMessage `json:"assets"`
}

const host = "localhost:3808"
var c *fasthttp.HostClient
var dev bool
var assets map[string][]string
var webpackBase string

func Filter(vs []string, f func(string) bool) []string {
    vsf := make([]string, 0)
    for _, v := range vs {
        if f(v) {
            vsf = append(vsf, v)
        }
    }
    return vsf
}

func devManifest() (data []byte) {
  manifestUrl := fmt.Sprint("http://", host, "/webpack/manifest.json")
	statusCode, body, err := c.Get(nil, manifestUrl)
	if err != nil {
		log.Fatalf("Error when loading manifest from %s: %s", manifestUrl, err)
	}
	if statusCode != fasthttp.StatusOK {
		log.Fatalf("Unexpected status code: %d. Expecting %d", statusCode, fasthttp.StatusOK)
	}
  return body
}

func prodManifest() (data []byte) {
  body, err := ioutil.ReadFile("./public/webpack/manifest.json")
	if err != nil {
		log.Fatalf("Error when loading manifest from file: %s", err)
	}
  return body
}

func Manifest() (map[string][]string) {
  var data []byte
  if dev {
    data = devManifest()
  } else {
    data = prodManifest()
  }
  resp := wpResponse{}
  json.Unmarshal(data, &resp)
  webpackBase = resp.PublicPath

  ast := make(map[string][]string, len(resp.AssetsByChunkName))
  var err error
  for akey, aval := range resp.AssetsByChunkName {
    var d []string
    err = json.Unmarshal(*aval, &d)
    if err != nil {
      //log.Fatalf("Error when parsing manifest for %s: %s %s", akey, err, aval)
      //continue
      var sd string
      err = json.Unmarshal(*aval, &sd)
      if err != nil {
        log.Fatalf("Error when parsing manifest for %s: %s %s", akey, err, aval)
        continue
      }
      d = []string{sd}
    }
    ast[akey] = Filter(d, func(v string) bool {
        return !strings.Contains(v, ".map")
    })
    //ast[akey] = d
  }
  //log.Println(ast)
  return ast
}

func AssetHelper(key string) (template.HTML, error) {
  var ast map[string][]string
  if (dev) {
    ast = Manifest()
  } else {
    ast = assets
  }

  dat := strings.Split(key, ".")

  buf := []string{}
  var err error
  v, ok := ast[dat[0]]
  if (!ok) {
    return "", errors.New(fmt.Sprint("asset file ", dat[0], " not found in manifest"))
  }
  for _, s := range(v) {
    if (dat[1] == "css") {
      if strings.HasSuffix(s, ".css") {
        buf = append(buf, fmt.Sprint("<link type=\"text/css\" rel=\"stylesheet\" href=\"", webpackBase, html.EscapeString(s), "\"></script>"))
      }
    } else if (dat[1] == "js") {
      if strings.HasSuffix(s, ".js") {
        buf = append(buf, fmt.Sprint("<script type=\"text/javascript\" src=\"", webpackBase, html.EscapeString(s), "\"></script>"))
      }
    }
  }

  return template.HTML(strings.Join(buf, "\n")), err
}

func Init(is_dev bool) {
  dev = is_dev
  if dev {
    c = &fasthttp.HostClient{
      Addr: host,
    }
    Manifest()
  } else {
    assets = Manifest()
  }
}

<commit_msg>format<commit_after>package wp

import (
	"encoding/json"
	"errors"
	"fmt"
	"html"
	"html/template"
	"io/ioutil"
	"log"
	"strings"

	"github.com/valyala/fasthttp"
)

type wpResponse struct {
	Errors            []string                    `json:"errors"`
	Warning           []string                    `json:"warnings"`
	Version           string                      `json:"version"`
	Hash              string                      `json:"hash"`
	PublicPath        string                      `json:"publicPath"`
	AssetsByChunkName map[string]*json.RawMessage `json:"assetsByChunkName"`
	Assets            []*json.RawMessage          `json:"assets"`
}

const host = "localhost:3808"

var c *fasthttp.HostClient
var dev bool
var assets map[string][]string
var webpackBase string

func Filter(vs []string, f func(string) bool) []string {
	vsf := make([]string, 0)
	for _, v := range vs {
		if f(v) {
			vsf = append(vsf, v)
		}
	}
	return vsf
}

func devManifest() (data []byte) {
	manifestUrl := fmt.Sprint("http://", host, "/webpack/manifest.json")
	statusCode, body, err := c.Get(nil, manifestUrl)
	if err != nil {
		log.Fatalf("Error when loading manifest from %s: %s", manifestUrl, err)
	}
	if statusCode != fasthttp.StatusOK {
		log.Fatalf("Unexpected status code: %d. Expecting %d", statusCode, fasthttp.StatusOK)
	}
	return body
}

func prodManifest() (data []byte) {
	body, err := ioutil.ReadFile("./public/webpack/manifest.json")
	if err != nil {
		log.Fatalf("Error when loading manifest from file: %s", err)
	}
	return body
}

func Manifest() map[string][]string {
	var data []byte
	if dev {
		data = devManifest()
	} else {
		data = prodManifest()
	}
	resp := wpResponse{}
	json.Unmarshal(data, &resp)
	webpackBase = resp.PublicPath

	ast := make(map[string][]string, len(resp.AssetsByChunkName))
	var err error
	for akey, aval := range resp.AssetsByChunkName {
		var d []string
		err = json.Unmarshal(*aval, &d)
		if err != nil {
			//log.Fatalf("Error when parsing manifest for %s: %s %s", akey, err, aval)
			//continue
			var sd string
			err = json.Unmarshal(*aval, &sd)
			if err != nil {
				log.Fatalf("Error when parsing manifest for %s: %s %s", akey, err, aval)
				continue
			}
			d = []string{sd}
		}
		ast[akey] = Filter(d, func(v string) bool {
			return !strings.Contains(v, ".map")
		})
		//ast[akey] = d
	}
	//log.Println(ast)
	return ast
}

func AssetHelper(key string) (template.HTML, error) {
	var ast map[string][]string
	if dev {
		ast = Manifest()
	} else {
		ast = assets
	}

	dat := strings.Split(key, ".")

	buf := []string{}
	var err error
	v, ok := ast[dat[0]]
	if !ok {
		return "", errors.New(fmt.Sprint("asset file ", dat[0], " not found in manifest"))
	}
	for _, s := range v {
		if dat[1] == "css" {
			if strings.HasSuffix(s, ".css") {
				buf = append(buf, fmt.Sprint("<link type=\"text/css\" rel=\"stylesheet\" href=\"", webpackBase, html.EscapeString(s), "\"></script>"))
			}
		} else if dat[1] == "js" {
			if strings.HasSuffix(s, ".js") {
				buf = append(buf, fmt.Sprint("<script type=\"text/javascript\" src=\"", webpackBase, html.EscapeString(s), "\"></script>"))
			}
		}
	}

	return template.HTML(strings.Join(buf, "\n")), err
}

func Init(is_dev bool) {
	dev = is_dev
	if dev {
		c = &fasthttp.HostClient{
			Addr: host,
		}
		Manifest()
	} else {
		assets = Manifest()
	}
}
<|endoftext|>


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

package instance

import (
	"bytes"
	"net"
	"strconv"
)

// Private network ranges for IPv4.
// See: http://tools.ietf.org/html/rfc1918
var (
	classAPrivate = mustParseCIDR("10.0.0.0/8")
	classBPrivate = mustParseCIDR("172.16.0.0/12")
	classCPrivate = mustParseCIDR("192.168.0.0/16")
)

func mustParseCIDR(s string) *net.IPNet {
	_, net, err := net.ParseCIDR(s)
	if err != nil {
		panic(err)
	}
	return net
}

// AddressType represents the possible ways of specifying a machine location by
// either a hostname resolvable by dns lookup, or ipv4 or ipv6 address.
type AddressType string

const (
	HostName    AddressType = "hostname"
	Ipv4Address AddressType = "ipv4"
	Ipv6Address AddressType = "ipv6"
)

// NetworkScope denotes the context a location may apply to. If a name or
// address can be reached from the wider internet, it is considered public. A
// private network address is either specific to the cloud or cloud subnet a
// machine belongs to, or to the machine itself for containers.
type NetworkScope string

const (
	NetworkUnknown      NetworkScope = ""
	NetworkPublic       NetworkScope = "public"
	NetworkCloudLocal   NetworkScope = "local-cloud"
	NetworkMachineLocal NetworkScope = "local-machine"
)

// Address represents the location of a machine, including metadata about what
// kind of location the address describes.
type Address struct {
	Value       string
	Type        AddressType
	NetworkName string
	NetworkScope
}

// HostPort associates an address with a port.
type HostPort struct {
	Address
	Port int
}

// AddressesWithPort returns the given addresses all
// associated with the given port.
func AddressesWithPort(addrs []Address, port int) []HostPort {
	hps := make([]HostPort, len(addrs))
	for i, addr := range addrs {
		hps[i] = HostPort{
			Address: addr,
			Port:    port,
		}
	}
	return hps
}

// NetAddr returns the host-port as an address
// suitable for calling net.Dial.
func (hp HostPort) NetAddr() string {
	return net.JoinHostPort(hp.Value, strconv.Itoa(hp.Port))
}

// String returns a string representation of the address,
// in the form: scope:address(network name);
// for example:
//
//	public:c2-54-226-162-124.compute-1.amazonaws.com(ec2network)
//
// If the scope is NetworkUnknown, the initial scope: prefix will
// be omitted. If the NetworkName is blank, the (network name) suffix
// will be omitted.
func (a Address) String() string {
	var buf bytes.Buffer
	if a.NetworkScope != NetworkUnknown {
		buf.WriteString(string(a.NetworkScope))
		buf.WriteByte(':')
	}
	buf.WriteString(a.Value)
	if a.NetworkName != "" {
		buf.WriteByte('(')
		buf.WriteString(a.NetworkName)
		buf.WriteByte(')')
	}
	return buf.String()
}

// NewAddresses is a convenience function to create addresses from a string slice
func NewAddresses(inAddresses ...string) (outAddresses []Address) {
	for _, address := range inAddresses {
		outAddresses = append(outAddresses, NewAddress(address, NetworkUnknown))
	}
	return outAddresses
}

func DeriveAddressType(value string) AddressType {
	ip := net.ParseIP(value)
	switch {
	case ip == nil:
		// TODO(gz): Check value is a valid hostname
		return HostName
	case ip.To4() != nil:
		return Ipv4Address
	case ip.To16() != nil:
		return Ipv6Address
	default:
		panic("Unknown form of IP address")
	}
}

func isIPv4PrivateNetworkAddress(ip net.IP) bool {
	return classAPrivate.Contains(ip) ||
		classBPrivate.Contains(ip) ||
		classCPrivate.Contains(ip)
}

// deriveNetworkScope attempts to derive the network scope from an address's
// type and value, returning the original network scope if no deduction can
// be made.
func deriveNetworkScope(addr Address) NetworkScope {
	if addr.Type == HostName {
		return addr.NetworkScope
	}
	ip := net.ParseIP(addr.Value)
	if ip == nil {
		return addr.NetworkScope
	}
	if ip.IsLoopback() {
		return NetworkMachineLocal
	}
	switch addr.Type {
	case Ipv4Address:
		if isIPv4PrivateNetworkAddress(ip) {
			return NetworkCloudLocal
		}
		// If it's not loopback, and it's not a private
		// network address, then it's publicly routable.
		return NetworkPublic
	case Ipv6Address:
		// TODO(axw) check for IPv6 unique local address, if/when we care.
	}
	return addr.NetworkScope
}

// NewAddress creates a new Address, deriving its type from the value.
//
// If the specified scope is NetworkUnknown, then NewAddress will
// attempt derive the scope based on reserved IP address ranges.
func NewAddress(value string, scope NetworkScope) Address {
	addr := Address{
		Value:        value,
		Type:         DeriveAddressType(value),
		NetworkScope: scope,
	}
	if scope == NetworkUnknown {
		addr.NetworkScope = deriveNetworkScope(addr)
	}
	return addr
}

// SelectPublicAddress picks one address from a slice that would
// be appropriate to display as a publicly accessible endpoint.
// If there are no suitable addresses, the empty string is returned.
func SelectPublicAddress(addresses []Address) string {
	index := bestAddressIndex(len(addresses), func(i int) Address {
		return addresses[i]
	}, publicMatch)
	if index < 0 {
		return ""
	}
	return addresses[index].Value
}

func SelectPublicHostPort(hps []HostPort) string {
	index := bestAddressIndex(len(hps), func(i int) Address {
		return hps[i].Address
	}, publicMatch)
	if index < 0 {
		return ""
	}
	return hps[index].NetAddr()
}

// SelectInternalAddress picks one address from a slice that can be
// used as an endpoint for juju internal communication.
// If there are no suitable addresses, the empty string is returned.
func SelectInternalAddress(addresses []Address, machineLocal bool) string {
	index := bestAddressIndex(len(addresses), func(i int) Address {
		return addresses[i]
	}, internalAddressMatcher(machineLocal))
	if index < 0 {
		return ""
	}
	return addresses[index].Value
}

// SelectInternalHostPort picks one HostPort from a slice that can be
// used as an endpoint for juju internal communication and returns it
// in its NetAddr form.
// If there are no suitable addresses, the empty string is returned.
func SelectInternalHostPort(hps []HostPort, machineLocal bool) string {
	index := bestAddressIndex(len(hps), func(i int) Address {
		return hps[i].Address
	}, internalAddressMatcher(machineLocal))
	if index < 0 {
		return ""
	}
	return hps[index].NetAddr()
}

func publicMatch(addr Address) scopeMatch {
	switch addr.NetworkScope {
	case NetworkPublic:
		return exactScope
	case NetworkCloudLocal, NetworkUnknown:
		return fallbackScope
	}
	return invalidScope
}

func internalAddressMatcher(machineLocal bool) func(Address) scopeMatch {
	if machineLocal {
		return cloudOrMachineLocalMatch
	}
	return cloudLocalMatch
}

func cloudLocalMatch(addr Address) scopeMatch {
	switch addr.NetworkScope {
	case NetworkCloudLocal:
		return exactScope
	case NetworkPublic, NetworkUnknown:
		return fallbackScope
	}
	return invalidScope
}

func cloudOrMachineLocalMatch(addr Address) scopeMatch {
	if addr.NetworkScope == NetworkMachineLocal {
		return exactScope
	}
	return cloudLocalMatch(addr)
}

type scopeMatch int

const (
	invalidScope scopeMatch = iota
	exactScope
	fallbackScope
)

// bestAddressIndex returns the index of the first address
// with an exactly matching scope, or the first address with
// a matching fallback scope if there are no exact matches.
// If there are no suitable addresses, -1 is returned.
func bestAddressIndex(numAddr int, getAddr func(i int) Address, match func(addr Address) scopeMatch) int {
	fallbackAddressIndex := -1
	for i := 0; i < numAddr; i++ {
		addr := getAddr(i)
		if addr.Type != Ipv6Address {
			switch match(addr) {
			case exactScope:
				return i
			case fallbackScope:
				// Use the first fallback address if there are no exact matches.
				if fallbackAddressIndex == -1 {
					fallbackAddressIndex = i
				}
			}
		}
	}
	return fallbackAddressIndex
}
<commit_msg>instance/address: whitespace fix required by gofmt<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package instance

import (
	"bytes"
	"net"
	"strconv"
)

// Private network ranges for IPv4.
// See: http://tools.ietf.org/html/rfc1918
var (
	classAPrivate = mustParseCIDR("10.0.0.0/8")
	classBPrivate = mustParseCIDR("172.16.0.0/12")
	classCPrivate = mustParseCIDR("192.168.0.0/16")
)

func mustParseCIDR(s string) *net.IPNet {
	_, net, err := net.ParseCIDR(s)
	if err != nil {
		panic(err)
	}
	return net
}

// AddressType represents the possible ways of specifying a machine location by
// either a hostname resolvable by dns lookup, or ipv4 or ipv6 address.
type AddressType string

const (
	HostName    AddressType = "hostname"
	Ipv4Address AddressType = "ipv4"
	Ipv6Address AddressType = "ipv6"
)

// NetworkScope denotes the context a location may apply to. If a name or
// address can be reached from the wider internet, it is considered public. A
// private network address is either specific to the cloud or cloud subnet a
// machine belongs to, or to the machine itself for containers.
type NetworkScope string

const (
	NetworkUnknown      NetworkScope = ""
	NetworkPublic       NetworkScope = "public"
	NetworkCloudLocal   NetworkScope = "local-cloud"
	NetworkMachineLocal NetworkScope = "local-machine"
)

// Address represents the location of a machine, including metadata about what
// kind of location the address describes.
type Address struct {
	Value       string
	Type        AddressType
	NetworkName string
	NetworkScope
}

// HostPort associates an address with a port.
type HostPort struct {
	Address
	Port int
}

// AddressesWithPort returns the given addresses all
// associated with the given port.
func AddressesWithPort(addrs []Address, port int) []HostPort {
	hps := make([]HostPort, len(addrs))
	for i, addr := range addrs {
		hps[i] = HostPort{
			Address: addr,
			Port:    port,
		}
	}
	return hps
}

// NetAddr returns the host-port as an address
// suitable for calling net.Dial.
func (hp HostPort) NetAddr() string {
	return net.JoinHostPort(hp.Value, strconv.Itoa(hp.Port))
}

// String returns a string representation of the address,
// in the form: scope:address(network name);
// for example:
//
//	public:c2-54-226-162-124.compute-1.amazonaws.com(ec2network)
//
// If the scope is NetworkUnknown, the initial scope: prefix will
// be omitted. If the NetworkName is blank, the (network name) suffix
// will be omitted.
func (a Address) String() string {
	var buf bytes.Buffer
	if a.NetworkScope != NetworkUnknown {
		buf.WriteString(string(a.NetworkScope))
		buf.WriteByte(':')
	}
	buf.WriteString(a.Value)
	if a.NetworkName != "" {
		buf.WriteByte('(')
		buf.WriteString(a.NetworkName)
		buf.WriteByte(')')
	}
	return buf.String()
}

// NewAddresses is a convenience function to create addresses from a string slice
func NewAddresses(inAddresses ...string) (outAddresses []Address) {
	for _, address := range inAddresses {
		outAddresses = append(outAddresses, NewAddress(address, NetworkUnknown))
	}
	return outAddresses
}

func DeriveAddressType(value string) AddressType {
	ip := net.ParseIP(value)
	switch {
	case ip == nil:
		// TODO(gz): Check value is a valid hostname
		return HostName
	case ip.To4() != nil:
		return Ipv4Address
	case ip.To16() != nil:
		return Ipv6Address
	default:
		panic("Unknown form of IP address")
	}
}

func isIPv4PrivateNetworkAddress(ip net.IP) bool {
	return classAPrivate.Contains(ip) ||
		classBPrivate.Contains(ip) ||
		classCPrivate.Contains(ip)
}

// deriveNetworkScope attempts to derive the network scope from an address's
// type and value, returning the original network scope if no deduction can
// be made.
func deriveNetworkScope(addr Address) NetworkScope {
	if addr.Type == HostName {
		return addr.NetworkScope
	}
	ip := net.ParseIP(addr.Value)
	if ip == nil {
		return addr.NetworkScope
	}
	if ip.IsLoopback() {
		return NetworkMachineLocal
	}
	switch addr.Type {
	case Ipv4Address:
		if isIPv4PrivateNetworkAddress(ip) {
			return NetworkCloudLocal
		}
		// If it's not loopback, and it's not a private
		// network address, then it's publicly routable.
		return NetworkPublic
	case Ipv6Address:
		// TODO(axw) check for IPv6 unique local address, if/when we care.
	}
	return addr.NetworkScope
}

// NewAddress creates a new Address, deriving its type from the value.
//
// If the specified scope is NetworkUnknown, then NewAddress will
// attempt derive the scope based on reserved IP address ranges.
func NewAddress(value string, scope NetworkScope) Address {
	addr := Address{
		Value:        value,
		Type:         DeriveAddressType(value),
		NetworkScope: scope,
	}
	if scope == NetworkUnknown {
		addr.NetworkScope = deriveNetworkScope(addr)
	}
	return addr
}

// SelectPublicAddress picks one address from a slice that would
// be appropriate to display as a publicly accessible endpoint.
// If there are no suitable addresses, the empty string is returned.
func SelectPublicAddress(addresses []Address) string {
	index := bestAddressIndex(len(addresses), func(i int) Address {
		return addresses[i]
	}, publicMatch)
	if index < 0 {
		return ""
	}
	return addresses[index].Value
}

func SelectPublicHostPort(hps []HostPort) string {
	index := bestAddressIndex(len(hps), func(i int) Address {
		return hps[i].Address
	}, publicMatch)
	if index < 0 {
		return ""
	}
	return hps[index].NetAddr()
}

// SelectInternalAddress picks one address from a slice that can be
// used as an endpoint for juju internal communication.
// If there are no suitable addresses, the empty string is returned.
func SelectInternalAddress(addresses []Address, machineLocal bool) string {
	index := bestAddressIndex(len(addresses), func(i int) Address {
		return addresses[i]
	}, internalAddressMatcher(machineLocal))
	if index < 0 {
		return ""
	}
	return addresses[index].Value
}

// SelectInternalHostPort picks one HostPort from a slice that can be
// used as an endpoint for juju internal communication and returns it
// in its NetAddr form.
// If there are no suitable addresses, the empty string is returned.
func SelectInternalHostPort(hps []HostPort, machineLocal bool) string {
	index := bestAddressIndex(len(hps), func(i int) Address {
		return hps[i].Address
	}, internalAddressMatcher(machineLocal))
	if index < 0 {
		return ""
	}
	return hps[index].NetAddr()
}

func publicMatch(addr Address) scopeMatch {
	switch addr.NetworkScope {
	case NetworkPublic:
		return exactScope
	case NetworkCloudLocal, NetworkUnknown:
		return fallbackScope
	}
	return invalidScope
}

func internalAddressMatcher(machineLocal bool) func(Address) scopeMatch {
	if machineLocal {
		return cloudOrMachineLocalMatch
	}
	return cloudLocalMatch
}

func cloudLocalMatch(addr Address) scopeMatch {
	switch addr.NetworkScope {
	case NetworkCloudLocal:
		return exactScope
	case NetworkPublic, NetworkUnknown:
		return fallbackScope
	}
	return invalidScope
}

func cloudOrMachineLocalMatch(addr Address) scopeMatch {
	if addr.NetworkScope == NetworkMachineLocal {
		return exactScope
	}
	return cloudLocalMatch(addr)
}

type scopeMatch int

const (
	invalidScope scopeMatch = iota
	exactScope
	fallbackScope
)

// bestAddressIndex returns the index of the first address
// with an exactly matching scope, or the first address with
// a matching fallback scope if there are no exact matches.
// If there are no suitable addresses, -1 is returned.
func bestAddressIndex(numAddr int, getAddr func(i int) Address, match func(addr Address) scopeMatch) int {
	fallbackAddressIndex := -1
	for i := 0; i < numAddr; i++ {
		addr := getAddr(i)
		if addr.Type != Ipv6Address {
			switch match(addr) {
			case exactScope:
				return i
			case fallbackScope:
				// Use the first fallback address if there are no exact matches.
				if fallbackAddressIndex == -1 {
					fallbackAddressIndex = i
				}
			}
		}
	}
	return fallbackAddressIndex
}
<|endoftext|>