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

package net

import (
	"os"
	"runtime"
	"testing"
)

var listenMulticastUDPTests = []struct {
	net   string
	gaddr *UDPAddr
	flags Flags
	ipv6  bool
}{
	// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
}

func TestListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "netbsd", "openbsd", "plan9", "windows":
		return
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
			continue
		}
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		defer c.Close() // test to listen concurrently across multiple listeners
		if !tt.ipv6 {
			testIPv4MulticastSocketOptions(t, c.fd, ifi)
		} else {
			testIPv6MulticastSocketOptions(t, c.fd, ifi)
		}
		ifmat, err := ifi.MulticastAddrs()
		if err != nil {
			t.Fatalf("MulticastAddrs failed: %v", err)
		}
		var found bool
		for _, ifma := range ifmat {
			if ifma.(*IPAddr).IP.Equal(tt.gaddr.IP) {
				found = true
				break
			}
		}
		if !found {
			t.Fatalf("%q not found in RIB", tt.gaddr.String())
		}
	}
}

func TestSimpleListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		return
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 {
			continue
		}
		tt.flags = FlagUp | FlagMulticast
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		c.Close()
	}
}

func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv4MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastInterface failed: %v", err)
	}
	t.Logf("IPv4 multicast interface: %v", ifmc)
	err = setIPv4MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv4MulticastInterface failed: %v", err)
	}

	ttl, err := ipv4MulticastTTL(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastTTL failed: %v", err)
	}
	t.Logf("IPv4 multicast TTL: %v", ttl)
	err = setIPv4MulticastTTL(fd, 1)
	if err != nil {
		t.Fatalf("setIPv4MulticastTTL failed: %v", err)
	}

	loop, err := ipv4MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv4 multicast loopback: %v", loop)
	err = setIPv4MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
	}
}

func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv6MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastInterface failed: %v", err)
	}
	t.Logf("IPv6 multicast interface: %v", ifmc)
	err = setIPv6MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv6MulticastInterface failed: %v", err)
	}

	hoplim, err := ipv6MulticastHopLimit(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
	}
	t.Logf("IPv6 multicast hop limit: %v", hoplim)
	err = setIPv6MulticastHopLimit(fd, 1)
	if err != nil {
		t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
	}

	loop, err := ipv6MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv6 multicast loopback: %v", loop)
	err = setIPv6MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
	}
}
<commit_msg>net: disable normal multicast testing on linux/arm<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"os"
	"runtime"
	"testing"
)

var listenMulticastUDPTests = []struct {
	net   string
	gaddr *UDPAddr
	flags Flags
	ipv6  bool
}{
	// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
}

func TestListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "netbsd", "openbsd", "plan9", "windows":
		return
	case "linux":
		if runtime.GOARCH == "arm" {
			return
		}
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
			continue
		}
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		defer c.Close() // test to listen concurrently across multiple listeners
		if !tt.ipv6 {
			testIPv4MulticastSocketOptions(t, c.fd, ifi)
		} else {
			testIPv6MulticastSocketOptions(t, c.fd, ifi)
		}
		ifmat, err := ifi.MulticastAddrs()
		if err != nil {
			t.Fatalf("MulticastAddrs failed: %v", err)
		}
		var found bool
		for _, ifma := range ifmat {
			if ifma.(*IPAddr).IP.Equal(tt.gaddr.IP) {
				found = true
				break
			}
		}
		if !found {
			t.Fatalf("%q not found in RIB", tt.gaddr.String())
		}
	}
}

func TestSimpleListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		return
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 {
			continue
		}
		tt.flags = FlagUp | FlagMulticast
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		c.Close()
	}
}

func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv4MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastInterface failed: %v", err)
	}
	t.Logf("IPv4 multicast interface: %v", ifmc)
	err = setIPv4MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv4MulticastInterface failed: %v", err)
	}

	ttl, err := ipv4MulticastTTL(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastTTL failed: %v", err)
	}
	t.Logf("IPv4 multicast TTL: %v", ttl)
	err = setIPv4MulticastTTL(fd, 1)
	if err != nil {
		t.Fatalf("setIPv4MulticastTTL failed: %v", err)
	}

	loop, err := ipv4MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv4 multicast loopback: %v", loop)
	err = setIPv4MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
	}
}

func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv6MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastInterface failed: %v", err)
	}
	t.Logf("IPv6 multicast interface: %v", ifmc)
	err = setIPv6MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv6MulticastInterface failed: %v", err)
	}

	hoplim, err := ipv6MulticastHopLimit(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
	}
	t.Logf("IPv6 multicast hop limit: %v", hoplim)
	err = setIPv6MulticastHopLimit(fd, 1)
	if err != nil {
		t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
	}

	loop, err := ipv6MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv6 multicast loopback: %v", loop)
	err = setIPv6MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/i18n"
)

type versionCmd struct{}

func (c *versionCmd) showByDefault() bool {
	return true
}

func (c *versionCmd) usage() string {
	return i18n.G(
		`Prints the version number of this client tool.

lxc version`)
}

func (c *versionCmd) flags() {
}

func (c *versionCmd) run(_ *lxd.Config, args []string) error {
	if len(args) > 0 {
		return errArgs
	}
	fmt.Println(shared.Version)
	return nil
}
<commit_msg>Do not show version command by default<commit_after>package main

import (
	"fmt"

	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/i18n"
)

type versionCmd struct{}

func (c *versionCmd) showByDefault() bool {
	return false
}

func (c *versionCmd) usage() string {
	return i18n.G(
		`Prints the version number of this client tool.

lxc version`)
}

func (c *versionCmd) flags() {
}

func (c *versionCmd) run(_ *lxd.Config, args []string) error {
	if len(args) > 0 {
		return errArgs
	}
	fmt.Println(shared.Version)
	return nil
}
<|endoftext|>


<commit_before>package helpers

import (
	"encoding/json"
)

var (
	sushiiImageServerBase string
)

func TakeHTMLScreenshot(html string, width, height int) (data []byte, err error) {
	if sushiiImageServerBase == "" {
		sushiiImageServerBase = GetConfig().Path("sushii-image-server.base").Data().(string)
	}

	marshalledRequest, err := json.Marshal(&SushiRequest{
		Html:   html,
		Width:  width,
		Height: height,
	})
	if err != nil {
		return nil, err
	}

	data, err = NetPostUAWithError(sushiiImageServerBase+"/html", string(marshalledRequest), DEFAULT_UA)
	if err != nil {
		return nil, err
	}

	return data, nil
}

type SushiRequest struct {
	Html   string `json:"html"`
	Width  int    `json:"width"`
	Height int    `json:"height"`
}
<commit_msg>🕰 [levels] increases timeout time<commit_after>package helpers

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"time"
)

var (
	sushiiImageServerBase string
)

func TakeHTMLScreenshot(html string, width, height int) (data []byte, err error) {
	if sushiiImageServerBase == "" {
		sushiiImageServerBase = GetConfig().Path("sushii-image-server.base").Data().(string)
	}

	marshalledRequest, err := json.Marshal(&SushiRequest{
		Html:   html,
		Width:  width,
		Height: height,
	})
	if err != nil {
		return nil, err
	}

	client := &http.Client{
		Timeout: time.Duration(30 * time.Second),
	}

	request, err := http.NewRequest("POST", sushiiImageServerBase+"/html", bytes.NewBuffer(marshalledRequest))
	if err != nil {
		return nil, err
	}

	request.Header.Set("User-Agent", DEFAULT_UA)
	request.Header.Set("Content-Type", "application/json")

	response, err := client.Do(request)
	if err != nil {
		return nil, err
	}

	return ioutil.ReadAll(response.Body)
}

type SushiRequest struct {
	Html   string `json:"html"`
	Width  int    `json:"width"`
	Height int    `json:"height"`
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"path"
	"strings"

	"github.com/ava-labs/gecko/database/leveldb"
	"github.com/ava-labs/gecko/database/memdb"
	"github.com/ava-labs/gecko/genesis"
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/nat"
	"github.com/ava-labs/gecko/node"
	"github.com/ava-labs/gecko/snow/networking/router"
	"github.com/ava-labs/gecko/staking"
	"github.com/ava-labs/gecko/utils"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/ava-labs/gecko/utils/hashing"
	"github.com/ava-labs/gecko/utils/logging"
	"github.com/ava-labs/gecko/utils/wrappers"
	"github.com/mitchellh/go-homedir"
)

const (
	dbVersion    = "v0.2.0"
	defaultDbDir = "~/.gecko/db"
)

// Results of parsing the CLI
var (
	Config                 = node.Config{}
	Err                    error
	defaultStakingKeyPath  = "~/.gecko/staking/staker.key"
	defaultStakingCertPath = "~/.gecko/staking/staker.crt"
)

var (
	errBootstrapMismatch = errors.New("more bootstrap IDs provided than bootstrap IPs")
)

// GetIPs returns the default IPs for each network
func GetIPs(networkID uint32) []string {
	switch networkID {
	case genesis.CascadeID:
		return []string{
			"3.227.207.132:21001",
			"34.207.133.167:21001",
			"107.23.241.199:21001",
			"54.197.215.186:21001",
			"18.234.153.22:21001",
		}
	default:
		return nil
	}
}

// Parse the CLI arguments
func init() {
	errs := &wrappers.Errs{}
	defer func() { Err = errs.Err }()

	loggingConfig, err := logging.DefaultConfig()
	if errs.Add(err); errs.Errored() {
		return
	}

	fs := flag.NewFlagSet("gecko", flag.ContinueOnError)

	// NetworkID:
	networkName := fs.String("network-id", genesis.CascadeName, "Network ID this node will connect to")

	// Ava fees:
	fs.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva")

	// Assertions:
	fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution")

	// Crypto:
	fs.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification")

	// Database:
	db := fs.Bool("db-enabled", true, "Turn on persistent storage")
	dbDir := fs.String("db-dir", defaultDbDir, "Database directory for Ava state")

	// IP:
	consensusIP := fs.String("public-ip", "", "Public IP of this node")

	// HTTP Server:
	httpPort := fs.Uint("http-port", 9650, "Port of the HTTP server")
	fs.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs")
	fs.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server")
	fs.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server")

	// Bootstrapping:
	bootstrapIPs := fs.String("bootstrap-ips", "default", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631")
	bootstrapIDs := fs.String("bootstrap-ids", "default", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")

	// Staking:
	consensusPort := fs.Uint("staking-port", 9651, "Port of the consensus server")
	fs.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections")
	fs.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", defaultStakingKeyPath, "TLS private key for staking")
	fs.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", defaultStakingCertPath, "TLS certificate for staking")

	// Plugins:
	fs.StringVar(&Config.PluginDir, "plugin-dir", "./build/plugins", "Plugin directory for Ava VMs")

	// Logging:
	logsDir := fs.String("log-dir", "", "Logging directory for Ava")
	logLevel := fs.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}")
	logDisplayLevel := fs.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}")

	fs.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 5, "Number of nodes to query for each network poll")
	fs.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 4, "Alpha value to use for required number positive results")
	fs.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions")
	fs.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions")
	fs.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex")
	fs.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex")
	fs.IntVar(&Config.ConsensusParams.ConcurrentRepolls, "snow-concurrent-repolls", 1, "Minimum number of concurrent polls for finalizing consensus")

	// Enable/Disable APIs:
	fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API")
	fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API")
	fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API")
	fs.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened")

	// Throughput Server
	throughputPort := fs.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server")
	fs.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created")

	ferr := fs.Parse(os.Args[1:])

	if ferr == flag.ErrHelp {
		// display usage/help text and exit successfully
		os.Exit(0)
	}

	if ferr != nil {
		// other type of error occurred when parsing args
		os.Exit(2)
	}

	networkID, err := genesis.NetworkID(*networkName)
	if errs.Add(err); errs.Errored() {
		return
	}

	Config.NetworkID = networkID

	// DB:
	if *db {
		*dbDir, err = homedir.Expand(*dbDir)
		if errs.Add(fmt.Errorf("couldn't resolve db path: %w", err)); errs.Errored() {
			return
		}
		dbPath := path.Join(*dbDir, genesis.NetworkName(Config.NetworkID), dbVersion)
		db, err := leveldb.New(dbPath, 0, 0, 0)
		if errs.Add(fmt.Errorf("couldn't create db: %w", err)); errs.Errored() {
			return
		}
		Config.DB = db
	} else {
		Config.DB = memdb.New()
	}

	Config.Nat = nat.NewRouter()

	var ip net.IP
	// If public IP is not specified, get it using shell command dig
	if *consensusIP == "" {
		ip, err = Config.Nat.IP()
		if err != nil {
			ip = net.IPv4zero // Couldn't get my IP...set to 0.0.0.0
		}
	} else {
		ip = net.ParseIP(*consensusIP)
	}

	if ip == nil {
		errs.Add(fmt.Errorf("Invalid IP Address %s", *consensusIP))
		return
	}

	Config.StakingIP = utils.IPDesc{
		IP:   ip,
		Port: uint16(*consensusPort),
	}

	// Bootstrapping:
	if *bootstrapIPs == "default" {
		*bootstrapIPs = strings.Join(GetIPs(networkID), ",")
	}
	for _, ip := range strings.Split(*bootstrapIPs, ",") {
		if ip != "" {
			addr, err := utils.ToIPDesc(ip)
			if err != nil {
				errs.Add(fmt.Errorf("couldn't parse ip: %w", err))
				return
			}
			Config.BootstrapPeers = append(Config.BootstrapPeers, &node.Peer{
				IP: addr,
			})
		}
	}

	if *bootstrapIDs == "default" {
		if *bootstrapIPs == "" {
			*bootstrapIDs = ""
		} else {
			*bootstrapIDs = strings.Join(genesis.GetConfig(networkID).StakerIDs, ",")
		}
	}
	if Config.EnableStaking {
		i := 0
		cb58 := formatting.CB58{}
		for _, id := range strings.Split(*bootstrapIDs, ",") {
			if id != "" {
				err = cb58.FromString(id)
				if err != nil {
					errs.Add(fmt.Errorf("couldn't parse bootstrap peer id to bytes: %w", err))
					return
				}
				peerID, err := ids.ToShortID(cb58.Bytes)
				if err != nil {
					errs.Add(fmt.Errorf("couldn't parse bootstrap peer id: %w", err))
					return
				}
				if len(Config.BootstrapPeers) <= i {
					errs.Add(errBootstrapMismatch)
					return
				}
				Config.BootstrapPeers[i].ID = peerID
				i++
			}
		}
		if len(Config.BootstrapPeers) != i {
			errs.Add(fmt.Errorf("More bootstrap IPs, %d, provided than bootstrap IDs, %d", len(Config.BootstrapPeers), i))
			return
		}
	} else {
		for _, peer := range Config.BootstrapPeers {
			peer.ID = ids.NewShortID(hashing.ComputeHash160Array([]byte(peer.IP.String())))
		}
	}

	// Staking
	Config.StakingKeyFile, err = homedir.Expand(Config.StakingKeyFile)
	if err != nil {
		errs.Add(fmt.Errorf("couldn't resolve staking key path: %w", err))
		return
	}
	Config.StakingCertFile, err = homedir.Expand(Config.StakingCertFile)
	if err != nil {
		errs.Add(fmt.Errorf("couldn't resolve staking cert path: %v", err))
		return
	}
	defaultKeyPath, _ := homedir.Expand(defaultStakingKeyPath)
	defaultStakingCertPath, _ := homedir.Expand(defaultStakingCertPath)

	switch {
	// If staking key/cert locations are specified but not found, error
	case Config.StakingKeyFile != defaultKeyPath || Config.StakingCertFile != defaultStakingCertPath:
		if _, err := os.Stat(Config.StakingKeyFile); os.IsNotExist(err) {
			errs.Add(fmt.Errorf("couldn't find staking key at %s", Config.StakingKeyFile))
			return
		} else if _, err := os.Stat(Config.StakingCertFile); os.IsNotExist(err) {
			errs.Add(fmt.Errorf("couldn't find staking certificate at %s", Config.StakingCertFile))
			return
		}
	default:
		// Only creates staking key/cert if [stakingKeyPath] doesn't exist
		if err := staking.GenerateStakingKeyCert(Config.StakingKeyFile, Config.StakingCertFile); err != nil {
			errs.Add(fmt.Errorf("couldn't generate staking key/cert: %w", err))
			return
		}
	}

	// HTTP:
	Config.HTTPPort = uint16(*httpPort)

	// Logging:
	if *logsDir != "" {
		loggingConfig.Directory = *logsDir
	}
	logFileLevel, err := logging.ToLevel(*logLevel)
	if errs.Add(err); errs.Errored() {
		return
	}
	loggingConfig.LogLevel = logFileLevel

	if *logDisplayLevel == "" {
		*logDisplayLevel = *logLevel
	}
	displayLevel, err := logging.ToLevel(*logDisplayLevel)
	if errs.Add(err); errs.Errored() {
		return
	}
	loggingConfig.DisplayLevel = displayLevel

	Config.LoggingConfig = loggingConfig

	// Throughput:
	Config.ThroughputPort = uint16(*throughputPort)

	// Router used for consensus
	Config.ConsensusRouter = &router.ChainRouter{}
}
<commit_msg>fix bug<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"path"
	"strings"

	"github.com/ava-labs/gecko/database/leveldb"
	"github.com/ava-labs/gecko/database/memdb"
	"github.com/ava-labs/gecko/genesis"
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/nat"
	"github.com/ava-labs/gecko/node"
	"github.com/ava-labs/gecko/snow/networking/router"
	"github.com/ava-labs/gecko/staking"
	"github.com/ava-labs/gecko/utils"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/ava-labs/gecko/utils/hashing"
	"github.com/ava-labs/gecko/utils/logging"
	"github.com/ava-labs/gecko/utils/wrappers"
	"github.com/mitchellh/go-homedir"
)

const (
	dbVersion    = "v0.2.0"
	defaultDbDir = "~/.gecko/db"
)

// Results of parsing the CLI
var (
	Config                 = node.Config{}
	Err                    error
	defaultStakingKeyPath  = "~/.gecko/staking/staker.key"
	defaultStakingCertPath = "~/.gecko/staking/staker.crt"
)

var (
	errBootstrapMismatch = errors.New("more bootstrap IDs provided than bootstrap IPs")
)

// GetIPs returns the default IPs for each network
func GetIPs(networkID uint32) []string {
	switch networkID {
	case genesis.CascadeID:
		return []string{
			"3.227.207.132:21001",
			"34.207.133.167:21001",
			"107.23.241.199:21001",
			"54.197.215.186:21001",
			"18.234.153.22:21001",
		}
	default:
		return nil
	}
}

// Parse the CLI arguments
func init() {
	errs := &wrappers.Errs{}
	defer func() { Err = errs.Err }()

	loggingConfig, err := logging.DefaultConfig()
	if errs.Add(err); errs.Errored() {
		return
	}

	fs := flag.NewFlagSet("gecko", flag.ContinueOnError)

	// NetworkID:
	networkName := fs.String("network-id", genesis.CascadeName, "Network ID this node will connect to")

	// Ava fees:
	fs.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva")

	// Assertions:
	fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution")

	// Crypto:
	fs.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification")

	// Database:
	db := fs.Bool("db-enabled", true, "Turn on persistent storage")
	dbDir := fs.String("db-dir", defaultDbDir, "Database directory for Ava state")

	// IP:
	consensusIP := fs.String("public-ip", "", "Public IP of this node")

	// HTTP Server:
	httpPort := fs.Uint("http-port", 9650, "Port of the HTTP server")
	fs.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs")
	fs.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server")
	fs.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server")

	// Bootstrapping:
	bootstrapIPs := fs.String("bootstrap-ips", "default", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631")
	bootstrapIDs := fs.String("bootstrap-ids", "default", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")

	// Staking:
	consensusPort := fs.Uint("staking-port", 9651, "Port of the consensus server")
	fs.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections")
	fs.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", defaultStakingKeyPath, "TLS private key for staking")
	fs.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", defaultStakingCertPath, "TLS certificate for staking")

	// Plugins:
	fs.StringVar(&Config.PluginDir, "plugin-dir", "./build/plugins", "Plugin directory for Ava VMs")

	// Logging:
	logsDir := fs.String("log-dir", "", "Logging directory for Ava")
	logLevel := fs.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}")
	logDisplayLevel := fs.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}")

	fs.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 5, "Number of nodes to query for each network poll")
	fs.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 4, "Alpha value to use for required number positive results")
	fs.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions")
	fs.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions")
	fs.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex")
	fs.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex")
	fs.IntVar(&Config.ConsensusParams.ConcurrentRepolls, "snow-concurrent-repolls", 1, "Minimum number of concurrent polls for finalizing consensus")

	// Enable/Disable APIs:
	fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API")
	fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API")
	fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API")
	fs.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened")

	// Throughput Server
	throughputPort := fs.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server")
	fs.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created")

	ferr := fs.Parse(os.Args[1:])

	if ferr == flag.ErrHelp {
		// display usage/help text and exit successfully
		os.Exit(0)
	}

	if ferr != nil {
		// other type of error occurred when parsing args
		os.Exit(2)
	}

	networkID, err := genesis.NetworkID(*networkName)
	if errs.Add(err); errs.Errored() {
		return
	}

	Config.NetworkID = networkID

	// DB:
	if *db {
		*dbDir, err = homedir.Expand(*dbDir)
		if errs.Add(fmt.Errorf("couldn't resolve db path: %w", err)); err != nil {
			return
		}
		dbPath := path.Join(*dbDir, genesis.NetworkName(Config.NetworkID), dbVersion)
		db, err := leveldb.New(dbPath, 0, 0, 0)
		if errs.Add(fmt.Errorf("couldn't create db: %w", err)); err != nil {
			return
		}
		Config.DB = db
	} else {
		Config.DB = memdb.New()
	}

	Config.Nat = nat.NewRouter()

	var ip net.IP
	// If public IP is not specified, get it using shell command dig
	if *consensusIP == "" {
		ip, err = Config.Nat.IP()
		if err != nil {
			ip = net.IPv4zero // Couldn't get my IP...set to 0.0.0.0
		}
	} else {
		ip = net.ParseIP(*consensusIP)
	}

	if ip == nil {
		errs.Add(fmt.Errorf("Invalid IP Address %s", *consensusIP))
		return
	}

	Config.StakingIP = utils.IPDesc{
		IP:   ip,
		Port: uint16(*consensusPort),
	}

	// Bootstrapping:
	if *bootstrapIPs == "default" {
		*bootstrapIPs = strings.Join(GetIPs(networkID), ",")
	}
	for _, ip := range strings.Split(*bootstrapIPs, ",") {
		if ip != "" {
			addr, err := utils.ToIPDesc(ip)
			if errs.Add(fmt.Errorf("couldn't parse ip: %w", err)); err != nil {
				return
			}
			Config.BootstrapPeers = append(Config.BootstrapPeers, &node.Peer{
				IP: addr,
			})
		}
	}

	if *bootstrapIDs == "default" {
		if *bootstrapIPs == "" {
			*bootstrapIDs = ""
		} else {
			*bootstrapIDs = strings.Join(genesis.GetConfig(networkID).StakerIDs, ",")
		}
	}
	if Config.EnableStaking {
		i := 0
		cb58 := formatting.CB58{}
		for _, id := range strings.Split(*bootstrapIDs, ",") {
			if id != "" {
				err = cb58.FromString(id)
				if err != nil {
					if errs.Add(fmt.Errorf("couldn't parse bootstrap peer id to bytes: %w", err)); err != nil {
						return
					}
				}
				peerID, err := ids.ToShortID(cb58.Bytes)
				if err != nil {
					errs.Add(fmt.Errorf("couldn't parse bootstrap peer id: %w", err))
					return
				}
				if len(Config.BootstrapPeers) <= i {
					errs.Add(errBootstrapMismatch)
					return
				}
				Config.BootstrapPeers[i].ID = peerID
				i++
			}
		}
		if len(Config.BootstrapPeers) != i {
			errs.Add(fmt.Errorf("More bootstrap IPs, %d, provided than bootstrap IDs, %d", len(Config.BootstrapPeers), i))
			return
		}
	} else {
		for _, peer := range Config.BootstrapPeers {
			peer.ID = ids.NewShortID(hashing.ComputeHash160Array([]byte(peer.IP.String())))
		}
	}

	// Staking
	Config.StakingKeyFile, err = homedir.Expand(Config.StakingKeyFile)
	if err != nil {
		errs.Add(fmt.Errorf("couldn't resolve staking key path: %w", err))
		return
	}
	Config.StakingCertFile, err = homedir.Expand(Config.StakingCertFile)
	if err != nil {
		errs.Add(fmt.Errorf("couldn't resolve staking cert path: %v", err))
		return
	}
	defaultKeyPath, _ := homedir.Expand(defaultStakingKeyPath)
	defaultStakingCertPath, _ := homedir.Expand(defaultStakingCertPath)

	switch {
	// If staking key/cert locations are specified but not found, error
	case Config.StakingKeyFile != defaultKeyPath || Config.StakingCertFile != defaultStakingCertPath:
		if _, err := os.Stat(Config.StakingKeyFile); os.IsNotExist(err) {
			errs.Add(fmt.Errorf("couldn't find staking key at %s", Config.StakingKeyFile))
			return
		} else if _, err := os.Stat(Config.StakingCertFile); os.IsNotExist(err) {
			errs.Add(fmt.Errorf("couldn't find staking certificate at %s", Config.StakingCertFile))
			return
		}
	default:
		// Only creates staking key/cert if [stakingKeyPath] doesn't exist
		if err := staking.GenerateStakingKeyCert(Config.StakingKeyFile, Config.StakingCertFile); err != nil {
			errs.Add(fmt.Errorf("couldn't generate staking key/cert: %w", err))
			return
		}
	}

	// HTTP:
	Config.HTTPPort = uint16(*httpPort)

	// Logging:
	if *logsDir != "" {
		loggingConfig.Directory = *logsDir
	}
	logFileLevel, err := logging.ToLevel(*logLevel)
	if errs.Add(err); errs.Errored() {
		return
	}
	loggingConfig.LogLevel = logFileLevel

	if *logDisplayLevel == "" {
		*logDisplayLevel = *logLevel
	}
	displayLevel, err := logging.ToLevel(*logDisplayLevel)
	if errs.Add(err); errs.Errored() {
		return
	}
	loggingConfig.DisplayLevel = displayLevel

	Config.LoggingConfig = loggingConfig

	// Throughput:
	Config.ThroughputPort = uint16(*throughputPort)

	// Router used for consensus
	Config.ConsensusRouter = &router.ChainRouter{}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"flag"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"

	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/githubhook"
	"github.com/pierrre/imageserver"
	imageserver_cache "github.com/pierrre/imageserver/cache"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_graphicsmagick "github.com/pierrre/imageserver/graphicsmagick"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_graphicsmagick "github.com/pierrre/imageserver/http/graphicsmagick"
	imageserver_testdata "github.com/pierrre/imageserver/testdata"
)

func main() {
	var httpAddr string
	flag.StringVar(&httpAddr, "http", ":8080", "Http")
	var gitHubWebhookSecret string
	flag.StringVar(&gitHubWebhookSecret, "github-webhook-secret", "", "GitHub webhook secret")
	flag.Parse()

	log.Println("Start")
	log.Printf("Go version: %s", runtime.Version())
	log.Printf("Go max procs: %d", runtime.GOMAXPROCS(0))

	startHTTPServerAddr(httpAddr, gitHubWebhookSecret)
}

func startHTTPServerAddr(addr string, gitHubWebhookSecret string) {
	http.Handle("/", newImageHTTPHandler())
	if gitHubWebhookSecret != "" {
		http.Handle("/github_webhook", newGitHubWebhookHTTPHandler(gitHubWebhookSecret))
	}
	log.Printf("Start HTTP server on %s", addr)
	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Panic(err)
	}
}

func newGitHubWebhookHTTPHandler(secret string) http.Handler {
	return &githubhook.Handler{
		Secret: secret,
		Delivery: func(event string, deliveryID string, payload interface{}) {
			log.Printf("Received GitHub webhook: %s", event)
			if event == "push" {
				delay := time.Duration(5 * time.Second)
				log.Printf("Killing process in %s", delay)
				time.AfterFunc(delay, func() {
					log.Println("Killing process now")
					os.Exit(0)
				})
			}
		},
		Error: func(err error, req *http.Request) {
			log.Printf("GitHub webhook error: %s", err)
		},
	}
}

func newImageHTTPHandler() http.Handler {
	handler := http.Handler(&imageserver_http.Handler{
		Parser:   newParser(),
		Server:   newServer(),
		ETagFunc: imageserver_http.NewParamsHashETagFunc(sha256.New),
		ErrorFunc: func(err error, request *http.Request) {
			log.Println("Error:", err)
		},
	})
	handler = &imageserver_http.ExpiresHandler{
		Handler: handler,
		Expires: time.Duration(7 * 24 * time.Hour),
	}
	return handler
}

func newParser() imageserver_http.Parser {
	return &imageserver_http.ListParser{
		&imageserver_http.SourceParser{},
		&imageserver_http_graphicsmagick.Parser{},
	}
}

func newServer() imageserver.Server {
	server := newServerTestData()
	server = newServerGraphicsMagick(server)
	server = newServerLimit(server)
	server = newServerCache(server)
	return server
}

func newServerTestData() imageserver.Server {
	return imageserver_testdata.Server
}

func newServerGraphicsMagick(server imageserver.Server) imageserver.Server {
	return &imageserver_graphicsmagick.Server{
		Server:     server,
		Executable: "gm",
		Timeout:    time.Duration(10 * time.Second),
		AllowedFormats: []string{
			"jpeg",
			"png",
			"bmp",
			"gif",
		},
	}
}

func newServerLimit(server imageserver.Server) imageserver.Server {
	return imageserver.NewLimitServer(server, runtime.GOMAXPROCS(0)*2)
}

func newServerCache(server imageserver.Server) imageserver.Server {
	keyGenerator := imageserver_cache.NewParamsHashKeyGenerator(sha256.New)
	server = &imageserver_cache.Server{
		Server:       server,
		Cache:        newCacheRedis(),
		KeyGenerator: keyGenerator,
	}
	server = &imageserver_cache.Server{
		Server:       server,
		Cache:        newCacheMemory(),
		KeyGenerator: keyGenerator,
	}
	return server
}

func newCacheRedis() imageserver_cache.Cache {
	cache := imageserver_cache.Cache(&imageserver_cache_redis.Cache{
		Pool: &redigo.Pool{
			Dial: func() (redigo.Conn, error) {
				return redigo.Dial("tcp", "localhost:6379")
			},
			MaxIdle: 50,
		},
		Expire: time.Duration(7 * 24 * time.Hour),
	})
	cache = &imageserver_cache.IgnoreError{
		Cache: cache,
	}
	cache = &imageserver_cache.Async{
		Cache: cache,
	}
	return cache
}

func newCacheMemory() imageserver_cache.Cache {
	return imageserver_cache_memory.New(10 * 1024 * 1024)
}
<commit_msg>improve flag system in advanced example<commit_after>package main

import (
	"crypto/sha256"
	"flag"
	"log"
	"net/http"
	"os"
	"runtime"
	"time"

	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/githubhook"
	"github.com/pierrre/imageserver"
	imageserver_cache "github.com/pierrre/imageserver/cache"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_graphicsmagick "github.com/pierrre/imageserver/graphicsmagick"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_graphicsmagick "github.com/pierrre/imageserver/http/graphicsmagick"
	imageserver_testdata "github.com/pierrre/imageserver/testdata"
)

var (
	flagHTTPAddr            = ":8080"
	flagGitHubWebhookSecret string
	flagHTTPExpires         = time.Duration(7 * 24 * time.Hour)
	flagRedis               = "localhost:6379"
	flagRedisExpire         = time.Duration(7 * 24 * time.Hour)
	flagCacheMemory         = int64(64 * (1 << 20))
)

func main() {
	parseFlags()
	log.Println("Start")
	logEnv()
	startHTTPServer()
}

func parseFlags() {
	flag.StringVar(&flagHTTPAddr, "http", flagHTTPAddr, "HTTP addr")
	flag.DurationVar(&flagHTTPExpires, "http-expires", flagHTTPExpires, "HTTP expires")
	flag.StringVar(&flagGitHubWebhookSecret, "github-webhook-secret", "", "GitHub webhook secret")
	flag.StringVar(&flagRedis, "redis", flagRedis, "Redis addr")
	flag.DurationVar(&flagRedisExpire, "redis-expire", flagRedisExpire, "Redis expire")
	flag.Int64Var(&flagCacheMemory, "cache-memory", flagCacheMemory, "Cache memory")
	flag.Parse()
}

func logEnv() {
	log.Printf("Go version: %s", runtime.Version())
	log.Printf("Go max procs: %d", runtime.GOMAXPROCS(0))
}

func startHTTPServer() {
	http.Handle("/", newImageHTTPHandler())
	if h := newGitHubWebhookHTTPHandler(); h != nil {
		http.Handle("/github_webhook", h)
	}
	log.Printf("Start HTTP server on %s", flagHTTPAddr)
	err := http.ListenAndServe(flagHTTPAddr, nil)
	if err != nil {
		log.Panic(err)
	}
}

func newGitHubWebhookHTTPHandler() http.Handler {
	if flagGitHubWebhookSecret == "" {
		return nil
	}
	return &githubhook.Handler{
		Secret: flagGitHubWebhookSecret,
		Delivery: func(event string, deliveryID string, payload interface{}) {
			log.Printf("Received GitHub webhook: %s", event)
			if event == "push" {
				delay := time.Duration(5 * time.Second)
				log.Printf("Killing process in %s", delay)
				time.AfterFunc(delay, func() {
					log.Println("Killing process now")
					os.Exit(0)
				})
			}
		},
		Error: func(err error, req *http.Request) {
			log.Printf("GitHub webhook error: %s", err)
		},
	}
}

func newImageHTTPHandler() http.Handler {
	handler := http.Handler(&imageserver_http.Handler{
		Parser:   newParser(),
		Server:   newServer(),
		ETagFunc: imageserver_http.NewParamsHashETagFunc(sha256.New),
		ErrorFunc: func(err error, request *http.Request) {
			log.Println("Error:", err)
		},
	})
	if flagHTTPExpires != 0 {
		handler = &imageserver_http.ExpiresHandler{
			Handler: handler,
			Expires: flagHTTPExpires,
		}
	}
	return handler
}

func newParser() imageserver_http.Parser {
	return &imageserver_http.ListParser{
		&imageserver_http.SourceParser{},
		&imageserver_http_graphicsmagick.Parser{},
	}
}

func newServer() imageserver.Server {
	server := newServerTestData()
	server = newServerGraphicsMagick(server)
	server = newServerLimit(server)
	server = newServerCache(server)
	return server
}

func newServerTestData() imageserver.Server {
	return imageserver_testdata.Server
}

func newServerGraphicsMagick(server imageserver.Server) imageserver.Server {
	return &imageserver_graphicsmagick.Server{
		Server:     server,
		Executable: "gm",
		Timeout:    time.Duration(10 * time.Second),
		AllowedFormats: []string{
			"jpeg",
			"png",
			"bmp",
			"gif",
		},
	}
}

func newServerLimit(server imageserver.Server) imageserver.Server {
	return imageserver.NewLimitServer(server, runtime.GOMAXPROCS(0)*2)
}

func newServerCache(server imageserver.Server) imageserver.Server {
	keyGenerator := imageserver_cache.NewParamsHashKeyGenerator(sha256.New)
	if cache := newCacheRedis(); cache != nil {
		server = &imageserver_cache.Server{
			Server:       server,
			Cache:        cache,
			KeyGenerator: keyGenerator,
		}
	}
	if cache := newCacheMemory(); cache != nil {
		server = &imageserver_cache.Server{
			Server:       server,
			Cache:        cache,
			KeyGenerator: keyGenerator,
		}
	}
	return server
}

func newCacheRedis() imageserver_cache.Cache {
	if flagRedis == "" {
		return nil
	}
	cache := imageserver_cache.Cache(&imageserver_cache_redis.Cache{
		Pool: &redigo.Pool{
			Dial: func() (redigo.Conn, error) {
				return redigo.Dial("tcp", flagRedis)
			},
			MaxIdle: 50,
		},
		Expire: flagRedisExpire,
	})
	cache = &imageserver_cache.IgnoreError{
		Cache: cache,
	}
	cache = &imageserver_cache.Async{
		Cache: cache,
	}
	return cache
}

func newCacheMemory() imageserver_cache.Cache {
	if flagCacheMemory == 0 {
		return nil
	}
	return imageserver_cache_memory.New(flagCacheMemory)
}
<|endoftext|>


<commit_before>// +build !js

package webrtc

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pion/rtp"
	"github.com/pion/rtp/codecs"
	"github.com/pion/sdp/v2"
)

// PayloadTypes for the default codecs
const (
	DefaultPayloadTypePCMU = 0
	DefaultPayloadTypePCMA = 8
	DefaultPayloadTypeG722 = 9
	DefaultPayloadTypeOpus = 111
	DefaultPayloadTypeVP8  = 96
	DefaultPayloadTypeVP9  = 98
	DefaultPayloadTypeH264 = 102

	mediaNameAudio = "audio"
	mediaNameVideo = "video"
)

// A MediaEngine defines the codecs supported by a PeerConnection.
// MediaEngines populated using RegisterCodec (and RegisterDefaultCodecs)
// may be set up once and reused, including concurrently,
// as long as no other codecs are added subsequently.
// MediaEngines populated using PopulateFromSDP should be used
// only for that session.
type MediaEngine struct {
	codecs []*RTPCodec
}

// RegisterCodec adds codec to m.
// RegisterCodec is not safe for concurrent use.
func (m *MediaEngine) RegisterCodec(codec *RTPCodec) uint8 {
	// TODO: dynamically generate a payload type in the range 96-127 if one wasn't provided.
	// See https://github.com/pion/webrtc/issues/43
	m.codecs = append(m.codecs, codec)
	return codec.PayloadType
}

// RegisterDefaultCodecs registers the default codecs supported by Pion WebRTC.
// RegisterDefaultCodecs is not safe for concurrent use.
func (m *MediaEngine) RegisterDefaultCodecs() {
	// Audio Codecs in descending order of preference
	m.RegisterCodec(NewRTPOpusCodec(DefaultPayloadTypeOpus, 48000))
	m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000))
	m.RegisterCodec(NewRTPPCMACodec(DefaultPayloadTypePCMA, 8000))
	m.RegisterCodec(NewRTPG722Codec(DefaultPayloadTypeG722, 8000))

	// Video Codecs in descending order of preference
	m.RegisterCodec(NewRTPVP8Codec(DefaultPayloadTypeVP8, 90000))
	m.RegisterCodec(NewRTPVP9Codec(DefaultPayloadTypeVP9, 90000))
	m.RegisterCodec(NewRTPH264Codec(DefaultPayloadTypeH264, 90000))
}

// PopulateFromSDP finds all codecs in sd and adds them to m, using the dynamic
// payload types and parameters from sd.
// PopulateFromSDP is intended for use when answering a request.
// The offerer sets the PayloadTypes for the connection.
// PopulateFromSDP allows an answerer to properly match the PayloadTypes from the offerer.
// A MediaEngine populated by PopulateFromSDP should be used only for a single session.
func (m *MediaEngine) PopulateFromSDP(sd SessionDescription) error {
	sdp := sdp.SessionDescription{}
	if err := sdp.Unmarshal([]byte(sd.SDP)); err != nil {
		return err
	}

	for _, md := range sdp.MediaDescriptions {
		if md.MediaName.Media != mediaNameAudio && md.MediaName.Media != mediaNameVideo {
			continue
		}

		for _, format := range md.MediaName.Formats {
			pt, err := strconv.Atoi(format)
			if err != nil {
				return fmt.Errorf("format parse error")
			}

			payloadType := uint8(pt)
			payloadCodec, err := sdp.GetCodecForPayloadType(payloadType)
			if err != nil {
				return fmt.Errorf("could not find codec for payload type %d", payloadType)
			}

			var codec *RTPCodec
			switch {
			case strings.EqualFold(payloadCodec.Name, PCMA):
				codec = NewRTPPCMACodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, PCMU):
				codec = NewRTPPCMUCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, G722):
				codec = NewRTPG722Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, Opus):
				codec = NewRTPOpusCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP8):
				codec = NewRTPVP8Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP9):
				codec = NewRTPVP9Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, H264):
				codec = NewRTPH264Codec(payloadType, payloadCodec.ClockRate)
			default:
				// ignoring other codecs
				continue
			}

			codec.SDPFmtpLine = payloadCodec.Fmtp
			m.RegisterCodec(codec)
		}
	}
	return nil
}

func (m *MediaEngine) getCodec(payloadType uint8) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.PayloadType == payloadType {
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

func (m *MediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.Name == sdpCodec.Name &&
			codec.ClockRate == sdpCodec.ClockRate &&
			(sdpCodec.EncodingParameters == "" ||
				strconv.Itoa(int(codec.Channels)) == sdpCodec.EncodingParameters) &&
			codec.SDPFmtpLine == sdpCodec.Fmtp { // pion/webrtc#43
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

// GetCodecsByKind returns all codecs of kind kind that are supported by m.
// The returned codecs should not be modified.
func (m *MediaEngine) GetCodecsByKind(kind RTPCodecType) []*RTPCodec {
	var codecs []*RTPCodec
	for _, codec := range m.codecs {
		if codec.Type == kind {
			// TODO: clone the codec for safety?
			codecs = append(codecs, codec)
		}
	}
	return codecs
}

// Names for the default codecs supported by Pion WebRTC
const (
	PCMU = "PCMU"
	PCMA = "PCMA"
	G722 = "G722"
	Opus = "opus"
	VP8  = "VP8"
	VP9  = "VP9"
	H264 = "H264"
)

// NewRTPPCMUCodec is a helper to create a PCMU codec
func NewRTPPCMUCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMU,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPPCMACodec is a helper to create a PCMA codec
func NewRTPPCMACodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMA,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPG722Codec is a helper to create a G722 codec
func NewRTPG722Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		G722,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G722Payloader{})
	return c
}

// NewRTPOpusCodec is a helper to create an Opus codec
func NewRTPOpusCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		Opus,
		clockrate,
		2, //According to RFC7587, Opus RTP streams must have exactly 2 channels.
		"minptime=10;useinbandfec=1",
		payloadType,
		&codecs.OpusPayloader{})
	return c
}

// NewRTPVP8Codec is a helper to create an VP8 codec
func NewRTPVP8Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP8CodecExt is a helper to create an VP8 codec
func NewRTPVP8CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP9Codec is a helper to create an VP9 codec
func NewRTPVP9Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP9,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP9Payloader{})
	return c
}

// NewRTPH264Codec is a helper to create an H264 codec
func NewRTPH264Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		"level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
		payloadType,
		&codecs.H264Payloader{})
	return c
}

// NewRTPH264CodecExt is a helper to create an H264 codec
func NewRTPH264CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.H264Payloader{})
	return c
}

// RTPCodecType determines the type of a codec
type RTPCodecType int

const (

	// RTPCodecTypeAudio indicates this is an audio codec
	RTPCodecTypeAudio RTPCodecType = iota + 1

	// RTPCodecTypeVideo indicates this is a video codec
	RTPCodecTypeVideo
)

func (t RTPCodecType) String() string {
	switch t {
	case RTPCodecTypeAudio:
		return "audio"
	case RTPCodecTypeVideo:
		return "video"
	default:
		return ErrUnknownType.Error()
	}
}

// NewRTPCodecType creates a RTPCodecType from a string
func NewRTPCodecType(r string) RTPCodecType {
	switch {
	case strings.EqualFold(r, "audio"):
		return RTPCodecTypeAudio
	case strings.EqualFold(r, "video"):
		return RTPCodecTypeVideo
	default:
		return RTPCodecType(0)
	}
}

// RTPCodec represents a codec supported by the PeerConnection
type RTPCodec struct {
	RTPCodecCapability
	Type        RTPCodecType
	Name        string
	PayloadType uint8
	Payloader   rtp.Payloader
}

// NewRTPCodec is used to define a new codec
func NewRTPCodec(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:    codecType.String() + "/" + name,
			ClockRate:   clockrate,
			Channels:    channels,
			SDPFmtpLine: fmtp,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// NewRTPCodecExt is used to define a new codec
func NewRTPCodecExt(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	rtcpfb []RTCPFeedback,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:     codecType.String() + "/" + name,
			ClockRate:    clockrate,
			Channels:     channels,
			SDPFmtpLine:  fmtp,
			RTCPFeedback: rtcpfb,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// RTPCodecCapability provides information about codec capabilities.
type RTPCodecCapability struct {
	MimeType     string
	ClockRate    uint32
	Channels     uint16
	SDPFmtpLine  string
	RTCPFeedback []RTCPFeedback
}

// RTPHeaderExtensionCapability is used to define a RFC5285 RTP header extension supported by the codec.
type RTPHeaderExtensionCapability struct {
	URI string
}

// RTPCapabilities represents the capabilities of a transceiver
type RTPCapabilities struct {
	Codecs           []RTPCodecCapability
	HeaderExtensions []RTPHeaderExtensionCapability
}
<commit_msg>Implement NewRTPVP9CodecExt<commit_after>// +build !js

package webrtc

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pion/rtp"
	"github.com/pion/rtp/codecs"
	"github.com/pion/sdp/v2"
)

// PayloadTypes for the default codecs
const (
	DefaultPayloadTypePCMU = 0
	DefaultPayloadTypePCMA = 8
	DefaultPayloadTypeG722 = 9
	DefaultPayloadTypeOpus = 111
	DefaultPayloadTypeVP8  = 96
	DefaultPayloadTypeVP9  = 98
	DefaultPayloadTypeH264 = 102

	mediaNameAudio = "audio"
	mediaNameVideo = "video"
)

// A MediaEngine defines the codecs supported by a PeerConnection.
// MediaEngines populated using RegisterCodec (and RegisterDefaultCodecs)
// may be set up once and reused, including concurrently,
// as long as no other codecs are added subsequently.
// MediaEngines populated using PopulateFromSDP should be used
// only for that session.
type MediaEngine struct {
	codecs []*RTPCodec
}

// RegisterCodec adds codec to m.
// RegisterCodec is not safe for concurrent use.
func (m *MediaEngine) RegisterCodec(codec *RTPCodec) uint8 {
	// TODO: dynamically generate a payload type in the range 96-127 if one wasn't provided.
	// See https://github.com/pion/webrtc/issues/43
	m.codecs = append(m.codecs, codec)
	return codec.PayloadType
}

// RegisterDefaultCodecs registers the default codecs supported by Pion WebRTC.
// RegisterDefaultCodecs is not safe for concurrent use.
func (m *MediaEngine) RegisterDefaultCodecs() {
	// Audio Codecs in descending order of preference
	m.RegisterCodec(NewRTPOpusCodec(DefaultPayloadTypeOpus, 48000))
	m.RegisterCodec(NewRTPPCMUCodec(DefaultPayloadTypePCMU, 8000))
	m.RegisterCodec(NewRTPPCMACodec(DefaultPayloadTypePCMA, 8000))
	m.RegisterCodec(NewRTPG722Codec(DefaultPayloadTypeG722, 8000))

	// Video Codecs in descending order of preference
	m.RegisterCodec(NewRTPVP8Codec(DefaultPayloadTypeVP8, 90000))
	m.RegisterCodec(NewRTPVP9Codec(DefaultPayloadTypeVP9, 90000))
	m.RegisterCodec(NewRTPH264Codec(DefaultPayloadTypeH264, 90000))
}

// PopulateFromSDP finds all codecs in sd and adds them to m, using the dynamic
// payload types and parameters from sd.
// PopulateFromSDP is intended for use when answering a request.
// The offerer sets the PayloadTypes for the connection.
// PopulateFromSDP allows an answerer to properly match the PayloadTypes from the offerer.
// A MediaEngine populated by PopulateFromSDP should be used only for a single session.
func (m *MediaEngine) PopulateFromSDP(sd SessionDescription) error {
	sdp := sdp.SessionDescription{}
	if err := sdp.Unmarshal([]byte(sd.SDP)); err != nil {
		return err
	}

	for _, md := range sdp.MediaDescriptions {
		if md.MediaName.Media != mediaNameAudio && md.MediaName.Media != mediaNameVideo {
			continue
		}

		for _, format := range md.MediaName.Formats {
			pt, err := strconv.Atoi(format)
			if err != nil {
				return fmt.Errorf("format parse error")
			}

			payloadType := uint8(pt)
			payloadCodec, err := sdp.GetCodecForPayloadType(payloadType)
			if err != nil {
				return fmt.Errorf("could not find codec for payload type %d", payloadType)
			}

			var codec *RTPCodec
			switch {
			case strings.EqualFold(payloadCodec.Name, PCMA):
				codec = NewRTPPCMACodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, PCMU):
				codec = NewRTPPCMUCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, G722):
				codec = NewRTPG722Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, Opus):
				codec = NewRTPOpusCodec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP8):
				codec = NewRTPVP8Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, VP9):
				codec = NewRTPVP9Codec(payloadType, payloadCodec.ClockRate)
			case strings.EqualFold(payloadCodec.Name, H264):
				codec = NewRTPH264Codec(payloadType, payloadCodec.ClockRate)
			default:
				// ignoring other codecs
				continue
			}

			codec.SDPFmtpLine = payloadCodec.Fmtp
			m.RegisterCodec(codec)
		}
	}
	return nil
}

func (m *MediaEngine) getCodec(payloadType uint8) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.PayloadType == payloadType {
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

func (m *MediaEngine) getCodecSDP(sdpCodec sdp.Codec) (*RTPCodec, error) {
	for _, codec := range m.codecs {
		if codec.Name == sdpCodec.Name &&
			codec.ClockRate == sdpCodec.ClockRate &&
			(sdpCodec.EncodingParameters == "" ||
				strconv.Itoa(int(codec.Channels)) == sdpCodec.EncodingParameters) &&
			codec.SDPFmtpLine == sdpCodec.Fmtp { // pion/webrtc#43
			return codec, nil
		}
	}
	return nil, ErrCodecNotFound
}

// GetCodecsByKind returns all codecs of kind kind that are supported by m.
// The returned codecs should not be modified.
func (m *MediaEngine) GetCodecsByKind(kind RTPCodecType) []*RTPCodec {
	var codecs []*RTPCodec
	for _, codec := range m.codecs {
		if codec.Type == kind {
			// TODO: clone the codec for safety?
			codecs = append(codecs, codec)
		}
	}
	return codecs
}

// Names for the default codecs supported by Pion WebRTC
const (
	PCMU = "PCMU"
	PCMA = "PCMA"
	G722 = "G722"
	Opus = "opus"
	VP8  = "VP8"
	VP9  = "VP9"
	H264 = "H264"
)

// NewRTPPCMUCodec is a helper to create a PCMU codec
func NewRTPPCMUCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMU,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPPCMACodec is a helper to create a PCMA codec
func NewRTPPCMACodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		PCMA,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G711Payloader{})
	return c
}

// NewRTPG722Codec is a helper to create a G722 codec
func NewRTPG722Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		G722,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.G722Payloader{})
	return c
}

// NewRTPOpusCodec is a helper to create an Opus codec
func NewRTPOpusCodec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeAudio,
		Opus,
		clockrate,
		2, //According to RFC7587, Opus RTP streams must have exactly 2 channels.
		"minptime=10;useinbandfec=1",
		payloadType,
		&codecs.OpusPayloader{})
	return c
}

// NewRTPVP8Codec is a helper to create an VP8 codec
func NewRTPVP8Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP8CodecExt is a helper to create an VP8 codec
func NewRTPVP8CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		VP8,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.VP8Payloader{})
	return c
}

// NewRTPVP9Codec is a helper to create an VP9 codec
func NewRTPVP9Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		VP9,
		clockrate,
		0,
		"",
		payloadType,
		&codecs.VP9Payloader{})
	return c
}

// NewRTPVP9CodecExt is a helper to create an VP8 codec
func NewRTPVP9CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		VP9,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.VP9Payloader{})
	return c
}

// NewRTPH264Codec is a helper to create an H264 codec
func NewRTPH264Codec(payloadType uint8, clockrate uint32) *RTPCodec {
	c := NewRTPCodec(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		"level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
		payloadType,
		&codecs.H264Payloader{})
	return c
}

// NewRTPH264CodecExt is a helper to create an H264 codec
func NewRTPH264CodecExt(payloadType uint8, clockrate uint32, rtcpfb []RTCPFeedback, fmtp string) *RTPCodec {
	c := NewRTPCodecExt(RTPCodecTypeVideo,
		H264,
		clockrate,
		0,
		fmtp,
		payloadType,
		rtcpfb,
		&codecs.H264Payloader{})
	return c
}

// RTPCodecType determines the type of a codec
type RTPCodecType int

const (

	// RTPCodecTypeAudio indicates this is an audio codec
	RTPCodecTypeAudio RTPCodecType = iota + 1

	// RTPCodecTypeVideo indicates this is a video codec
	RTPCodecTypeVideo
)

func (t RTPCodecType) String() string {
	switch t {
	case RTPCodecTypeAudio:
		return "audio"
	case RTPCodecTypeVideo:
		return "video"
	default:
		return ErrUnknownType.Error()
	}
}

// NewRTPCodecType creates a RTPCodecType from a string
func NewRTPCodecType(r string) RTPCodecType {
	switch {
	case strings.EqualFold(r, "audio"):
		return RTPCodecTypeAudio
	case strings.EqualFold(r, "video"):
		return RTPCodecTypeVideo
	default:
		return RTPCodecType(0)
	}
}

// RTPCodec represents a codec supported by the PeerConnection
type RTPCodec struct {
	RTPCodecCapability
	Type        RTPCodecType
	Name        string
	PayloadType uint8
	Payloader   rtp.Payloader
}

// NewRTPCodec is used to define a new codec
func NewRTPCodec(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:    codecType.String() + "/" + name,
			ClockRate:   clockrate,
			Channels:    channels,
			SDPFmtpLine: fmtp,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// NewRTPCodecExt is used to define a new codec
func NewRTPCodecExt(
	codecType RTPCodecType,
	name string,
	clockrate uint32,
	channels uint16,
	fmtp string,
	payloadType uint8,
	rtcpfb []RTCPFeedback,
	payloader rtp.Payloader,
) *RTPCodec {
	return &RTPCodec{
		RTPCodecCapability: RTPCodecCapability{
			MimeType:     codecType.String() + "/" + name,
			ClockRate:    clockrate,
			Channels:     channels,
			SDPFmtpLine:  fmtp,
			RTCPFeedback: rtcpfb,
		},
		PayloadType: payloadType,
		Payloader:   payloader,
		Type:        codecType,
		Name:        name,
	}
}

// RTPCodecCapability provides information about codec capabilities.
type RTPCodecCapability struct {
	MimeType     string
	ClockRate    uint32
	Channels     uint16
	SDPFmtpLine  string
	RTCPFeedback []RTCPFeedback
}

// RTPHeaderExtensionCapability is used to define a RFC5285 RTP header extension supported by the codec.
type RTPHeaderExtensionCapability struct {
	URI string
}

// RTPCapabilities represents the capabilities of a transceiver
type RTPCapabilities struct {
	Codecs           []RTPCodecCapability
	HeaderExtensions []RTPHeaderExtensionCapability
}
<|endoftext|>


<commit_before>package ethereal

import (
	"encoding/json"
	"fmt"
	"github.com/justinas/alice"
	"log"
	"net/http"
)

/**
/ Add middleware in App under certain condition..
*/
type AddMiddleware interface {
	Add(*[]alice.Constructor, *Application)
}

type Middleware struct {
	// all middleware
	allMiddleware []AddMiddleware
	// middleware only included in application
	includeMiddleware []alice.Constructor
}

func (m Middleware) AddMiddleware(middleware ...AddMiddleware) {
	m.allMiddleware = append(m.allMiddleware, middleware...)
}

// Method loading middleware for application
func (m *Middleware) LoadApplication(application *Application) []alice.Constructor {
	for _, middleware := range m.allMiddleware {
		middleware.Add(&m.includeMiddleware, application)
	}
	return m.includeMiddleware
}

/**
/ ability to set jwt token all queries or choose query
*/
type middlewareJWTToken struct {
	jwt            EtherealClaims
	statusError    int
	responseError  string
	authenticated  bool
	responseWriter http.ResponseWriter
	included       bool // flag is enabled or disabled authJwtToken
}

func (m middlewareJWTToken) Add(where *[]alice.Constructor, application *Application) {
	confToken := config("AUTH.JWT_TOKEN").(string)

	if confToken == "local" {
		m.included = true
		*where = append(*where, func(handler http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				m.responseWriter = w
				if check, err := m.jwt.Verify(r); !check {
					m.responseError = handlerErrorToken(err).Error()
				} else {
					m.authenticated = true
				}
				ctxStruct(application, m)
				handler.ServeHTTP(w, r)
			})
		})
	} else if confToken == "global" {
		// check jwt token all queries..
		*where = append(*where, func(handler http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				fmt.Println("working")
				if check, err := m.jwt.Verify(r); !check {
					json.NewEncoder(w).Encode(handlerErrorToken(err).Error())
					w.WriteHeader(m.statusError)
				}
			})
		})
	} else {
		log.Println("Our config parameter AUTH.JWT_TOKEN = " + confToken)
	}
}

// ---- waiting for your implementation ------

// middleware set Accept-Language
func middlewareLocal(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// TODO Pipline choose
		// TODO set locale from request
		//app.Locale = parserLocale(r.Header["Accept-Language"])
		next.ServeHTTP(w, r)
	})
}
<commit_msg>small chamge<commit_after>package ethereal

import (
	"encoding/json"
	"github.com/justinas/alice"
	"net/http"
)

/**
/ Add middleware in App under certain condition..
*/
type AddMiddleware interface {
	Add(*[]alice.Constructor, *Application)
}

type Middleware struct {
	// all middleware
	allMiddleware []AddMiddleware
	// middleware only included in application
	includeMiddleware []alice.Constructor
}

func (m Middleware) AddMiddleware(middleware ...AddMiddleware) {
	m.allMiddleware = append(m.allMiddleware, middleware...)
}

// Method loading middleware for application
func (m *Middleware) LoadApplication(application *Application) []alice.Constructor {
	for _, middleware := range m.allMiddleware {
		middleware.Add(&m.includeMiddleware, application)
	}
	return m.includeMiddleware
}

/**
/ ability to set jwt token all queries or choose query
*/
type middlewareJWTToken struct {
	jwt            EtherealClaims
	statusError    int
	responseError  string
	authenticated  bool
	responseWriter http.ResponseWriter
	included       bool // flag is enabled or disabled authJwtToken
}

func (m middlewareJWTToken) Add(where *[]alice.Constructor, application *Application) {
	confToken := config("AUTH.JWT_TOKEN").(string)

	if confToken == "local" {
		m.included = true
		*where = append(*where, func(handler http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				m.responseWriter = w
				if check, err := m.jwt.Verify(r); !check {
					m.responseError = handlerErrorToken(err).Error()
				} else {
					m.authenticated = true
				}
				ctxStruct(application, m)
				handler.ServeHTTP(w, r)
			})
		})
	} else if confToken == "global" {
		// check jwt token all queries..
		*where = append(*where, func(handler http.Handler) http.Handler {
			return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				if check, err := m.jwt.Verify(r); !check {
					json.NewEncoder(w).Encode(handlerErrorToken(err).Error())
					w.WriteHeader(m.statusError)
				}
			})
		})
	}
}

// ---- waiting for your implementation ------

// middleware set Accept-Language
func middlewareLocal(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// TODO Pipline choose
		// TODO set locale from request
		//app.Locale = parserLocale(r.Header["Accept-Language"])
		next.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>package handler

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/goharbor/harbor/src/lib/config"
	"os"
	"strings"

	"github.com/go-openapi/runtime/middleware"
	"github.com/goharbor/harbor/src/common/rbac"
	"github.com/goharbor/harbor/src/controller/gc"
	"github.com/goharbor/harbor/src/lib/errors"
	"github.com/goharbor/harbor/src/lib/q"
	"github.com/goharbor/harbor/src/pkg/task"
	"github.com/goharbor/harbor/src/server/v2.0/handler/model"
	"github.com/goharbor/harbor/src/server/v2.0/models"
	operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/gc"
)

type gcAPI struct {
	BaseAPI
	gcCtr gc.Controller
}

func newGCAPI() *gcAPI {
	return &gcAPI{
		gcCtr: gc.NewController(),
	}
}

func (g *gcAPI) Prepare(ctx context.Context, operation string, params interface{}) middleware.Responder {
	return nil
}

func (g *gcAPI) CreateGCSchedule(ctx context.Context, params operation.CreateGCScheduleParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionCreate, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	id, err := g.kick(ctx, params.Schedule.Schedule.Type, params.Schedule.Schedule.Cron, params.Schedule.Parameters)
	if err != nil {
		return g.SendError(ctx, err)
	}
	// replace the /api/v2.0/system/gc/schedule/{id} to /api/v2.0/system/gc/{id}
	lastSlashIndex := strings.LastIndex(params.HTTPRequest.URL.Path, "/")
	if lastSlashIndex != -1 {
		location := fmt.Sprintf("%s/%d", params.HTTPRequest.URL.Path[:lastSlashIndex], id)
		return operation.NewCreateGCScheduleCreated().WithLocation(location)
	}
	return operation.NewCreateGCScheduleCreated()
}

func (g *gcAPI) UpdateGCSchedule(ctx context.Context, params operation.UpdateGCScheduleParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionUpdate, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	_, err := g.kick(ctx, params.Schedule.Schedule.Type, params.Schedule.Schedule.Cron, params.Schedule.Parameters)
	if err != nil {
		return g.SendError(ctx, err)
	}
	return operation.NewUpdateGCScheduleOK()
}

func (g *gcAPI) kick(ctx context.Context, scheType string, cron string, parameters map[string]interface{}) (int64, error) {
	// set the required parameters for GC
	parameters["redis_url_reg"] = os.Getenv("_REDIS_URL_REG")
	parameters["time_window"] = config.GetGCTimeWindow()

	var err error
	var id int64
	switch scheType {
	case ScheduleManual:
		policy := gc.Policy{
			ExtraAttrs: parameters,
		}
		if dryRun, ok := parameters["dry_run"].(bool); ok {
			policy.DryRun = dryRun
		}
		if deleteUntagged, ok := parameters["delete_untagged"].(bool); ok {
			policy.DeleteUntagged = deleteUntagged
		}
		id, err = g.gcCtr.Start(ctx, policy, task.ExecutionTriggerManual)
	case ScheduleNone:
		err = g.gcCtr.DeleteSchedule(ctx)
	case ScheduleHourly, ScheduleDaily, ScheduleWeekly, ScheduleCustom:
		policy := gc.Policy{
			ExtraAttrs: parameters,
		}
		if dryRun, ok := parameters["dry_run"].(bool); ok {
			policy.DryRun = dryRun
		}
		if deleteUntagged, ok := parameters["delete_untagged"].(bool); ok {
			policy.DeleteUntagged = deleteUntagged
		}
		err = g.updateSchedule(ctx, scheType, cron, policy)
	}
	return id, err
}

func (g *gcAPI) createSchedule(ctx context.Context, cronType, cron string, policy gc.Policy) error {
	if cron == "" {
		return errors.New(nil).WithCode(errors.BadRequestCode).
			WithMessage("empty cron string for gc schedule")
	}
	_, err := g.gcCtr.CreateSchedule(ctx, cronType, cron, policy)
	if err != nil {
		return err
	}
	return nil
}

func (g *gcAPI) updateSchedule(ctx context.Context, cronType, cron string, policy gc.Policy) error {
	if err := g.gcCtr.DeleteSchedule(ctx); err != nil {
		return err
	}
	return g.createSchedule(ctx, cronType, cron, policy)
}

func (g *gcAPI) GetGCSchedule(ctx context.Context, params operation.GetGCScheduleParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	schedule, err := g.gcCtr.GetSchedule(ctx)
	if errors.IsNotFoundErr(err) {
		return operation.NewGetGCScheduleOK()
	}
	if err != nil {
		return g.SendError(ctx, err)
	}

	return operation.NewGetGCScheduleOK().WithPayload(model.NewGCSchedule(schedule).ToSwagger())
}

func (g *gcAPI) GetGCHistory(ctx context.Context, params operation.GetGCHistoryParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	query, err := g.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
	if err != nil {
		return g.SendError(ctx, err)
	}
	total, err := g.gcCtr.ExecutionCount(ctx, query)
	if err != nil {
		return g.SendError(ctx, err)
	}
	execs, err := g.gcCtr.ListExecutions(ctx, query)
	if err != nil {
		return g.SendError(ctx, err)
	}

	var hs []*model.GCHistory
	for _, exec := range execs {
		extraAttrsString, err := json.Marshal(exec.ExtraAttrs)
		if err != nil {
			return g.SendError(ctx, err)
		}
		hs = append(hs, &model.GCHistory{
			ID:         exec.ID,
			Name:       gc.GCVendorType,
			Kind:       exec.Trigger,
			Parameters: string(extraAttrsString),
			Schedule: &model.ScheduleParam{
				Type: exec.Trigger,
			},
			Status:       exec.Status,
			CreationTime: exec.StartTime,
			UpdateTime:   exec.EndTime,
		})
	}

	var results []*models.GCHistory
	for _, h := range hs {
		results = append(results, h.ToSwagger())
	}

	return operation.NewGetGCHistoryOK().
		WithXTotalCount(total).
		WithLink(g.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
		WithPayload(results)
}

func (g *gcAPI) GetGC(ctx context.Context, params operation.GetGCParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	exec, err := g.gcCtr.GetExecution(ctx, params.GCID)
	if err != nil {
		return g.SendError(ctx, err)
	}

	extraAttrsString, err := json.Marshal(exec.ExtraAttrs)
	if err != nil {
		return g.SendError(ctx, err)
	}

	res := &model.GCHistory{
		ID:         exec.ID,
		Name:       gc.GCVendorType,
		Kind:       exec.Trigger,
		Parameters: string(extraAttrsString),
		Status:     exec.Status,
		Schedule: &model.ScheduleParam{
			Type: exec.Trigger,
		},
		CreationTime: exec.StartTime,
		UpdateTime:   exec.EndTime,
	}

	return operation.NewGetGCOK().WithPayload(res.ToSwagger())
}

func (g *gcAPI) GetGCLog(ctx context.Context, params operation.GetGCLogParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	tasks, err := g.gcCtr.ListTasks(ctx, q.New(q.KeyWords{
		"ExecutionID": params.GCID,
	}))
	if err != nil {
		return g.SendError(ctx, err)
	}
	if len(tasks) == 0 {
		return g.SendError(ctx, errors.New(nil).WithCode(errors.NotFoundCode).WithMessage("garbage collection %d log is not found", params.GCID))
	}
	log, err := g.gcCtr.GetTaskLog(ctx, tasks[0].ID)
	if err != nil {
		return g.SendError(ctx, err)
	}
	return operation.NewGetGCLogOK().WithPayload(string(log))
}
<commit_msg>fix nil map assignment in gc handler (#14918)<commit_after>package handler

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/goharbor/harbor/src/lib/config"
	"os"
	"strings"

	"github.com/go-openapi/runtime/middleware"
	"github.com/goharbor/harbor/src/common/rbac"
	"github.com/goharbor/harbor/src/controller/gc"
	"github.com/goharbor/harbor/src/lib/errors"
	"github.com/goharbor/harbor/src/lib/q"
	"github.com/goharbor/harbor/src/pkg/task"
	"github.com/goharbor/harbor/src/server/v2.0/handler/model"
	"github.com/goharbor/harbor/src/server/v2.0/models"
	operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/gc"
)

type gcAPI struct {
	BaseAPI
	gcCtr gc.Controller
}

func newGCAPI() *gcAPI {
	return &gcAPI{
		gcCtr: gc.NewController(),
	}
}

func (g *gcAPI) Prepare(ctx context.Context, operation string, params interface{}) middleware.Responder {
	return nil
}

func (g *gcAPI) CreateGCSchedule(ctx context.Context, params operation.CreateGCScheduleParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionCreate, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	id, err := g.kick(ctx, params.Schedule.Schedule.Type, params.Schedule.Schedule.Cron, params.Schedule.Parameters)
	if err != nil {
		return g.SendError(ctx, err)
	}
	// replace the /api/v2.0/system/gc/schedule/{id} to /api/v2.0/system/gc/{id}
	lastSlashIndex := strings.LastIndex(params.HTTPRequest.URL.Path, "/")
	if lastSlashIndex != -1 {
		location := fmt.Sprintf("%s/%d", params.HTTPRequest.URL.Path[:lastSlashIndex], id)
		return operation.NewCreateGCScheduleCreated().WithLocation(location)
	}
	return operation.NewCreateGCScheduleCreated()
}

func (g *gcAPI) UpdateGCSchedule(ctx context.Context, params operation.UpdateGCScheduleParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionUpdate, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	_, err := g.kick(ctx, params.Schedule.Schedule.Type, params.Schedule.Schedule.Cron, params.Schedule.Parameters)
	if err != nil {
		return g.SendError(ctx, err)
	}
	return operation.NewUpdateGCScheduleOK()
}

func (g *gcAPI) kick(ctx context.Context, scheType string, cron string, parameters map[string]interface{}) (int64, error) {
	if parameters == nil {
		parameters = make(map[string]interface{})
	}
	// set the required parameters for GC
	parameters["redis_url_reg"] = os.Getenv("_REDIS_URL_REG")
	parameters["time_window"] = config.GetGCTimeWindow()

	var err error
	var id int64
	switch scheType {
	case ScheduleManual:
		policy := gc.Policy{
			ExtraAttrs: parameters,
		}
		if dryRun, ok := parameters["dry_run"].(bool); ok {
			policy.DryRun = dryRun
		}
		if deleteUntagged, ok := parameters["delete_untagged"].(bool); ok {
			policy.DeleteUntagged = deleteUntagged
		}
		id, err = g.gcCtr.Start(ctx, policy, task.ExecutionTriggerManual)
	case ScheduleNone:
		err = g.gcCtr.DeleteSchedule(ctx)
	case ScheduleHourly, ScheduleDaily, ScheduleWeekly, ScheduleCustom:
		policy := gc.Policy{
			ExtraAttrs: parameters,
		}
		if dryRun, ok := parameters["dry_run"].(bool); ok {
			policy.DryRun = dryRun
		}
		if deleteUntagged, ok := parameters["delete_untagged"].(bool); ok {
			policy.DeleteUntagged = deleteUntagged
		}
		err = g.updateSchedule(ctx, scheType, cron, policy)
	}
	return id, err
}

func (g *gcAPI) createSchedule(ctx context.Context, cronType, cron string, policy gc.Policy) error {
	if cron == "" {
		return errors.New(nil).WithCode(errors.BadRequestCode).
			WithMessage("empty cron string for gc schedule")
	}
	_, err := g.gcCtr.CreateSchedule(ctx, cronType, cron, policy)
	if err != nil {
		return err
	}
	return nil
}

func (g *gcAPI) updateSchedule(ctx context.Context, cronType, cron string, policy gc.Policy) error {
	if err := g.gcCtr.DeleteSchedule(ctx); err != nil {
		return err
	}
	return g.createSchedule(ctx, cronType, cron, policy)
}

func (g *gcAPI) GetGCSchedule(ctx context.Context, params operation.GetGCScheduleParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	schedule, err := g.gcCtr.GetSchedule(ctx)
	if errors.IsNotFoundErr(err) {
		return operation.NewGetGCScheduleOK()
	}
	if err != nil {
		return g.SendError(ctx, err)
	}

	return operation.NewGetGCScheduleOK().WithPayload(model.NewGCSchedule(schedule).ToSwagger())
}

func (g *gcAPI) GetGCHistory(ctx context.Context, params operation.GetGCHistoryParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionList, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	query, err := g.BuildQuery(ctx, params.Q, params.Sort, params.Page, params.PageSize)
	if err != nil {
		return g.SendError(ctx, err)
	}
	total, err := g.gcCtr.ExecutionCount(ctx, query)
	if err != nil {
		return g.SendError(ctx, err)
	}
	execs, err := g.gcCtr.ListExecutions(ctx, query)
	if err != nil {
		return g.SendError(ctx, err)
	}

	var hs []*model.GCHistory
	for _, exec := range execs {
		extraAttrsString, err := json.Marshal(exec.ExtraAttrs)
		if err != nil {
			return g.SendError(ctx, err)
		}
		hs = append(hs, &model.GCHistory{
			ID:         exec.ID,
			Name:       gc.GCVendorType,
			Kind:       exec.Trigger,
			Parameters: string(extraAttrsString),
			Schedule: &model.ScheduleParam{
				Type: exec.Trigger,
			},
			Status:       exec.Status,
			CreationTime: exec.StartTime,
			UpdateTime:   exec.EndTime,
		})
	}

	var results []*models.GCHistory
	for _, h := range hs {
		results = append(results, h.ToSwagger())
	}

	return operation.NewGetGCHistoryOK().
		WithXTotalCount(total).
		WithLink(g.Links(ctx, params.HTTPRequest.URL, total, query.PageNumber, query.PageSize).String()).
		WithPayload(results)
}

func (g *gcAPI) GetGC(ctx context.Context, params operation.GetGCParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	exec, err := g.gcCtr.GetExecution(ctx, params.GCID)
	if err != nil {
		return g.SendError(ctx, err)
	}

	extraAttrsString, err := json.Marshal(exec.ExtraAttrs)
	if err != nil {
		return g.SendError(ctx, err)
	}

	res := &model.GCHistory{
		ID:         exec.ID,
		Name:       gc.GCVendorType,
		Kind:       exec.Trigger,
		Parameters: string(extraAttrsString),
		Status:     exec.Status,
		Schedule: &model.ScheduleParam{
			Type: exec.Trigger,
		},
		CreationTime: exec.StartTime,
		UpdateTime:   exec.EndTime,
	}

	return operation.NewGetGCOK().WithPayload(res.ToSwagger())
}

func (g *gcAPI) GetGCLog(ctx context.Context, params operation.GetGCLogParams) middleware.Responder {
	if err := g.RequireSystemAccess(ctx, rbac.ActionRead, rbac.ResourceGarbageCollection); err != nil {
		return g.SendError(ctx, err)
	}
	tasks, err := g.gcCtr.ListTasks(ctx, q.New(q.KeyWords{
		"ExecutionID": params.GCID,
	}))
	if err != nil {
		return g.SendError(ctx, err)
	}
	if len(tasks) == 0 {
		return g.SendError(ctx, errors.New(nil).WithCode(errors.NotFoundCode).WithMessage("garbage collection %d log is not found", params.GCID))
	}
	log, err := g.gcCtr.GetTaskLog(ctx, tasks[0].ID)
	if err != nil {
		return g.SendError(ctx, err)
	}
	return operation.NewGetGCLogOK().WithPayload(string(log))
}
<|endoftext|>


<commit_before>package persist

// disk_test.go probes some of the disk operations that are very commonly used
// within Sia. Namely, Read, Write, Truncate, WriteAt(rand), ReadAt(rand).

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/NebulousLabs/Sia/build"

	"github.com/NebulousLabs/fastrand"
)

// BenchmarkWrite256MiB checks how long it takes to write 256MiB sequentially.
func BenchmarkWrite256MiB(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 28)
	filename := filepath.Join(testDir, "1gb.file")
	for i := 0; i < b.N; i++ {
		// Make the file.
		f, err := os.Create(filename)
		if err != nil {
			b.Fatal(err)
		}

		// 2^12 writes of 4MiB.
		for i := 0; i < 1<<6; i++ {
			// Get the entropy separate from the timer.
			b.StopTimer()
			data := fastrand.Bytes(1 << 22)
			b.StartTimer()
			_, err = f.Write(data)
			if err != nil {
				b.Fatal(err)
			}
			// Sync after every write.
			err = f.Sync()
			if err != nil {
				b.Fatal(err)
			}
		}

		// Close the file before iterating.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkWrite256MiBRand checks how long it takes to write 256MiB randomly.
func BenchmarkWrite256MiBRand(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 28)
	filename := filepath.Join(testDir, "1gb.file")
	for i := 0; i < b.N; i++ {
		// Make the file.
		f, err := os.Create(filename)
		if err != nil {
			b.Fatal(err)
		}

		// 2^6 writes of 4MiB.
		for i := 0; i < 1<<6; i++ {
			// Get the entropy separate from the timer.
			b.StopTimer()
			data := fastrand.Bytes(1 << 22)
			offset := int64(fastrand.Intn(1 << 6))
			offset *= 1 << 22
			b.StartTimer()
			_, err = f.WriteAt(data, offset)
			if err != nil {
				b.Fatal(err)
			}
			// Sync after every write.
			err = f.Sync()
			if err != nil {
				b.Fatal(err)
			}
		}

		// Close the file before iterating.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkRead256MiB checks how long it takes to read 256MiB sequentially.
func BenchmarkRead256MiB(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 28)

	// Make the file.
	filename := filepath.Join(testDir, "1gb.file")
	f, err := os.Create(filename)
	if err != nil {
		b.Fatal(err)
	}

	// 2^6 writes of 4MiB.
	for i := 0; i < 1<<6; i++ {
		// Get the entropy separate from the timer.
		b.StopTimer()
		data := fastrand.Bytes(1 << 22)
		b.StartTimer()
		_, err = f.Write(data)
		if err != nil {
			b.Fatal(err)
		}
		// Sync after every write.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}
	}

	// Close the file.
	err = f.Close()
	if err != nil {
		b.Fatal(err)
	}

	// Check the sequential read speed.
	for i := 0; i < b.N; i++ {
		// Open the file.
		f, err := os.Open(filename)
		if err != nil {
			b.Fatal(err)
		}

		// Read the file 4 MiB at a time.
		for i := 0; i < 1<<6; i++ {
			data := make([]byte, 1<<22)
			_, err = f.Read(data)
			if err != nil {
				b.Fatal(err)
			}
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkRead256MiBRand checks how long it takes to read 256MiB randomly.
func BenchmarkRead256MiBRand(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 28)

	// Make the file.
	filename := filepath.Join(testDir, "1gb.file")
	f, err := os.Create(filename)
	if err != nil {
		b.Fatal(err)
	}

	// 2^6 writes of 4MiB.
	for i := 0; i < 1<<6; i++ {
		// Get the entropy separate from the timer.
		b.StopTimer()
		data := fastrand.Bytes(1 << 22)
		b.StartTimer()
		_, err = f.Write(data)
		if err != nil {
			b.Fatal(err)
		}
		// Sync after every write.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}
	}

	// Close the file.
	err = f.Close()
	if err != nil {
		b.Fatal(err)
	}

	// Check the sequential read speed.
	for i := 0; i < b.N; i++ {
		// Open the file.
		f, err := os.Open(filename)
		if err != nil {
			b.Fatal(err)
		}

		// Read the file 4 MiB at a time.
		for i := 0; i < 1<<6; i++ {
			offset := int64(fastrand.Intn(1 << 6))
			offset *= 1 << 22
			data := make([]byte, 1<<22)
			_, err = f.ReadAt(data, offset)
			if err != nil {
				b.Fatal(err)
			}
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkTruncate256MiB checks how long it takes to truncate a 256 MiB file.
func BenchmarkTruncate256MiB(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 28)
	filename := filepath.Join(testDir, "1gb.file")
	// Check the truncate speed.
	for i := 0; i < b.N; i++ {
		// Make the file separate from the timer.
		b.StopTimer()
		f, err := os.Create(filename)
		if err != nil {
			b.Fatal(err)
		}

		// 2^6 writes of 4MiB.
		for i := 0; i < 1<<6; i++ {
			// Get the entropy separate from the timer.
			b.StopTimer()
			data := fastrand.Bytes(1 << 22)
			b.StartTimer()
			_, err = f.Write(data)
			if err != nil {
				b.Fatal(err)
			}
		}
		// Sync after writing.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}

		// Close the file.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
		b.StartTimer()

		// Open the file.
		f, err = os.OpenFile(filename, os.O_RDWR, 0600)
		if err != nil {
			b.Fatal(err)
		}

		// Truncate the file.
		err = f.Truncate(0)
		if err != nil {
			b.Fatal(err)
		}

		// Sync.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}

		// Close.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}
<commit_msg>fixup small test mistakes<commit_after>package persist

// disk_test.go probes some of the disk operations that are very commonly used
// within Sia. Namely, Read, Write, Truncate, WriteAt(rand), ReadAt(rand).

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/NebulousLabs/Sia/build"

	"github.com/NebulousLabs/fastrand"
)

// BenchmarkWrite512MiB checks how long it takes to write 512MiB sequentially.
func BenchmarkWrite512MiB(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}

	b.SetBytes(1 << 29)
	filename := filepath.Join(testDir, "512MiB.file")
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Make the file.
		f, err := os.Create(filename)
		if err != nil {
			b.Fatal(err)
		}

		// 2^12 writes of 4MiB.
		for i := 0; i < 1<<7; i++ {
			// Get the entropy separate from the timer.
			b.StopTimer()
			data := fastrand.Bytes(1 << 22)
			b.StartTimer()
			_, err = f.Write(data)
			if err != nil {
				b.Fatal(err)
			}
			// Sync after every write.
			err = f.Sync()
			if err != nil {
				b.Fatal(err)
			}
		}

		// Close the file before iterating.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkWrite512MiBRand checks how long it takes to write 512MiB randomly.
func BenchmarkWrite512MiBRand(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 29)
	filename := filepath.Join(testDir, "512MiB.file")
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Make the file.
		f, err := os.Create(filename)
		if err != nil {
			b.Fatal(err)
		}

		// 2^7 writes of 4MiB.
		for i := 0; i < 1<<7; i++ {
			// Get the entropy separate from the timer.
			b.StopTimer()
			data := fastrand.Bytes(1 << 22)
			offset := int64(fastrand.Intn(1 << 6))
			offset *= 1 << 22
			b.StartTimer()
			_, err = f.WriteAt(data, offset)
			if err != nil {
				b.Fatal(err)
			}
			// Sync after every write.
			err = f.Sync()
			if err != nil {
				b.Fatal(err)
			}
		}

		// Close the file before iterating.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkRead512MiB checks how long it takes to read 512MiB sequentially.
func BenchmarkRead512MiB(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 29)

	// Make the file.
	filename := filepath.Join(testDir, "512MiB.file")
	f, err := os.Create(filename)
	if err != nil {
		b.Fatal(err)
	}

	// 2^7 writes of 4MiB.
	for i := 0; i < 1<<7; i++ {
		// Get the entropy separate from the timer.
		b.StopTimer()
		data := fastrand.Bytes(1 << 22)
		b.StartTimer()
		_, err = f.Write(data)
		if err != nil {
			b.Fatal(err)
		}
		// Sync after every write.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}
	}

	// Close the file.
	err = f.Close()
	if err != nil {
		b.Fatal(err)
	}

	// Check the sequential read speed.
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Open the file.
		f, err := os.Open(filename)
		if err != nil {
			b.Fatal(err)
		}

		// Read the file 4 MiB at a time.
		for i := 0; i < 1<<6; i++ {
			data := make([]byte, 1<<22)
			_, err = f.Read(data)
			if err != nil {
				b.Fatal(err)
			}
		}

		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkRead512MiBRand checks how long it takes to read 512MiB randomly.
func BenchmarkRead512MiBRand(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 29)

	// Make the file.
	filename := filepath.Join(testDir, "512MiB.file")
	f, err := os.Create(filename)
	if err != nil {
		b.Fatal(err)
	}

	// 2^7 writes of 4MiB.
	for i := 0; i < 1<<7; i++ {
		// Get the entropy separate from the timer.
		b.StopTimer()
		data := fastrand.Bytes(1 << 22)
		b.StartTimer()
		_, err = f.Write(data)
		if err != nil {
			b.Fatal(err)
		}
		// Sync after every write.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}
	}

	// Close the file.
	err = f.Close()
	if err != nil {
		b.Fatal(err)
	}

	// Check the sequential read speed.
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Open the file.
		f, err := os.Open(filename)
		if err != nil {
			b.Fatal(err)
		}

		// Read the file 4 MiB at a time.
		for i := 0; i < 1<<6; i++ {
			offset := int64(fastrand.Intn(1 << 6))
			offset *= 1 << 22
			data := make([]byte, 1<<22)
			_, err = f.ReadAt(data, offset)
			if err != nil {
				b.Fatal(err)
			}
		}

		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}

// BenchmarkTruncate512MiB checks how long it takes to truncate a 512 MiB file.
func BenchmarkTruncate512MiB(b *testing.B) {
	testDir := build.TempDir("persist", b.Name())
	err := os.MkdirAll(testDir, 0700)
	if err != nil {
		b.Fatal(err)
	}
	b.SetBytes(1 << 29)
	filename := filepath.Join(testDir, "512MiB.file")
	// Check the truncate speed.
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		// Make the file separate from the timer.
		b.StopTimer()
		f, err := os.Create(filename)
		if err != nil {
			b.Fatal(err)
		}

		// 2^7 writes of 4MiB.
		for i := 0; i < 1<<7; i++ {
			// Get the entropy separate from the timer.
			b.StopTimer()
			data := fastrand.Bytes(1 << 22)
			b.StartTimer()
			_, err = f.Write(data)
			if err != nil {
				b.Fatal(err)
			}
		}
		// Sync after writing.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}

		// Close the file.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
		b.StartTimer()

		// Open the file.
		f, err = os.OpenFile(filename, os.O_RDWR, 0600)
		if err != nil {
			b.Fatal(err)
		}

		// Truncate the file.
		err = f.Truncate(0)
		if err != nil {
			b.Fatal(err)
		}

		// Sync.
		err = f.Sync()
		if err != nil {
			b.Fatal(err)
		}

		// Close.
		err = f.Close()
		if err != nil {
			b.Fatal(err)
		}
	}

	err = os.Remove(filename)
	if err != nil {
		b.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package goMiddlewareChain

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// RequestChainHandler chains all handler
func RequestChainHandler(responseHandler ResponseHandler, handlers ...Handler) httprouter.Handle {
	return httprouter.Handle(func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		payload := Response{}

		// iterate all handlers
		for _, handler := range handlers {
			handler(&payload, request, params)
		}

		// pass responseHandler
		responseHandler(&payload, writer, request, params)
	})
}

// RestrictedRequestChainHandler need a RestrictHandler.
// A RestrictHandler returns bool if call is allowed.
func RestrictedRequestChainHandler(restrictHandler RestrictHandler, responseHandler ResponseHandler, handlers ...Handler) httprouter.Handle {
	return httprouter.Handle(func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		payload := Response{}

		// check restriction
		allowed := restrictHandler(&payload, request, params)

		if allowed {
			// iterate all handlers
			for _, handler := range handlers {
				handler(&payload, request, params)
			}
		}

		// pass ResponseHandler
		responseHandler(&payload, writer, request, params)
	})
}
<commit_msg>set status-code and message if retrict-handler failed and doesnt set this<commit_after>package goMiddlewareChain

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
)

// RequestChainHandler chains all handler
func RequestChainHandler(responseHandler ResponseHandler, handlers ...Handler) httprouter.Handle {
	return httprouter.Handle(func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		payload := Response{}

		// iterate all handlers
		for _, handler := range handlers {
			handler(&payload, request, params)
		}

		// pass responseHandler
		responseHandler(&payload, writer, request, params)
	})
}

// RestrictedRequestChainHandler need a RestrictHandler.
// A RestrictHandler returns bool if call is allowed.
func RestrictedRequestChainHandler(restrictHandler RestrictHandler, responseHandler ResponseHandler, handlers ...Handler) httprouter.Handle {
	return httprouter.Handle(func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		payload := Response{}

		// check restriction
		allowed := restrictHandler(&payload, request, params)

		if allowed {
			// iterate all handlers
			for _, handler := range handlers {
				handler(&payload, request, params)
			}
		} else if payload.Status.Code == 0 {
			payload.Status.Code = http.StatusUnauthorized
			payload.Status.Message = "failed by passing restrictHandler"
		}

		// pass ResponseHandler
		responseHandler(&payload, writer, request, params)
	})
}
<|endoftext|>