<commit_before>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/golang/glog"
	"github.com/google/certificate-transparency/go/x509"
	ctfe "github.com/google/trillian/examples/ct"
	"github.com/google/trillian/integration"
)

var (
	httpServersFlag = flag.String("ct_http_servers", "localhost:8092", "Comma-separated list of (assumed interchangeable) servers, each as address:port")
	testDir         = flag.String("testdata_dir", "testdata", "Name of directory with test data")
	seed            = flag.Int64("seed", -1, "Seed for random number generation")
	logConfigFlag   = flag.String("log_config", "", "File holding log config in JSON")
	mmdFlag         = flag.Duration("mmd", 2*time.Minute, "MMD for logs")
	operationsFlag  = flag.Uint64("operations", ^uint64(0), "Number of operations to perform")
)
var (
	addChainBias          = flag.Int("add_chain", 20, "Bias for add-chain operations")
	addPreChainBias       = flag.Int("add_pre_chain", 20, "Bias for add-pre-chain operations")
	getSTHBias            = flag.Int("get_sth", 2, "Bias for get-sth operations")
	getSTHConsistencyBias = flag.Int("get_sth_consistency", 2, "Bias for get-sth-consistency operations")
	getProofByHashBias    = flag.Int("get_proof_by_hash", 2, "Bias for get-proof-by-hash operations")
	getEntriesBias        = flag.Int("get_entries", 2, "Bias for get-entries operations")
	getRootsBias          = flag.Int("get_roots", 1, "Bias for get-roots operations")
	getEntryAndProofBias  = flag.Int("get_entry_and_proof", 0, "Bias for get-entry-and-proof operations")
)

func main() {
	flag.Parse()
	if *logConfigFlag == "" {
		glog.Fatal("Test aborted as no log config provided")
	}
	if *seed == -1 {
		*seed = time.Now().UTC().UnixNano() & 0xFFFFFFFF
	}
	rand.Seed(*seed)

	cfg, err := ctfe.LogConfigFromFile(*logConfigFlag)
	if err != nil {
		glog.Fatalf("Failed to read log config: %v", err)
	}

	// Retrieve the test data.
	caChain, err := integration.GetChain(*testDir, "int-ca.cert")
	if err != nil {
		glog.Fatalf("failed to load certificate: %v", err)
	}
	leafChain, err := integration.GetChain(*testDir, "leaf01.chain")
	if err != nil {
		glog.Fatalf("failed to load certificate: %v", err)
	}
	signer, err := integration.MakeSigner(*testDir)
	if err != nil {
		glog.Fatalf("failed to retrieve signer for re-signing: %v", err)
	}
	leafCert, err := x509.ParseCertificate(leafChain[0].Data)
	if err != nil {
		glog.Fatalf("failed to parse leaf certificate to build precert from: %v", err)
	}
	caCert, err := x509.ParseCertificate(caChain[0].Data)
	if err != nil {
		glog.Fatalf("failed to parse issuer for precert: %v", err)
	}
	bias := integration.HammerBias{Bias: map[ctfe.EntrypointName]int{
		ctfe.AddChainName:          *addChainBias,
		ctfe.AddPreChainName:       *addPreChainBias,
		ctfe.GetSTHName:            *getSTHBias,
		ctfe.GetSTHConsistencyName: *getSTHConsistencyBias,
		ctfe.GetProofByHashName:    *getProofByHashBias,
		ctfe.GetEntriesName:        *getEntriesBias,
		ctfe.GetRootsName:          *getRootsBias,
		ctfe.GetEntryAndProofName:  *getEntryAndProofBias,
	}}

	fmt.Print("\n\nStop ")
	for i := 0; i < 8; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Print(".")
	}
	fmt.Print(" Hammer Time\n\n")

	type result struct {
		prefix string
		err    error
	}
	results := make(chan result, len(cfg))
	var wg sync.WaitGroup
	for _, c := range cfg {
		wg.Add(1)
		cfg := integration.HammerConfig{
			LogCfg:     c,
			MMD:        *mmdFlag,
			LeafChain:  leafChain,
			LeafCert:   leafCert,
			CACert:     caCert,
			Signer:     signer,
			Servers:    *httpServersFlag,
			EPBias:     bias,
			Operations: *operationsFlag,
		}
		go func(cfg integration.HammerConfig) {
			defer wg.Done()
			err := integration.HammerCTLog(cfg)
			results <- result{prefix: cfg.LogCfg.Prefix, err: err}
		}(cfg)
	}
	wg.Wait()
	close(results)
	for e := range results {
		if e.err != nil {
			glog.Errorf("%s: %v", e.prefix, e.err)
		}
	}
}
<commit_msg>integration/ct: make test distinctive<commit_after>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"sync"
	"time"

	"github.com/golang/glog"
	"github.com/google/certificate-transparency/go/x509"
	ctfe "github.com/google/trillian/examples/ct"
	"github.com/google/trillian/integration"
)

var (
	httpServersFlag = flag.String("ct_http_servers", "localhost:8092", "Comma-separated list of (assumed interchangeable) servers, each as address:port")
	testDir         = flag.String("testdata_dir", "testdata", "Name of directory with test data")
	seed            = flag.Int64("seed", -1, "Seed for random number generation")
	logConfigFlag   = flag.String("log_config", "", "File holding log config in JSON")
	mmdFlag         = flag.Duration("mmd", 2*time.Minute, "MMD for logs")
	operationsFlag  = flag.Uint64("operations", ^uint64(0), "Number of operations to perform")
)
var (
	addChainBias          = flag.Int("add_chain", 20, "Bias for add-chain operations")
	addPreChainBias       = flag.Int("add_pre_chain", 20, "Bias for add-pre-chain operations")
	getSTHBias            = flag.Int("get_sth", 2, "Bias for get-sth operations")
	getSTHConsistencyBias = flag.Int("get_sth_consistency", 2, "Bias for get-sth-consistency operations")
	getProofByHashBias    = flag.Int("get_proof_by_hash", 2, "Bias for get-proof-by-hash operations")
	getEntriesBias        = flag.Int("get_entries", 2, "Bias for get-entries operations")
	getRootsBias          = flag.Int("get_roots", 1, "Bias for get-roots operations")
	getEntryAndProofBias  = flag.Int("get_entry_and_proof", 0, "Bias for get-entry-and-proof operations")
)

func main() {
	flag.Parse()
	if *logConfigFlag == "" {
		glog.Fatal("Test aborted as no log config provided")
	}
	if *seed == -1 {
		*seed = time.Now().UTC().UnixNano() & 0xFFFFFFFF
	}
	rand.Seed(*seed)

	cfg, err := ctfe.LogConfigFromFile(*logConfigFlag)
	if err != nil {
		glog.Fatalf("Failed to read log config: %v", err)
	}

	// Retrieve the test data.
	caChain, err := integration.GetChain(*testDir, "int-ca.cert")
	if err != nil {
		glog.Fatalf("failed to load certificate: %v", err)
	}
	leafChain, err := integration.GetChain(*testDir, "leaf01.chain")
	if err != nil {
		glog.Fatalf("failed to load certificate: %v", err)
	}
	signer, err := integration.MakeSigner(*testDir)
	if err != nil {
		glog.Fatalf("failed to retrieve signer for re-signing: %v", err)
	}
	leafCert, err := x509.ParseCertificate(leafChain[0].Data)
	if err != nil {
		glog.Fatalf("failed to parse leaf certificate to build precert from: %v", err)
	}
	caCert, err := x509.ParseCertificate(caChain[0].Data)
	if err != nil {
		glog.Fatalf("failed to parse issuer for precert: %v", err)
	}
	bias := integration.HammerBias{Bias: map[ctfe.EntrypointName]int{
		ctfe.AddChainName:          *addChainBias,
		ctfe.AddPreChainName:       *addPreChainBias,
		ctfe.GetSTHName:            *getSTHBias,
		ctfe.GetSTHConsistencyName: *getSTHConsistencyBias,
		ctfe.GetProofByHashName:    *getProofByHashBias,
		ctfe.GetEntriesName:        *getEntriesBias,
		ctfe.GetRootsName:          *getRootsBias,
		ctfe.GetEntryAndProofName:  *getEntryAndProofBias,
	}}

	fmt.Print("\n\nStop")
	for i := 0; i < 8; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Print(".")
	}

	fmt.Print(`
                                   ':++/.
                                  'sddhhyo'
                                  /hyyho+s-       '-:/+:.
                                 .sdhhysoy-  ' '/sdmNNmmy'
                             ':oooymmmdddmysymhmNNNNNNNh-
                      '.:::+so++++ymmmNNNdyyyNNNNNMMNd/'
             '...:::/://osoo++s+yyhmNNNMmdddhyymNNhs+.
     '..-://+++/////+//+sooosyyhdmmdNNNMmmmhhs+y/-'
    'oooooooo++++++/ossyyyyhhhhdddyymNNmhdmmdy:-'
  ':ohhso++/++//+/+/////:oyyyddhhy+/hmNNNMMMmo-'
  -hddo-''               +syyhhyyy+:ymNNMMNms:'
  'ss+'                  /sssyssyyo/sdmmmds+/.
   ''                    +sssssyyyysyhhyys+:.'
                         +ssyyssoosoosss+/:.'
                        -yyyyysooso+so+/::-'
                        smmdhyssssoso+//:-'
                       -mNMMMNdyssyso+/:.'
                   ':shmMMMMMMMMNMMNmo.
                  -hNMMMMMMMMMMMMMMMMd/'
                 .hNMMMMMMMMMMMMMMMMMMNy/.
                .yNMMMMMMMMMMMMMMMMMMMMMMd:
              .omMMMMMMMMMMMMMMMMMMMMNMMMMNo'
            .omMMMMMMMMMMMMMMMMMMMMMMMMMMMMMy.
           -dNMMMMMMMMMMMMMMMMMNNMMMMMNMMMMMMy'
          :dMMMMMMMMMMMMMMMMMMMNmNMMMMNNMMMMMN/
         .dMMMMMMMMMMMMMMMMMMMNmmMMMMMMMMMMMMMs'
         +NMMMMMMMMMMMMNmMMMMMNmNMMMMMMMMMMMMMy'
         -mMMMMMMMMMMMMMMMMMMMNNMMMMMMMMMMMMMMo'
         'hNMMMMMMMMMMMMMMMMMMMMMMMMMMMNNNMNNh.
          sNMMMMMMMMMMMMMMMMMMMMMMMMMMNNNNmh+.
          /NMMMMMMMMMMMMMMMMMNdmNMMMMMNNNm:
          -mMMMMMMMMMMMMMMNms-''/mMMMNddNm-
           oNMMMMMMMMMMMMd/'     +NMMNddmm:
           -mMMMMMMMMMMMN+'      'sNMMMNNmy-
            sNMMMMMMMMMNd.        'sNNMNNNmh-
            :NMMMMMMMMNm:          'yNNMMNNmy'
            'yNMMMMMMMNo'           .hNMMMNNm.
             .dMMMMMNNy'             -dNMMNNN:
              oNMMMNNm-               /NNMMNN/
              :NMMMMNh.                yNMMNms'
              :mMMMNN/                 -mMMMNy'
              'yNMmho'                  sNNmNNs.
            ''/mMMMmy'                  -mNMMMMNdhhy+'
          .yNNMMMMMNm+'                 /NMMMNNNmdy+-
           :hNNMMMNdd/'                 /dmNNdso+:.'`)
	fmt.Print("\n\nHammer Time\n\n")

	type result struct {
		prefix string
		err    error
	}
	results := make(chan result, len(cfg))
	var wg sync.WaitGroup
	for _, c := range cfg {
		wg.Add(1)
		cfg := integration.HammerConfig{
			LogCfg:     c,
			MMD:        *mmdFlag,
			LeafChain:  leafChain,
			LeafCert:   leafCert,
			CACert:     caCert,
			Signer:     signer,
			Servers:    *httpServersFlag,
			EPBias:     bias,
			Operations: *operationsFlag,
		}
		go func(cfg integration.HammerConfig) {
			defer wg.Done()
			err := integration.HammerCTLog(cfg)
			results <- result{prefix: cfg.LogCfg.Prefix, err: err}
		}(cfg)
	}
	wg.Wait()
	close(results)
	for e := range results {
		if e.err != nil {
			glog.Errorf("%s: %v", e.prefix, e.err)
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tournaments

import (
	"errors"
	"net/http"
	"time"

	"appengine"

	"github.com/taironas/gonawin/helpers"
	"github.com/taironas/gonawin/helpers/log"
	templateshlp "github.com/taironas/gonawin/helpers/templates"

	mdl "github.com/taironas/gonawin/models"
)

// Json new world cup tournament handler.
func NewWorldCup(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	c := appengine.NewContext(r)
	desc := "New World Cup Handler:"

	if r.Method == "POST" {
		tournament, err := mdl.CreateWorldCup(c, u.Id)
		if err != nil {
			log.Errorf(c, "%s error when trying to create a tournament: %v", desc, err)
			return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeTournamentCannotCreate)}
		}

		return templateshlp.RenderJson(w, c, tournament)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}

// Json new world cup tournament handler.
func GetWorldCup(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	c := appengine.NewContext(r)
	desc := "Get World Cup Handler:"

	if r.Method == "GET" {
		tournaments := mdl.FindTournaments(c, "Name", "2014 FIFA World Cup")
		if tournaments == nil {
			log.Errorf(c, "%s World Cup tournament was not found.", desc)
			return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		tournament := tournaments[0]

		// tournament
		fieldsToKeep := []string{"Id", "Name", "Description"}
		var TournamentJSON mdl.TournamentJSON
		helpers.InitPointerStructure(tournament, &TournamentJSON, fieldsToKeep)
		// formatted start and end
		const layout = "2 January 2006"
		start := tournament.Start.Format(layout)
		end := tournament.End.Format(layout)
		// remaining days
		remainingDays := int64(tournament.Start.Sub(time.Now()).Hours() / 24)
		// data
		data := struct {
			Tournament    mdl.TournamentJSON
			Start         string
			End           string
			RemainingDays int64
		}{
			TournamentJSON,
			start,
			end,
			remainingDays,
		}

		return templateshlp.RenderJson(w, c, data)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}
<commit_msg>go lint controllers/tournaments/worldcup.go<commit_after>/*
 * Copyright (c) 2014 Santiago Arias | Remy Jourde
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package tournaments

import (
	"errors"
	"net/http"
	"time"

	"appengine"

	"github.com/taironas/gonawin/helpers"
	"github.com/taironas/gonawin/helpers/log"
	templateshlp "github.com/taironas/gonawin/helpers/templates"

	mdl "github.com/taironas/gonawin/models"
)

// NewWorldCup is the new world cup tournament handler.
//
func NewWorldCup(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	c := appengine.NewContext(r)
	desc := "New World Cup Handler:"

	if r.Method == "POST" {
		tournament, err := mdl.CreateWorldCup(c, u.Id)
		if err != nil {
			log.Errorf(c, "%s error when trying to create a tournament: %v", desc, err)
			return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeTournamentCannotCreate)}
		}

		return templateshlp.RenderJson(w, c, tournament)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}

// GetWorldCup is the get world cup tournament handler.
//
func GetWorldCup(w http.ResponseWriter, r *http.Request, u *mdl.User) error {
	c := appengine.NewContext(r)
	desc := "Get World Cup Handler:"

	if r.Method == "GET" {
		tournaments := mdl.FindTournaments(c, "Name", "2014 FIFA World Cup")
		if tournaments == nil {
			log.Errorf(c, "%s World Cup tournament was not found.", desc)
			return &helpers.InternalServerError{Err: errors.New(helpers.ErrorCodeTournamentNotFound)}
		}

		tournament := tournaments[0]

		// tournament
		fieldsToKeep := []string{"Id", "Name", "Description"}
		var TournamentJSON mdl.TournamentJSON
		helpers.InitPointerStructure(tournament, &TournamentJSON, fieldsToKeep)
		// formatted start and end
		const layout = "2 January 2006"
		start := tournament.Start.Format(layout)
		end := tournament.End.Format(layout)
		// remaining days
		remainingDays := int64(tournament.Start.Sub(time.Now()).Hours() / 24)
		// data
		data := struct {
			Tournament    mdl.TournamentJSON
			Start         string
			End           string
			RemainingDays int64
		}{
			TournamentJSON,
			start,
			end,
			remainingDays,
		}

		return templateshlp.RenderJson(w, c, data)
	}
	return &helpers.BadRequest{Err: errors.New(helpers.ErrorCodeNotSupported)}
}
<|endoftext|>


<commit_before>package storage

import (
	"fmt"
	"github.com/pkg/errors"
	"github.com/viant/toolbox"
	"github.com/viant/toolbox/cred"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

//httpStorageService represents basic http storage service (only limited listing and full download are supported)
type httpStorageService struct {
	Credential *cred.Config
}

//HTTPClientProvider represents http client provider
var HTTPClientProvider = func() (*http.Client, error) {
	return toolbox.NewHttpClient(&toolbox.HttpOptions{Key: "MaxIdleConns", Value: 0})
}

func (s *httpStorageService) addCredentialToURLIfNeeded(URL string) string {
	if s.Credential == nil || s.Credential.Password == "" || s.Credential.Username == "" {
		return URL
	}
	prasedURL, err := url.Parse(URL)
	if err != nil {
		return URL
	}
	if prasedURL.User != nil {
		return URL
	}
	return strings.Replace(URL, "://", fmt.Sprintf("://%v:%v@", s.Credential.Username, s.Credential.Password), 1)
}

type hRef struct {
	URL   string
	Value string
}

func extractLinks(body string) []*hRef {
	var result = make([]*hRef, 0)
	var linkContents = strings.Split(string(body), "href=\"")
	for i := 1; i < len(linkContents); i++ {
		var linkContent = linkContents[i]
		linkEndPosition := strings.Index(linkContent, "\"")
		if linkEndPosition == -1 {
			continue
		}
		linkHref :=string(linkContent[:linkEndPosition] )
		var content = ""
		contentStartPosition := strings.Index(linkContent, ">")
		if contentStartPosition != 1 {
			content = string(linkContent[contentStartPosition+1:])
			contentEndPosition := strings.Index(content, "<")
			if contentEndPosition != -1 {
				content = string(content[:contentEndPosition])
			}
		}
		link := &hRef{
			URL:   linkHref,
			Value: strings.Trim(content, " \t\r\n"),
		}
		result = append(result, link)

	}
	return result
}

//List returns a list of object for supplied url
func (s *httpStorageService) List(URL string) ([]Object, error) {
	listURL := s.addCredentialToURLIfNeeded(URL)
	client, err := HTTPClientProvider()
	if err != nil {
		return nil, err
	}
	response, err := client.Get(listURL)

	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	contentType := response.Header.Get("Content-Type")
	var result = make([]Object, 0)

	if response.Status != "200 OK" {
		return nil, fmt.Errorf("Invalid response code: %v", response.Status)
	}

	isGitUrl := strings.Contains(URL, "github.")
	isPublicGit  := strings.Contains(URL, "github.com")
	if strings.Contains(contentType, "text/html") {

		links := extractLinks(string(body))
		var indexedLinks = map[string]bool{}
		if isGitUrl {

			for _, link := range links {
				if !((strings.Contains(link.URL, "/blob/") || strings.Contains(link.URL, "/tree/")) && strings.HasSuffix(link.URL, link.Value)) {
					continue
				}
				linkType := StorageObjectContentType
				_, name := toolbox.URLSplit(link.URL)
				if path.Ext(name) == "" {
					linkType = StorageObjectFolderType
				}

				baseURL := toolbox.URLBase(URL)

				objectURL := link.URL
				if ! strings.Contains(objectURL, baseURL) {
					objectURL = toolbox.URLPathJoin(baseURL, link.URL)
				}

				if linkType == StorageObjectContentType && strings.Contains(objectURL, "/master/") {
					objectURL = strings.Replace(objectURL, "/blob/", "/", 1)
					if isPublicGit {
						objectURL = strings.Replace(objectURL, "github.com", "raw.githubusercontent.com", 1)
					} else {
						objectURL = strings.Replace(objectURL, ".com/", ".com/raw/", 1)
					}
				}
				if linkType ==  StorageObjectContentType && !strings.Contains(objectURL, "raw") {
					continue
				}
				if _, ok:= indexedLinks[objectURL];ok {
					continue
				}
				storageObject := newHttpFileObject(objectURL, linkType, nil, now, 1)
				indexedLinks[objectURL]=true
				result = append(result, storageObject)
			}

		} else {

			for _, link := range links {
				if link.URL == "" || strings.Contains(link.URL, ":") || strings.HasPrefix(link.URL, "#") || strings.HasPrefix(link.URL, "?") || strings.HasPrefix(link.URL, ".") || strings.HasPrefix(link.URL, "/") {
					continue
				}
				linkType := StorageObjectContentType
				if strings.HasSuffix(link.URL, "/") {
					linkType = StorageObjectFolderType
				}
				objectURL := toolbox.URLPathJoin(URL, link.URL)
				storageObject := newHttpFileObject(objectURL, linkType, nil, now, 1)
				result = append(result, storageObject)
			}
		}
	}

	if strings.Contains(string(body), ">..<") {
		return result, err
	}
	storageObject := newHttpFileObject(URL, StorageObjectContentType, nil, now, response.ContentLength)
	result = append(result, storageObject)
	return result, err
}

//Exists returns true if resource exists
func (s *httpStorageService) Exists(URL string) (bool, error) {
	client, err := HTTPClientProvider()
	if err != nil {
		return false, err
	}
	response, err := client.Get(URL)
	if err != nil {
		return false, err
	}
	return response.StatusCode == 200, nil
}

//Object returns a Object for supplied url
func (s *httpStorageService) StorageObject(URL string) (Object, error) {
	objects, err := s.List(URL)
	if err != nil {
		return nil, err
	}
	if len(objects) == 0 {
		return nil, fmt.Errorf("resource  not found: %v", URL)
	}

	return objects[0], nil
}

//Download returns reader for downloaded storage object
func (s *httpStorageService) Download(object Object) (io.ReadCloser, error) {
	client, err := HTTPClientProvider()
	if err != nil {
		return nil, err
	}
	response, err := client.Get(s.addCredentialToURLIfNeeded(object.URL()))
	return response.Body, err
}

//Upload uploads provided reader content for supplied url.
func (s *httpStorageService) Upload(URL string, reader io.Reader) error {
	return errors.New("unsupported")
}

func (s *httpStorageService) Register(schema string, service Service) error {
	return errors.New("unsupported")
}

//Delete removes passed in storage object
func (s *httpStorageService) Delete(object Object) error {
	fileName := toolbox.Filename(object.URL())
	return os.Remove(fileName)
}

func (s *httpStorageService) Close() error {
	return nil
}

func NewHttpStorageService(credential *cred.Config) Service {
	return &httpStorageService{
		Credential: credential,
	}
}

type httpStorageObject struct {
	*AbstractObject
}

func (o *httpStorageObject) Unwrap(target interface{}) error {
	return fmt.Errorf("unsuported target %T", target)
}

func newHttpFileObject(url string, objectType int, source interface{}, lastModified time.Time, size int64) Object {
	var isDir = objectType == StorageObjectFolderType
	var _, name = toolbox.URLSplit(url)
	var fileMode, _ = NewFileMode("-r--r--r--")
	if isDir {
		fileMode, _ = NewFileMode("dr--r--r--")
	}
	fileInfo := NewFileInfo(name, size, fileMode, lastModified, isDir)
	abstract := NewAbstractStorageObject(url, source, fileInfo)
	result := &httpStorageObject{
		AbstractObject: abstract,
	}
	result.AbstractObject.Object = result
	return result
}

const HttpProviderScheme = "http"
const HttpsProviderScheme = "https"

func init() {
	NewStorageProvider().Registry[HttpsProviderScheme] = httpServiceProvider
	NewStorageProvider().Registry[HttpProviderScheme] = httpServiceProvider

}

func httpServiceProvider(credentialFile string) (Service, error) {

	if credentialFile == "" {
		return NewHttpStorageService(nil), nil
	}

	if !strings.HasPrefix(credentialFile, "/") {
		dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
		credentialFile = path.Join(dir, credentialFile)
	}
	config, err := cred.NewConfig(credentialFile)
	if err != nil {
		return nil, err
	}
	return NewHttpStorageService(config), nil
}
<commit_msg>refactored<commit_after>package storage

import (
	"fmt"
	"github.com/pkg/errors"
	"github.com/viant/toolbox"
	"github.com/viant/toolbox/cred"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

//httpStorageService represents basic http storage service (only limited listing and full download are supported)
type httpStorageService struct {
	Credential *cred.Config
}

//HTTPClientProvider represents http client provider
var HTTPClientProvider = func() (*http.Client, error) {
	return toolbox.NewHttpClient(&toolbox.HttpOptions{Key: "MaxIdleConns", Value: 0})
}

func (s *httpStorageService) addCredentialToURLIfNeeded(URL string) string {
	if s.Credential == nil || s.Credential.Password == "" || s.Credential.Username == "" {
		return URL
	}
	prasedURL, err := url.Parse(URL)
	if err != nil {
		return URL
	}
	if prasedURL.User != nil {
		return URL
	}
	return strings.Replace(URL, "://", fmt.Sprintf("://%v:%v@", s.Credential.Username, s.Credential.Password), 1)
}

type hRef struct {
	URL   string
	Value string
}

func extractLinks(body string) []*hRef {
	var result = make([]*hRef, 0)
	var linkContents = strings.Split(string(body), "href=\"")
	for i := 1; i < len(linkContents); i++ {
		var linkContent = linkContents[i]
		linkEndPosition := strings.Index(linkContent, "\"")
		if linkEndPosition == -1 {
			continue
		}
		linkHref := string(linkContent[:linkEndPosition])
		var content = ""
		contentStartPosition := strings.Index(linkContent, ">")
		if contentStartPosition != 1 {
			content = string(linkContent[contentStartPosition+1:])
			contentEndPosition := strings.Index(content, "<")
			if contentEndPosition != -1 {
				content = string(content[:contentEndPosition])
			}
		}
		link := &hRef{
			URL:   linkHref,
			Value: strings.Trim(content, " \t\r\n"),
		}
		result = append(result, link)

	}
	return result
}

//List returns a list of object for supplied url
func (s *httpStorageService) List(URL string) ([]Object, error) {
	listURL := s.addCredentialToURLIfNeeded(URL)
	client, err := HTTPClientProvider()
	if err != nil {
		return nil, err
	}
	response, err := client.Get(listURL)

	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	contentType := response.Header.Get("Content-Type")
	var result = make([]Object, 0)

	if response.Status != "200 OK" {
		return nil, fmt.Errorf("Invalid response code: %v", response.Status)
	}

	isGitUrl := strings.Contains(URL, "github.")
	isPublicGit := strings.Contains(URL, "github.com")
	if strings.Contains(contentType, "text/html") {

		links := extractLinks(string(body))
		var indexedLinks = map[string]bool{}
		if isGitUrl {

			for _, link := range links {
				if !((strings.Contains(link.URL, "/blob/") || strings.Contains(link.URL, "/tree/")) && strings.HasSuffix(link.URL, link.Value)) {
					continue
				}
				linkType := StorageObjectContentType
				_, name := toolbox.URLSplit(link.URL)
				if path.Ext(name) == "" {
					linkType = StorageObjectFolderType
				}

				baseURL := toolbox.URLBase(URL)

				objectURL := link.URL
				if !strings.Contains(objectURL, baseURL) {
					objectURL = toolbox.URLPathJoin(baseURL, link.URL)
				}

				if linkType == StorageObjectContentType && strings.Contains(objectURL, "/master/") {
					objectURL = strings.Replace(objectURL, "/blob/", "/", 1)
					if isPublicGit {
						objectURL = strings.Replace(objectURL, "github.com", "raw.githubusercontent.com", 1)
					} else {
						objectURL = strings.Replace(objectURL, ".com/", ".com/raw/", 1)
					}
				}
				if linkType == StorageObjectContentType && !strings.Contains(objectURL, "raw") {
					continue
				}
				if _, ok := indexedLinks[objectURL]; ok {
					continue
				}
				storageObject := newHttpFileObject(objectURL, linkType, nil, now, 1)
				indexedLinks[objectURL] = true
				result = append(result, storageObject)
			}

		} else {

			for _, link := range links {
				if link.URL == "" || strings.Contains(link.URL, ":") || strings.HasPrefix(link.URL, "#") || strings.HasPrefix(link.URL, "?") || strings.HasPrefix(link.URL, ".") || strings.HasPrefix(link.URL, "/") {
					continue
				}
				linkType := StorageObjectContentType
				if strings.HasSuffix(link.URL, "/") {
					linkType = StorageObjectFolderType
				}
				objectURL := toolbox.URLPathJoin(URL, link.URL)
				storageObject := newHttpFileObject(objectURL, linkType, nil, now, 1)
				result = append(result, storageObject)
			}
		}
	}

	if strings.Contains(string(body), ">..<") {
		return result, err
	}
	storageObject := newHttpFileObject(URL, StorageObjectContentType, nil, now, response.ContentLength)
	result = append(result, storageObject)
	return result, err
}

//Exists returns true if resource exists
func (s *httpStorageService) Exists(URL string) (bool, error) {
	client, err := HTTPClientProvider()
	if err != nil {
		return false, err
	}
	response, err := client.Get(URL)
	if err != nil {
		return false, err
	}
	return response.StatusCode == 200, nil
}

//Object returns a Object for supplied url
func (s *httpStorageService) StorageObject(URL string) (Object, error) {
	objects, err := s.List(URL)
	if err != nil {
		return nil, err
	}
	if len(objects) == 0 {
		return nil, fmt.Errorf("resource  not found: %v", URL)
	}

	return objects[0], nil
}

//Download returns reader for downloaded storage object
func (s *httpStorageService) Download(object Object) (io.ReadCloser, error) {
	client, err := HTTPClientProvider()
	if err != nil {
		return nil, err
	}
	response, err := client.Get(s.addCredentialToURLIfNeeded(object.URL()))
	return response.Body, err
}

//Upload uploads provided reader content for supplied url.
func (s *httpStorageService) Upload(URL string, reader io.Reader) error {
	return errors.New("unsupported")
}

func (s *httpStorageService) Register(schema string, service Service) error {
	return errors.New("unsupported")
}

//Delete removes passed in storage object
func (s *httpStorageService) Delete(object Object) error {
	fileName := toolbox.Filename(object.URL())
	return os.Remove(fileName)
}

func (s *httpStorageService) Close() error {
	return nil
}

func NewHttpStorageService(credential *cred.Config) Service {
	return &httpStorageService{
		Credential: credential,
	}
}

type httpStorageObject struct {
	*AbstractObject
}

func (o *httpStorageObject) Unwrap(target interface{}) error {
	return fmt.Errorf("unsuported target %T", target)
}

func newHttpFileObject(url string, objectType int, source interface{}, lastModified time.Time, size int64) Object {
	var isDir = objectType == StorageObjectFolderType
	var _, name = toolbox.URLSplit(url)
	var fileMode, _ = NewFileMode("-r--r--r--")
	if isDir {
		fileMode, _ = NewFileMode("dr--r--r--")
	}
	fileInfo := NewFileInfo(name, size, fileMode, lastModified, isDir)
	abstract := NewAbstractStorageObject(url, source, fileInfo)
	result := &httpStorageObject{
		AbstractObject: abstract,
	}
	result.AbstractObject.Object = result
	return result
}

const HttpProviderScheme = "http"
const HttpsProviderScheme = "https"

func init() {
	NewStorageProvider().Registry[HttpsProviderScheme] = httpServiceProvider
	NewStorageProvider().Registry[HttpProviderScheme] = httpServiceProvider

}

func httpServiceProvider(credentialFile string) (Service, error) {

	if credentialFile == "" {
		return NewHttpStorageService(nil), nil
	}

	if !strings.HasPrefix(credentialFile, "/") {
		dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
		credentialFile = path.Join(dir, credentialFile)
	}
	config, err := cred.NewConfig(credentialFile)
	if err != nil {
		return nil, err
	}
	return NewHttpStorageService(config), nil
}
<|endoftext|>


<commit_before>/** Copyright 2015 Outright Mental, Inc. */
package atomix // is for sequence mixing

/*
#include <stdio.h>
#include <stdint.h>
typedef unsigned char Uint8;
extern uint8_t* Sha256data(uint8_t* p0, int p1);
void AudioCallback(void *userdata, Uint8 *stream, int len);
*/
import "C"
import (
	"fmt"
	"reflect"
	"unsafe"
	"sync"
	// log "github.com/Sirupsen/logrus"
	"github.com/veandco/go-sdl2/sdl"
)

type Mixer struct {
	// nothing yet
}

func (m *Mixer) Initialize() {
	// nothing yet
}

var instance *Mixer
var once sync.Once

func Instance() *Mixer {
	once.Do(func() {
		instance = &Mixer{}
		instance.Initialize()
	})
	return instance
}

func Spec(spec *sdl.AudioSpec) *sdl.AudioSpec {
	if spec.Freq == 0 {
		panic("Must specify Frequency")
	} else if spec.Format == 0 {
		panic("Must specify Format")
	} else if spec.Channels == 0 {
		panic("Must specify Channels")
	} else if spec.Samples == 0 {
		panic("Must specify Samples")
	}
	spec.Callback = sdl.AudioCallback(C.AudioCallback)
	return spec
}

var	(
	defaultSample = uint8(0xFF)
	defaultAudio = C.Uint8(defaultSample)
)

//export AudioCallback
func AudioCallback(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
	n := int(length)
	hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(stream)), Len: n, Cap: n}
	buf := *(*[]C.Uint8)(unsafe.Pointer(&hdr))

	for i := 0; i < n; i += 1 {
		buf[i] = defaultAudio
	}
	fmt.Printf("AudioCallback length %d\n", n)
}
<commit_msg>remove unused c header<commit_after>/** Copyright 2015 Outright Mental, Inc. */
package atomix // is for sequence mixing

/*
#include <stdio.h>
#include <stdint.h>
typedef unsigned char Uint8;
void AudioCallback(void *userdata, Uint8 *stream, int len);
*/
import "C"
import (
	"fmt"
	"reflect"
	"unsafe"
	"sync"
	// log "github.com/Sirupsen/logrus"
	"github.com/veandco/go-sdl2/sdl"
)

type Mixer struct {
	// nothing yet
}

func (m *Mixer) Initialize() {
	// nothing yet
}

var instance *Mixer
var once sync.Once

func Instance() *Mixer {
	once.Do(func() {
		instance = &Mixer{}
		instance.Initialize()
	})
	return instance
}

func Spec(spec *sdl.AudioSpec) *sdl.AudioSpec {
	if spec.Freq == 0 {
		panic("Must specify Frequency")
	} else if spec.Format == 0 {
		panic("Must specify Format")
	} else if spec.Channels == 0 {
		panic("Must specify Channels")
	} else if spec.Samples == 0 {
		panic("Must specify Samples")
	}
	spec.Callback = sdl.AudioCallback(C.AudioCallback)
	return spec
}

var	(
	defaultSample = uint8(0xFF)
	defaultAudio = C.Uint8(defaultSample)
)

//export AudioCallback
func AudioCallback(userdata unsafe.Pointer, stream *C.Uint8, length C.int) {
	n := int(length)
	hdr := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(stream)), Len: n, Cap: n}
	buf := *(*[]C.Uint8)(unsafe.Pointer(&hdr))

	for i := 0; i < n; i += 1 {
		buf[i] = defaultAudio
	}
	fmt.Printf("AudioCallback length %d\n", n)
}
<|endoftext|>


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

package fakestorage

import (
	"sort"
)

type listResponse struct {
	Kind     string        `json:"kind"`
	Items    []interface{} `json:"items"`
	Prefixes []string      `json:"prefixes"`
}

func newListBucketsResponse(bucketNames []string) listResponse {
	resp := listResponse{
		Kind:  "storage#buckets",
		Items: make([]interface{}, len(bucketNames)),
	}
	sort.Strings(bucketNames)
	for i, name := range bucketNames {
		resp.Items[i] = newBucketResponse(name)
	}
	return resp
}

type bucketResponse struct {
	Kind string `json:"kind"`
	ID   string `json:"ID"`
	Name string `json:"Name"`
}

func newBucketResponse(bucketName string) bucketResponse {
	return bucketResponse{
		Kind: "storage#bucket",
		ID:   bucketName,
		Name: bucketName,
	}
}

func newListObjectsResponse(objs []Object, prefixes []string) listResponse {
	resp := listResponse{
		Kind:     "storage#objects",
		Items:    make([]interface{}, len(objs)),
		Prefixes: prefixes,
	}
	for i, obj := range objs {
		resp.Items[i] = newObjectResponse(obj)
	}
	return resp
}

type objectResponse struct {
	Kind   string `json:"kind"`
	Name   string `json:"name"`
	ID     string `json:"id"`
	Bucket string `json:"bucket"`
	Size   int64  `json:"size,string"`
	// Crc32c: CRC32c checksum, same as in google storage client code
	Crc32c  string `json:"crc32c,omitempty"`
	Md5Hash string `json:"md5hash,omitempty"`
}

func newObjectResponse(obj Object) objectResponse {
	return objectResponse{
		Kind:    "storage#object",
		ID:      obj.id(),
		Bucket:  obj.BucketName,
		Name:    obj.Name,
		Size:    int64(len(obj.Content)),
		Crc32c:  obj.Crc32c,
		Md5Hash: obj.Md5Hash,
	}
}

type rewriteResponse struct {
	Kind                string         `json:"kind"`
	TotalBytesRewritten int64          `json:"totalBytesRewritten,string"`
	ObjectSize          int64          `json:"objectSize,string"`
	Done                bool           `json:"done"`
	RewriteToken        string         `json:"rewriteToken"`
	Resource            objectResponse `json:"resource"`
}

func newObjectRewriteResponse(obj Object) rewriteResponse {
	return rewriteResponse{
		Kind:                "storage#rewriteResponse",
		TotalBytesRewritten: int64(len(obj.Content)),
		ObjectSize:          int64(len(obj.Content)),
		Done:                true,
		RewriteToken:        "",
		Resource:            newObjectResponse(obj),
	}
}

type errorResponse struct {
	Error httpError `json:"error"`
}

type httpError struct {
	Code    int        `json:"code"`
	Message string     `json:"message"`
	Errors  []apiError `json:"errors"`
}

type apiError struct {
	Domain  string `json:"domain"`
	Reason  string `json:"reason"`
	Message string `json:"message"`
}

func newErrorResponse(code int, message string, errs []apiError) errorResponse {
	return errorResponse{
		Error: httpError{
			Code:    code,
			Message: message,
			Errors:  errs,
		},
	}
}
<commit_msg>Using lowercase keys in bucketResponse struct json<commit_after>// Copyright 2017 Francisco Souza. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package fakestorage

import (
	"sort"
)

type listResponse struct {
	Kind     string        `json:"kind"`
	Items    []interface{} `json:"items"`
	Prefixes []string      `json:"prefixes"`
}

func newListBucketsResponse(bucketNames []string) listResponse {
	resp := listResponse{
		Kind:  "storage#buckets",
		Items: make([]interface{}, len(bucketNames)),
	}
	sort.Strings(bucketNames)
	for i, name := range bucketNames {
		resp.Items[i] = newBucketResponse(name)
	}
	return resp
}

type bucketResponse struct {
	Kind string `json:"kind"`
	ID   string `json:"id"`
	Name string `json:"name"`
}

func newBucketResponse(bucketName string) bucketResponse {
	return bucketResponse{
		Kind: "storage#bucket",
		ID:   bucketName,
		Name: bucketName,
	}
}

func newListObjectsResponse(objs []Object, prefixes []string) listResponse {
	resp := listResponse{
		Kind:     "storage#objects",
		Items:    make([]interface{}, len(objs)),
		Prefixes: prefixes,
	}
	for i, obj := range objs {
		resp.Items[i] = newObjectResponse(obj)
	}
	return resp
}

type objectResponse struct {
	Kind   string `json:"kind"`
	Name   string `json:"name"`
	ID     string `json:"id"`
	Bucket string `json:"bucket"`
	Size   int64  `json:"size,string"`
	// Crc32c: CRC32c checksum, same as in google storage client code
	Crc32c  string `json:"crc32c,omitempty"`
	Md5Hash string `json:"md5hash,omitempty"`
}

func newObjectResponse(obj Object) objectResponse {
	return objectResponse{
		Kind:    "storage#object",
		ID:      obj.id(),
		Bucket:  obj.BucketName,
		Name:    obj.Name,
		Size:    int64(len(obj.Content)),
		Crc32c:  obj.Crc32c,
		Md5Hash: obj.Md5Hash,
	}
}

type rewriteResponse struct {
	Kind                string         `json:"kind"`
	TotalBytesRewritten int64          `json:"totalBytesRewritten,string"`
	ObjectSize          int64          `json:"objectSize,string"`
	Done                bool           `json:"done"`
	RewriteToken        string         `json:"rewriteToken"`
	Resource            objectResponse `json:"resource"`
}

func newObjectRewriteResponse(obj Object) rewriteResponse {
	return rewriteResponse{
		Kind:                "storage#rewriteResponse",
		TotalBytesRewritten: int64(len(obj.Content)),
		ObjectSize:          int64(len(obj.Content)),
		Done:                true,
		RewriteToken:        "",
		Resource:            newObjectResponse(obj),
	}
}

type errorResponse struct {
	Error httpError `json:"error"`
}

type httpError struct {
	Code    int        `json:"code"`
	Message string     `json:"message"`
	Errors  []apiError `json:"errors"`
}

type apiError struct {
	Domain  string `json:"domain"`
	Reason  string `json:"reason"`
	Message string `json:"message"`
}

func newErrorResponse(code int, message string, errs []apiError) errorResponse {
	return errorResponse{
		Error: httpError{
			Code:    code,
			Message: message,
			Errors:  errs,
		},
	}
}
<|endoftext|>


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

package oto

import (
	"fmt"
	"reflect"
	"runtime"
	"unsafe"

	"golang.org/x/sys/windows"
)

type comThread struct {
	funcCh chan func()
}

func newCOMThread() (*comThread, error) {
	funcCh := make(chan func())
	errCh := make(chan error)
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		if err := _CoInitializeEx(nil, _COINIT_MULTITHREADED); err != nil {
			errCh <- err
		}
		defer _CoUninitialize()

		close(errCh)

		for f := range funcCh {
			f()
		}
	}()

	if err := <-errCh; err != nil {
		return nil, err
	}

	return &comThread{
		funcCh: funcCh,
	}, nil
}

func (c *comThread) Run(f func()) {
	ch := make(chan struct{})
	c.funcCh <- func() {
		f()
		close(ch)
	}
	<-ch
}

type wasapiContext struct {
	sampleRate   int
	channelCount int
	players      *players

	comThread *comThread
	err       atomicError

	sampleReadyEvent windows.Handle
	client           *_IAudioClient2
	mixFormat        *_WAVEFORMATEXTENSIBLE
	bufferFrames     uint32
	renderClient     *_IAudioRenderClient
}

func newWASAPIContext(sampleRate, channelCount int, players *players) (*wasapiContext, chan struct{}, error) {
	t, err := newCOMThread()
	if err != nil {
		return nil, nil, err
	}

	c := &wasapiContext{
		sampleRate:   sampleRate,
		channelCount: channelCount,
		players:      players,
		comThread:    t,
	}

	var cerr error
	t.Run(func() {
		if err := c.initOnCOMThread(); err != nil {
			cerr = err
			return
		}
	})
	if cerr != nil {
		return nil, nil, cerr
	}

	ready := make(chan struct{})
	close(ready)

	return c, ready, nil
}

func (c *wasapiContext) initOnCOMThread() error {
	e, err := _CoCreateInstance(&uuidMMDeviceEnumerator, nil, uint32(_CLSCTX_ALL), &uuidIMMDeviceEnumerator)
	if err != nil {
		return err
	}
	enumerator := (*_IMMDeviceEnumerator)(e)
	defer enumerator.Release()

	device, err := enumerator.GetDefaultAudioEndPoint(eRender, eConsole)
	if err != nil {
		return err
	}
	defer device.Release()

	client, err := device.Activate(&uuidIAudioClient2, uint32(_CLSCTX_ALL), nil)
	if err != nil {
		return err
	}
	c.client = (*_IAudioClient2)(client)

	if err := c.client.SetClientProperties(&_AudioClientProperties{
		cbSize:     uint32(unsafe.Sizeof(_AudioClientProperties{})),
		bIsOffload: 0,                    // false
		eCategory:  _AudioCategory_Other, // In the example, AudioCategory_ForegroundOnlyMedia was used, but this value is deprecated.
	}); err != nil {
		return err
	}

	// Check the format is supported by WASAPI.
	// Stereo with 48000 [Hz] is likely supported, but mono and/or other sample rates are unlikely supported.
	// Fallback to WinMM in this case anyway.
	const bitsPerSample = 32
	nBlockAlign := c.channelCount * bitsPerSample / 8
	var channelMask uint32
	switch c.channelCount {
	case 1:
		channelMask = _SPEAKER_FRONT_CENTER
	case 2:
		channelMask = _SPEAKER_FRONT_LEFT | _SPEAKER_FRONT_RIGHT
	}
	f := &_WAVEFORMATEXTENSIBLE{
		wFormatTag:      _WAVE_FORMAT_EXTENSIBLE,
		nChannels:       uint16(c.channelCount),
		nSamplesPerSec:  uint32(c.sampleRate),
		nAvgBytesPerSec: uint32(c.sampleRate * nBlockAlign),
		nBlockAlign:     uint16(nBlockAlign),
		wBitsPerSample:  bitsPerSample,
		cbSize:          0x16,
		Samples:         bitsPerSample,
		dwChannelMask:   channelMask,
		SubFormat:       _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
	}
	closest, err := c.client.IsFormatSupported(_AUDCLNT_SHAREMODE_SHARED, f)
	if err != nil {
		return err
	}
	if closest != nil {
		return fmt.Errorf("oto: the specified format is not supported (there is the closest format instead)")
	}
	c.mixFormat = f

	if err := c.client.Initialize(_AUDCLNT_SHAREMODE_SHARED,
		_AUDCLNT_STREAMFLAGS_EVENTCALLBACK|_AUDCLNT_STREAMFLAGS_NOPERSIST,
		0, 0, c.mixFormat, nil); err != nil {
		return err
	}

	frames, err := c.client.GetBufferSize()
	if err != nil {
		return err
	}
	c.bufferFrames = frames

	renderClient, err := c.client.GetService(&uuidIAudioRenderClient)
	if err != nil {
		return err
	}
	c.renderClient = (*_IAudioRenderClient)(renderClient)

	ev, err := windows.CreateEventEx(nil, nil, 0, windows.EVENT_ALL_ACCESS)
	if err != nil {
		return err
	}
	c.sampleReadyEvent = ev

	if err := c.client.SetEventHandle(c.sampleReadyEvent); err != nil {
		return err
	}

	// TODO: Should some errors be allowed? See WASAPIManager.cpp in the official example SimpleWASAPIPlaySound.

	if err := c.client.Start(); err != nil {
		return err
	}

	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		if err := _CoInitializeEx(nil, _COINIT_MULTITHREADED); err != nil {
			c.client.Stop()
			c.err.TryStore(err)
			return
		}
		defer _CoUninitialize()

		if err := c.loopOnRenderThread(); err != nil {
			c.client.Stop()
			c.err.TryStore(err)
			return
		}
	}()

	return nil
}

func (c *wasapiContext) loopOnRenderThread() error {
	var buf []float32
	for {
		evt, err := windows.WaitForSingleObject(c.sampleReadyEvent, 2000)
		if err != nil {
			return err
		}
		if evt != windows.WAIT_OBJECT_0 {
			return fmt.Errorf("oto: WaitForSingleObject failed: returned value: %d", evt)
		}

		paddingFrames, err := c.client.GetCurrentPadding()
		if err != nil {
			return err
		}

		frames := c.bufferFrames - paddingFrames
		if frames <= 0 {
			continue
		}

		// Get the destination buffer.
		dstBuf, err := c.renderClient.GetBuffer(frames)
		if err != nil {
			return err
		}

		// Calculate the buffer size.
		buflen := int(frames) * c.channelCount
		if cap(buf) < buflen {
			buf = make([]float32, buflen)
		} else {
			buf = buf[:buflen]
		}

		// Read the buffer from the players.
		c.players.read(buf)

		// Copy the read buf to the destination buffer.
		var dst []float32
		h := (*reflect.SliceHeader)(unsafe.Pointer(&dst))
		h.Data = uintptr(unsafe.Pointer(dstBuf))
		h.Len = buflen
		h.Cap = buflen
		copy(dst, buf)

		// Release the buffer.
		if err := c.renderClient.ReleaseBuffer(frames, 0); err != nil {
			return err
		}

		buf = buf[:0]
	}
}

func (c *wasapiContext) Suspend() error {
	if err := c.client.Stop(); err != nil {
		return err
	}
	return nil
}

func (c *wasapiContext) Resume() error {
	if err := c.client.Start(); err != nil {
		return err
	}
	return nil
}

func (c *wasapiContext) Err() error {
	return c.err.Load()
}
<commit_msg>wasapi: bug fix: Suspend and Resume were concurrent unsafe<commit_after>// Copyright 2022 The Oto Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oto

import (
	"fmt"
	"reflect"
	"runtime"
	"sync"
	"unsafe"

	"golang.org/x/sys/windows"
)

type comThread struct {
	funcCh chan func()
}

func newCOMThread() (*comThread, error) {
	funcCh := make(chan func())
	errCh := make(chan error)
	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		if err := _CoInitializeEx(nil, _COINIT_MULTITHREADED); err != nil {
			errCh <- err
		}
		defer _CoUninitialize()

		close(errCh)

		for f := range funcCh {
			f()
		}
	}()

	if err := <-errCh; err != nil {
		return nil, err
	}

	return &comThread{
		funcCh: funcCh,
	}, nil
}

func (c *comThread) Run(f func()) {
	ch := make(chan struct{})
	c.funcCh <- func() {
		f()
		close(ch)
	}
	<-ch
}

type wasapiContext struct {
	sampleRate   int
	channelCount int
	players      *players

	comThread *comThread
	err       atomicError

	sampleReadyEvent windows.Handle
	client           *_IAudioClient2
	mixFormat        *_WAVEFORMATEXTENSIBLE
	bufferFrames     uint32
	renderClient     *_IAudioRenderClient

	buf []float32

	m sync.Mutex
}

func newWASAPIContext(sampleRate, channelCount int, players *players) (*wasapiContext, chan struct{}, error) {
	t, err := newCOMThread()
	if err != nil {
		return nil, nil, err
	}

	c := &wasapiContext{
		sampleRate:   sampleRate,
		channelCount: channelCount,
		players:      players,
		comThread:    t,
	}

	var cerr error
	t.Run(func() {
		if err := c.initOnCOMThread(); err != nil {
			cerr = err
			return
		}
	})
	if cerr != nil {
		return nil, nil, cerr
	}

	ready := make(chan struct{})
	close(ready)

	return c, ready, nil
}

func (c *wasapiContext) initOnCOMThread() error {
	e, err := _CoCreateInstance(&uuidMMDeviceEnumerator, nil, uint32(_CLSCTX_ALL), &uuidIMMDeviceEnumerator)
	if err != nil {
		return err
	}
	enumerator := (*_IMMDeviceEnumerator)(e)
	defer enumerator.Release()

	device, err := enumerator.GetDefaultAudioEndPoint(eRender, eConsole)
	if err != nil {
		return err
	}
	defer device.Release()

	client, err := device.Activate(&uuidIAudioClient2, uint32(_CLSCTX_ALL), nil)
	if err != nil {
		return err
	}
	c.client = (*_IAudioClient2)(client)

	if err := c.client.SetClientProperties(&_AudioClientProperties{
		cbSize:     uint32(unsafe.Sizeof(_AudioClientProperties{})),
		bIsOffload: 0,                    // false
		eCategory:  _AudioCategory_Other, // In the example, AudioCategory_ForegroundOnlyMedia was used, but this value is deprecated.
	}); err != nil {
		return err
	}

	// Check the format is supported by WASAPI.
	// Stereo with 48000 [Hz] is likely supported, but mono and/or other sample rates are unlikely supported.
	// Fallback to WinMM in this case anyway.
	const bitsPerSample = 32
	nBlockAlign := c.channelCount * bitsPerSample / 8
	var channelMask uint32
	switch c.channelCount {
	case 1:
		channelMask = _SPEAKER_FRONT_CENTER
	case 2:
		channelMask = _SPEAKER_FRONT_LEFT | _SPEAKER_FRONT_RIGHT
	}
	f := &_WAVEFORMATEXTENSIBLE{
		wFormatTag:      _WAVE_FORMAT_EXTENSIBLE,
		nChannels:       uint16(c.channelCount),
		nSamplesPerSec:  uint32(c.sampleRate),
		nAvgBytesPerSec: uint32(c.sampleRate * nBlockAlign),
		nBlockAlign:     uint16(nBlockAlign),
		wBitsPerSample:  bitsPerSample,
		cbSize:          0x16,
		Samples:         bitsPerSample,
		dwChannelMask:   channelMask,
		SubFormat:       _KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
	}
	closest, err := c.client.IsFormatSupported(_AUDCLNT_SHAREMODE_SHARED, f)
	if err != nil {
		return err
	}
	if closest != nil {
		return fmt.Errorf("oto: the specified format is not supported (there is the closest format instead)")
	}
	c.mixFormat = f

	if err := c.client.Initialize(_AUDCLNT_SHAREMODE_SHARED,
		_AUDCLNT_STREAMFLAGS_EVENTCALLBACK|_AUDCLNT_STREAMFLAGS_NOPERSIST,
		0, 0, c.mixFormat, nil); err != nil {
		return err
	}

	frames, err := c.client.GetBufferSize()
	if err != nil {
		return err
	}
	c.bufferFrames = frames

	renderClient, err := c.client.GetService(&uuidIAudioRenderClient)
	if err != nil {
		return err
	}
	c.renderClient = (*_IAudioRenderClient)(renderClient)

	ev, err := windows.CreateEventEx(nil, nil, 0, windows.EVENT_ALL_ACCESS)
	if err != nil {
		return err
	}
	c.sampleReadyEvent = ev

	if err := c.client.SetEventHandle(c.sampleReadyEvent); err != nil {
		return err
	}

	// TODO: Should some errors be allowed? See WASAPIManager.cpp in the official example SimpleWASAPIPlaySound.

	if err := c.client.Start(); err != nil {
		return err
	}

	go func() {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()

		if err := _CoInitializeEx(nil, _COINIT_MULTITHREADED); err != nil {
			c.client.Stop()
			c.err.TryStore(err)
			return
		}
		defer _CoUninitialize()

		if err := c.loopOnRenderThread(); err != nil {
			c.client.Stop()
			c.err.TryStore(err)
			return
		}
	}()

	return nil
}

func (c *wasapiContext) loopOnRenderThread() error {
	for {
		evt, err := windows.WaitForSingleObject(c.sampleReadyEvent, 2000)
		if err != nil {
			return err
		}
		if evt != windows.WAIT_OBJECT_0 {
			return fmt.Errorf("oto: WaitForSingleObject failed: returned value: %d", evt)
		}

		if err := c.writeOnRenderThread(); err != nil {
			return err
		}
	}
}

func (c *wasapiContext) writeOnRenderThread() error {
	c.m.Lock()
	defer c.m.Unlock()

	paddingFrames, err := c.client.GetCurrentPadding()
	if err != nil {
		return err
	}

	frames := c.bufferFrames - paddingFrames
	if frames <= 0 {
		return nil
	}

	// Get the destination buffer.
	dstBuf, err := c.renderClient.GetBuffer(frames)
	if err != nil {
		return err
	}

	// Calculate the buffer size.
	buflen := int(frames) * c.channelCount
	if cap(c.buf) < buflen {
		c.buf = make([]float32, buflen)
	} else {
		c.buf = c.buf[:buflen]
	}

	// Read the buffer from the players.
	c.players.read(c.buf)

	// Copy the read buf to the destination buffer.
	var dst []float32
	h := (*reflect.SliceHeader)(unsafe.Pointer(&dst))
	h.Data = uintptr(unsafe.Pointer(dstBuf))
	h.Len = buflen
	h.Cap = buflen
	copy(dst, c.buf)

	// Release the buffer.
	if err := c.renderClient.ReleaseBuffer(frames, 0); err != nil {
		return err
	}

	c.buf = c.buf[:0]
	return nil
}

func (c *wasapiContext) Suspend() error {
	var cerr error
	c.comThread.Run(func() {
		c.m.Lock()
		defer c.m.Unlock()

		if err := c.client.Stop(); err != nil {
			cerr = err
			return
		}
	})
	return cerr
}

func (c *wasapiContext) Resume() error {
	var cerr error
	c.comThread.Run(func() {
		c.m.Lock()
		defer c.m.Unlock()

		if err := c.client.Start(); err != nil {
			cerr = err
			return
		}
	})
	return cerr
}

func (c *wasapiContext) Err() error {
	return c.err.Load()
}
<|endoftext|>


<commit_before>package pager

import (
	"io"
	"os"
	"os/exec"
	"strings"

	"golang.org/x/sync/errgroup"
)

var (
	defaultPager = []string{"less", "-R"}
)

// Page pages content to whichever pager is defined by the PAGER env-var
// (normally /usr/bin/less). If noop is true it's just a pass through.
func Page(noop bool, out io.Writer, run func(out io.Writer) error) error {
	if noop {
		return run(out)
	}
	var eg errgroup.Group
	r, w := io.Pipe()
	eg.Go(func() error {
		return w.CloseWithError(run(w))
	})
	eg.Go(func() error {
		pager := strings.Fields(os.Getenv("PAGER"))
		if len(pager) == 0 {
			pager = defaultPager
		}
		cmd := exec.Command(pager[0], pager[1:]...)
		cmd.Stdin = r
		cmd.Stdout = out
		cmd.Stderr = os.Stderr
		return cmd.Run()
	})
	return eg.Wait()
}
<commit_msg>Adds better flags to less.<commit_after>package pager

import (
	"io"
	"os"
	"os/exec"
	"strings"

	"golang.org/x/sync/errgroup"
)

var (
	defaultPager = []string{"less", "-RFX"}
)

// Page pages content to whichever pager is defined by the PAGER env-var
// (normally /usr/bin/less). If noop is true it's just a pass through.
func Page(noop bool, out io.Writer, run func(out io.Writer) error) error {
	if noop {
		return run(out)
	}
	var eg errgroup.Group
	r, w := io.Pipe()
	eg.Go(func() error {
		return w.CloseWithError(run(w))
	})
	eg.Go(func() error {
		pager := strings.Fields(os.Getenv("PAGER"))
		if len(pager) == 0 {
			pager = defaultPager
		}
		cmd := exec.Command(pager[0], pager[1:]...)
		cmd.Stdin = r
		cmd.Stdout = out
		cmd.Stderr = os.Stderr
		return cmd.Run()
	})
	return eg.Wait()
}
<|endoftext|>


<commit_before>package kip

import (
	"errors"
	"reflect"
	"strings"

	"gopkg.in/mgo.v2/bson"
)

type Item struct { // or interface{} ?????
	Dao       *Dao
	Value     interface{}
	saved     bool
	updated   bool
	updates   *bson.M
	condition *bson.M
}

func (i *Item) Save() error {

	if !i.saved {
		insertErr := i.Dao.Insert(i)
		if nil == insertErr {
			i.saved = true
			i.updated = true
		}

		return insertErr
	}

	if !i.updated {
		selector := bson.M{
			"_id": i.GetId(),
		}
		if nil != i.condition {
			selector = bson.M{
				"$and": []bson.M{
					selector,
					*(i.condition),
				},
			}
		}
		updateErr := i.Dao.update(selector, i.updates)
		if nil == updateErr {
			i.updated = true
		}

		return updateErr
	}

	return errors.New("already saved")
}

func (i *Item) Patch(p *Patch) error {

	if "set" == p.Operation {
		if nil == i.updates {
			i.updates = &bson.M{}
		}

		u := *i.updates

		if _, exists := u["$set"]; !exists {
			u["$set"] = bson.M{}
		}

		// TODO: check value type with type
		// TODO: check mapping bson/json field name

		u["$set"].(bson.M)[p.Key] = p.Value
		i.updated = false
		return nil
	} else if "add_to_set" == p.Operation {
		if nil == i.updates {
			i.updates = &bson.M{}
		}

		u := *i.updates

		if _, exists := u["$addToSet"]; !exists {
			u["$addToSet"] = bson.M{}
		}

		c := u["$addToSet"].(bson.M)

		if _, exists := c[p.Key]; !exists {
			c[p.Key] = bson.M{
				"$each": []interface{}{},
			}
		}

		f := c[p.Key].(bson.M)["$each"].([]interface{})

		c[p.Key].(bson.M)["$each"] = append(f, p.Value)

		i.updated = false
		return nil
	}

	return errors.New("invalid operation")
}

func (i *Item) GetId() interface{} {
	return get_id(i.Value)
}

func get_id(item interface{}) interface{} {
	t := reflect.ValueOf(item)

	// Follow pointers
	for reflect.Ptr == t.Kind() {
		t = t.Elem()
	}

	switch t.Kind() {
	case reflect.Struct:
		// Traverse all fields and search for tag bson:"_id"
		n := t.NumField()
		for i := 0; i < n; i++ {
			field := t.Type().Field(i)
			if word_in_string("_id", field.Tag.Get("bson")) {
				return t.Field(i).Interface()
			}
		}
		// Fallback: search CI for fieldnames 'id'
		for i := 0; i < n; i++ {
			field := t.Type().Field(i)
			if "id" == strings.ToLower(field.Name) {
				return t.Field(i).Interface()
			}
		}
		return nil

	case reflect.Map:
		return t.MapIndex(reflect.ValueOf("_id")).Interface()
	}

	return nil
}

func word_in_string(w string, s string) bool {
	for _, v := range strings.Split(s, " ") {
		if w == v {
			return true
		}
	}
	return false
}

func (i *Item) Delete() error {

	d := i.Dao

	db := d.Database.Clone()
	defer db.Close()

	collection := d.Collection

	return db.C(collection.Name).RemoveId(i.GetId())
}

func (i *Item) Where(condition bson.M) *Item {
	i.condition = &condition

	return i
}

func (i *Item) Reload() error {
	d := i.Dao

	db := d.Database.Clone()
	defer db.Close()

	return db.C(d.Collection.Name).FindId(i.GetId()).One(i.Value)
}
<commit_msg>Add operation `remove_from_set`<commit_after>package kip

import (
	"errors"
	"reflect"
	"strings"

	"gopkg.in/mgo.v2/bson"
)

type Item struct { // or interface{} ?????
	Dao       *Dao
	Value     interface{}
	saved     bool
	updated   bool
	updates   *bson.M
	condition *bson.M
}

func (i *Item) Save() error {

	if !i.saved {
		insertErr := i.Dao.Insert(i)
		if nil == insertErr {
			i.saved = true
			i.updated = true
		}

		return insertErr
	}

	if !i.updated {
		selector := bson.M{
			"_id": i.GetId(),
		}
		if nil != i.condition {
			selector = bson.M{
				"$and": []bson.M{
					selector,
					*(i.condition),
				},
			}
		}
		updateErr := i.Dao.update(selector, i.updates)
		if nil == updateErr {
			i.updated = true
		}

		return updateErr
	}

	return errors.New("already saved")
}

func (i *Item) Patch(p *Patch) error {

	if "set" == p.Operation {
		if nil == i.updates {
			i.updates = &bson.M{}
		}

		u := *i.updates

		if _, exists := u["$set"]; !exists {
			u["$set"] = bson.M{}
		}

		// TODO: check value type with type
		// TODO: check mapping bson/json field name

		u["$set"].(bson.M)[p.Key] = p.Value
		i.updated = false
		return nil
	} else if "add_to_set" == p.Operation {
		if nil == i.updates {
			i.updates = &bson.M{}
		}

		u := *i.updates

		if _, exists := u["$addToSet"]; !exists {
			u["$addToSet"] = bson.M{}
		}

		c := u["$addToSet"].(bson.M)

		if _, exists := c[p.Key]; !exists {
			c[p.Key] = bson.M{
				"$each": []interface{}{},
			}
		}

		f := c[p.Key].(bson.M)["$each"].([]interface{})

		c[p.Key].(bson.M)["$each"] = append(f, p.Value)

		i.updated = false
		return nil
	} else if "remove_from_set" == p.Operation {
		if nil == i.updates {
			i.updates = &bson.M{}
		}

		u := *i.updates

		if _, exists := u["$pull"]; !exists {
			u["$pull"] = bson.M{}
		}

		c := u["$pull"].(bson.M)

		if _, exists := c[p.Key]; !exists {
			c[p.Key] = bson.M{
				"$in": []interface{}{},
			}
		}

		f := c[p.Key].(bson.M)["$in"].([]interface{})

		c[p.Key].(bson.M)["$in"] = append(f, p.Value)

		i.updated = false
		return nil
	}

	return errors.New("invalid operation")
}

func (i *Item) GetId() interface{} {
	return get_id(i.Value)
}

func get_id(item interface{}) interface{} {
	t := reflect.ValueOf(item)

	// Follow pointers
	for reflect.Ptr == t.Kind() {
		t = t.Elem()
	}

	switch t.Kind() {
	case reflect.Struct:
		// Traverse all fields and search for tag bson:"_id"
		n := t.NumField()
		for i := 0; i < n; i++ {
			field := t.Type().Field(i)
			if word_in_string("_id", field.Tag.Get("bson")) {
				return t.Field(i).Interface()
			}
		}
		// Fallback: search CI for fieldnames 'id'
		for i := 0; i < n; i++ {
			field := t.Type().Field(i)
			if "id" == strings.ToLower(field.Name) {
				return t.Field(i).Interface()
			}
		}
		return nil

	case reflect.Map:
		return t.MapIndex(reflect.ValueOf("_id")).Interface()
	}

	return nil
}

func word_in_string(w string, s string) bool {
	for _, v := range strings.Split(s, " ") {
		if w == v {
			return true
		}
	}
	return false
}

func (i *Item) Delete() error {

	d := i.Dao

	db := d.Database.Clone()
	defer db.Close()

	collection := d.Collection

	return db.C(collection.Name).RemoveId(i.GetId())
}

func (i *Item) Where(condition bson.M) *Item {
	i.condition = &condition

	return i
}

func (i *Item) Reload() error {
	d := i.Dao

	db := d.Database.Clone()
	defer db.Close()

	return db.C(d.Collection.Name).FindId(i.GetId()).One(i.Value)
}
<|endoftext|>


<commit_before>// service for exchanging current user settings with UI
package settings

import (
	"net/http"
	"sync"

	"github.com/getlantern/flashlight/analytics"
	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/launcher"

	"github.com/getlantern/flashlight/ui"
	"github.com/getlantern/golog"
)

const (
	messageType = `Settings`
)

var (
	log           = golog.LoggerFor("flashlight.settings")
	service       *ui.Service
	cfgMutex      sync.RWMutex
	settingsMutex sync.RWMutex
	baseSettings  *Settings
	httpClient    *http.Client
)

type Settings struct {
	Version    string
	BuildDate  string
	AutoReport bool
	AutoLaunch bool
}

func Configure(cfg *config.Config, version, buildDate string) {

	cfgMutex.Lock()
	defer cfgMutex.Unlock()

	if service == nil {
		// base settings are always written
		baseSettings = &Settings{
			Version:    version,
			BuildDate:  buildDate,
			AutoReport: *cfg.AutoReport,
			AutoLaunch: *cfg.AutoLaunch,
		}

		err := start(baseSettings)
		if err != nil {
			log.Errorf("Unable to register settings service: %q", err)
			return
		}
		go read()
	} else {
		baseSettings.AutoReport = *cfg.AutoReport
		baseSettings.AutoLaunch = *cfg.AutoLaunch
		launcher.CreateLaunchFile(*cfg.AutoLaunch)
	}
}

// start the settings service
// that synchronizes Lantern's configuration
// with every UI client
func start(baseSettings *Settings) error {
	var err error

	helloFn := func(write func(interface{}) error) error {
		log.Debugf("Sending Lantern settings to new client")
		settingsMutex.RLock()
		defer settingsMutex.RUnlock()
		return write(baseSettings)
	}
	service, err = ui.Register(messageType, nil, helloFn)
	return err
}

func read() {
	for msg := range service.In {
		settings := (msg).(map[string]interface{})
		config.Update(func(updated *config.Config) error {
			if autoReport, ok := settings["autoReport"].(bool); ok {
				// turn on/off analaytics reporting
				if autoReport {
					analytics.StartService()
				} else {
					analytics.StopService()
				}
				baseSettings.AutoReport = autoReport
				*updated.AutoReport = autoReport
			} else if autoLaunch, ok := settings["autoLaunch"].(bool); ok {
				launcher.CreateLaunchFile(autoLaunch)
				baseSettings.AutoLaunch = autoLaunch
				*updated.AutoLaunch = autoLaunch
			}
			return nil
		})
	}
}
<commit_msg>remove print statement<commit_after>// service for exchanging current user settings with UI
package settings

import (
	"net/http"
	"sync"

	"github.com/getlantern/flashlight/analytics"
	"github.com/getlantern/flashlight/config"
	"github.com/getlantern/launcher"

	"github.com/getlantern/flashlight/ui"
	"github.com/getlantern/golog"
)

const (
	messageType = `Settings`
)

var (
	log           = golog.LoggerFor("flashlight.settings")
	service       *ui.Service
	cfgMutex      sync.RWMutex
	settingsMutex sync.RWMutex
	baseSettings  *Settings
	httpClient    *http.Client
)

type Settings struct {
	Version    string
	BuildDate  string
	AutoReport bool
	AutoLaunch bool
}

func Configure(cfg *config.Config, version, buildDate string) {

	cfgMutex.Lock()
	defer cfgMutex.Unlock()

	if service == nil {
		// base settings are always written
		baseSettings = &Settings{
			Version:    version,
			BuildDate:  buildDate,
			AutoReport: *cfg.AutoReport,
			AutoLaunch: *cfg.AutoLaunch,
		}

		err := start(baseSettings)
		if err != nil {
			log.Errorf("Unable to register settings service: %q", err)
			return
		}
		go read()
	} else {
		if *cfg.AutoLaunch != baseSettings.AutoLaunch {
			// autolaunch setting modified on disk
			launcher.CreateLaunchFile(*cfg.AutoLaunch)
		}
		baseSettings.AutoReport = *cfg.AutoReport
		baseSettings.AutoLaunch = *cfg.AutoLaunch
	}
}

// start the settings service
// that synchronizes Lantern's configuration
// with every UI client
func start(baseSettings *Settings) error {
	var err error

	helloFn := func(write func(interface{}) error) error {
		log.Debugf("Sending Lantern settings to new client")
		settingsMutex.RLock()
		defer settingsMutex.RUnlock()
		return write(baseSettings)
	}
	service, err = ui.Register(messageType, nil, helloFn)
	return err
}

func read() {
	for msg := range service.In {
		settings := (msg).(map[string]interface{})
		config.Update(func(updated *config.Config) error {
			if autoReport, ok := settings["autoReport"].(bool); ok {
				// turn on/off analaytics reporting
				if autoReport {
					analytics.StartService()
				} else {
					analytics.StopService()
				}
				baseSettings.AutoReport = autoReport
				*updated.AutoReport = autoReport
			} else if autoLaunch, ok := settings["autoLaunch"].(bool); ok {
				launcher.CreateLaunchFile(autoLaunch)
				baseSettings.AutoLaunch = autoLaunch
				*updated.AutoLaunch = autoLaunch
			}
			return nil
		})
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fake

import (
	"context"
	"fmt"
	"testing"

	"k8s.io/apimachinery/pkg/api/equality"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/diff"
)

const (
	testGroup      = "testgroup"
	testVersion    = "testversion"
	testResource   = "testkinds"
	testNamespace  = "testns"
	testName       = "testname"
	testKind       = "TestKind"
	testAPIVersion = "testgroup/testversion"
)

func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
	return &unstructured.Unstructured{
		Object: map[string]interface{}{
			"apiVersion": apiVersion,
			"kind":       kind,
			"metadata": map[string]interface{}{
				"namespace": namespace,
				"name":      name,
			},
		},
	}
}

func newUnstructuredWithSpec(spec map[string]interface{}) *unstructured.Unstructured {
	u := newUnstructured(testAPIVersion, testKind, testNamespace, testName)
	u.Object["spec"] = spec
	return u
}

func TestList(t *testing.T) {
	scheme := runtime.NewScheme()

	client := NewSimpleDynamicClient(scheme,
		newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
		newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"),
		newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
		newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
		newUnstructured("group2/version", "TheKind", "ns-foo", "name2-baz"),
	)
	listFirst, err := client.Resource(schema.GroupVersionResource{Group: "group", Version: "version", Resource: "thekinds"}).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		t.Fatal(err)
	}

	expected := []unstructured.Unstructured{
		*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
		*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
		*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
	}
	if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
		t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
	}
}

type patchTestCase struct {
	name                  string
	object                runtime.Object
	patchType             types.PatchType
	patchBytes            []byte
	wantErrMsg            string
	expectedPatchedObject runtime.Object
}

func (tc *patchTestCase) runner(t *testing.T) {
	client := NewSimpleDynamicClient(runtime.NewScheme(), tc.object)
	resourceInterface := client.Resource(schema.GroupVersionResource{Group: testGroup, Version: testVersion, Resource: testResource}).Namespace(testNamespace)

	got, recErr := resourceInterface.Patch(context.TODO(), testName, tc.patchType, tc.patchBytes, metav1.PatchOptions{})

	if err := tc.verifyErr(recErr); err != nil {
		t.Error(err)
	}

	if err := tc.verifyResult(got); err != nil {
		t.Error(err)
	}

}

// verifyErr verifies that the given error returned from Patch is the error
// expected by the test case.
func (tc *patchTestCase) verifyErr(err error) error {
	if tc.wantErrMsg != "" && err == nil {
		return fmt.Errorf("want error, got nil")
	}

	if tc.wantErrMsg == "" && err != nil {
		return fmt.Errorf("want no error, got %v", err)
	}

	if err != nil {
		if want, got := tc.wantErrMsg, err.Error(); want != got {
			return fmt.Errorf("incorrect error: want: %q got: %q", want, got)
		}
	}
	return nil
}

func (tc *patchTestCase) verifyResult(result *unstructured.Unstructured) error {
	if tc.expectedPatchedObject == nil && result == nil {
		return nil
	}
	if !equality.Semantic.DeepEqual(result, tc.expectedPatchedObject) {
		return fmt.Errorf("unexpected diff in received object: %s", diff.ObjectGoPrintDiff(tc.expectedPatchedObject, result))
	}
	return nil
}

func TestPatch(t *testing.T) {
	testCases := []patchTestCase{
		{
			name:       "jsonpatch fails with merge type",
			object:     newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType:  types.StrategicMergePatchType,
			patchBytes: []byte(`[]`),
			wantErrMsg: "invalid JSON document",
		}, {
			name:      "jsonpatch works with empty patch",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.JSONPatchType,
			// No-op
			patchBytes:            []byte(`[]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
		}, {
			name:      "jsonpatch works with simple change patch",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.JSONPatchType,
			// change spec.foo from bar to foobar
			patchBytes:            []byte(`[{"op": "replace", "path": "/spec/foo", "value": "foobar"}]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "foobar"}),
		}, {
			name:      "jsonpatch works with simple addition",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.JSONPatchType,
			// add spec.newvalue = dummy
			patchBytes:            []byte(`[{"op": "add", "path": "/spec/newvalue", "value": "dummy"}]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "bar", "newvalue": "dummy"}),
		}, {
			name:      "jsonpatch works with simple deletion",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar", "toremove": "shouldnotbehere"}),
			patchType: types.JSONPatchType,
			// remove spec.newvalue = dummy
			patchBytes:            []byte(`[{"op": "remove", "path": "/spec/toremove"}]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
		}, {
			name:      "strategic merge patch fails with JSONPatch",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.StrategicMergePatchType,
			// add spec.newvalue = dummy
			patchBytes: []byte(`[{"op": "add", "path": "/spec/newvalue", "value": "dummy"}]`),
			wantErrMsg: "invalid JSON document",
		}, {
			name:                  "merge patch works with simple replacement",
			object:                newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType:             types.MergePatchType,
			patchBytes:            []byte(`{ "spec": { "foo": "baz" } }`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "baz"}),
		},
		// TODO: Add tests for strategic merge using v1.Pod for example to ensure the test cases
		// demonstrate expected use cases.
	}

	for _, tc := range testCases {
		t.Run(tc.name, tc.runner)
	}
}
<commit_msg>fake dynamic client: support *List kinds<commit_after>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package fake

import (
	"context"
	"fmt"
	"testing"

	"k8s.io/apimachinery/pkg/api/equality"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/diff"
)

const (
	testGroup      = "testgroup"
	testVersion    = "testversion"
	testResource   = "testkinds"
	testNamespace  = "testns"
	testName       = "testname"
	testKind       = "TestKind"
	testAPIVersion = "testgroup/testversion"
)

func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
	return &unstructured.Unstructured{
		Object: map[string]interface{}{
			"apiVersion": apiVersion,
			"kind":       kind,
			"metadata": map[string]interface{}{
				"namespace": namespace,
				"name":      name,
			},
		},
	}
}

func newUnstructuredWithSpec(spec map[string]interface{}) *unstructured.Unstructured {
	u := newUnstructured(testAPIVersion, testKind, testNamespace, testName)
	u.Object["spec"] = spec
	return u
}

func TestList(t *testing.T) {
	scheme := runtime.NewScheme()

	client := NewSimpleDynamicClient(scheme,
		newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
		newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"),
		newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
		newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
		newUnstructured("group2/version", "TheKind", "ns-foo", "name2-baz"),
	)
	listFirst, err := client.Resource(schema.GroupVersionResource{Group: "group", Version: "version", Resource: "thekinds"}).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		t.Fatal(err)
	}

	expected := []unstructured.Unstructured{
		*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
		*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
		*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
	}
	if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
		t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
	}
}

func Test_ListKind(t *testing.T) {
	scheme := runtime.NewScheme()

	client := NewSimpleDynamicClient(scheme,
		&unstructured.UnstructuredList{
			Object: map[string]interface{}{
				"apiVersion": "group/version",
				"kind":       "TheKindList",
			},
			Items: []unstructured.Unstructured{
				*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
				*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
				*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
			},
		},
	)
	listFirst, err := client.Resource(schema.GroupVersionResource{Group: "group", Version: "version", Resource: "thekinds"}).List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		t.Fatal(err)
	}

	expectedList := &unstructured.UnstructuredList{
		Object: map[string]interface{}{
			"apiVersion": "group/version",
			"kind":       "TheKindList",
			"metadata": map[string]interface{}{
				"resourceVersion": "",
			},
		},
		Items: []unstructured.Unstructured{
			*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
			*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
			*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
		},
	}
	if !equality.Semantic.DeepEqual(listFirst, expectedList) {
		t.Fatal(diff.ObjectGoPrintDiff(expectedList, listFirst))
	}
}

type patchTestCase struct {
	name                  string
	object                runtime.Object
	patchType             types.PatchType
	patchBytes            []byte
	wantErrMsg            string
	expectedPatchedObject runtime.Object
}

func (tc *patchTestCase) runner(t *testing.T) {
	client := NewSimpleDynamicClient(runtime.NewScheme(), tc.object)
	resourceInterface := client.Resource(schema.GroupVersionResource{Group: testGroup, Version: testVersion, Resource: testResource}).Namespace(testNamespace)

	got, recErr := resourceInterface.Patch(context.TODO(), testName, tc.patchType, tc.patchBytes, metav1.PatchOptions{})

	if err := tc.verifyErr(recErr); err != nil {
		t.Error(err)
	}

	if err := tc.verifyResult(got); err != nil {
		t.Error(err)
	}

}

// verifyErr verifies that the given error returned from Patch is the error
// expected by the test case.
func (tc *patchTestCase) verifyErr(err error) error {
	if tc.wantErrMsg != "" && err == nil {
		return fmt.Errorf("want error, got nil")
	}

	if tc.wantErrMsg == "" && err != nil {
		return fmt.Errorf("want no error, got %v", err)
	}

	if err != nil {
		if want, got := tc.wantErrMsg, err.Error(); want != got {
			return fmt.Errorf("incorrect error: want: %q got: %q", want, got)
		}
	}
	return nil
}

func (tc *patchTestCase) verifyResult(result *unstructured.Unstructured) error {
	if tc.expectedPatchedObject == nil && result == nil {
		return nil
	}
	if !equality.Semantic.DeepEqual(result, tc.expectedPatchedObject) {
		return fmt.Errorf("unexpected diff in received object: %s", diff.ObjectGoPrintDiff(tc.expectedPatchedObject, result))
	}
	return nil
}

func TestPatch(t *testing.T) {
	testCases := []patchTestCase{
		{
			name:       "jsonpatch fails with merge type",
			object:     newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType:  types.StrategicMergePatchType,
			patchBytes: []byte(`[]`),
			wantErrMsg: "invalid JSON document",
		}, {
			name:      "jsonpatch works with empty patch",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.JSONPatchType,
			// No-op
			patchBytes:            []byte(`[]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
		}, {
			name:      "jsonpatch works with simple change patch",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.JSONPatchType,
			// change spec.foo from bar to foobar
			patchBytes:            []byte(`[{"op": "replace", "path": "/spec/foo", "value": "foobar"}]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "foobar"}),
		}, {
			name:      "jsonpatch works with simple addition",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.JSONPatchType,
			// add spec.newvalue = dummy
			patchBytes:            []byte(`[{"op": "add", "path": "/spec/newvalue", "value": "dummy"}]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "bar", "newvalue": "dummy"}),
		}, {
			name:      "jsonpatch works with simple deletion",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar", "toremove": "shouldnotbehere"}),
			patchType: types.JSONPatchType,
			// remove spec.newvalue = dummy
			patchBytes:            []byte(`[{"op": "remove", "path": "/spec/toremove"}]`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
		}, {
			name:      "strategic merge patch fails with JSONPatch",
			object:    newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType: types.StrategicMergePatchType,
			// add spec.newvalue = dummy
			patchBytes: []byte(`[{"op": "add", "path": "/spec/newvalue", "value": "dummy"}]`),
			wantErrMsg: "invalid JSON document",
		}, {
			name:                  "merge patch works with simple replacement",
			object:                newUnstructuredWithSpec(map[string]interface{}{"foo": "bar"}),
			patchType:             types.MergePatchType,
			patchBytes:            []byte(`{ "spec": { "foo": "baz" } }`),
			expectedPatchedObject: newUnstructuredWithSpec(map[string]interface{}{"foo": "baz"}),
		},
		// TODO: Add tests for strategic merge using v1.Pod for example to ensure the test cases
		// demonstrate expected use cases.
	}

	for _, tc := range testCases {
		t.Run(tc.name, tc.runner)
	}
}
<|endoftext|>


<commit_before>package application

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/mholt/binding"
	"net/http"
)

func NotFoundHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "404 not found", http.StatusNotFound)
	})
}

type Handler func(Response, *Request, *Application)

var ImageHandler Handler = func(res Response, req *Request, app *Application) {
	file, err := app.ImageFileFromRequest(req, true, true)

	if err != nil {
		panic(err)
	}

	res.SetHeaders(file.Headers, true)
	res.ResponseWriter.Write(file.Content())
}

var UploadHandler = func(res Response, req *http.Request, app *Application) {
	if !app.EnableUpload {
		res.Forbidden()
		return
	}

	if app.SourceStorage == nil {
		res.Abort(500, "Your application doesn't have a source storage")
		return
	}

	var err error

	multipartForm := new(MultipartForm)
	errs := binding.Bind(req, multipartForm)
	if errs.Handle(res) {
		return
	}

	file, err := multipartForm.Upload(app.SourceStorage)

	if err != nil {
		panic(err)
	}

	content, err := json.Marshal(map[string]string{
		"filename": file.Filename(),
		"path":     file.Path(),
		"url":      file.URL(),
	})

	if err != nil {
		panic(err)
	}

	res.ContentType("application/json")
	res.ResponseWriter.Write(content)
}

var DeleteHandler = func(res Response, req *http.Request, app *Application) {
	if app.SourceStorage == nil {
		res.Abort(500, "Your application doesn't have a source storage")
		return
	}

	params := mux.Vars(req)

	filename := params["path"]

	// Delete the image from the source storage right away.
	// Upcoming requests will be able to read stuff from cache, but never
	// create new things after we've deleted the source image.
	//
	// Don't care about an error here. If it's not there, then whatever..
	// Keep going...
	app.Logger.Infof("Deleting source storage file: %s", filename)
	_ = app.SourceStorage.Delete(filename)

	// We can clean up the rest now. Again, don't care about errors.
	// ImageCleanup always succeeds.
	app.ImageCleanup(filename)

	content, err := json.Marshal(map[string]string{
		"filename": filename,
	})

	if err != nil {
		panic(err)
	}

	res.ContentType("application/json")
	res.ResponseWriter.Write(content)
}

var GetHandler Handler = func(res Response, req *Request, app *Application) {
	file, err := app.ImageFileFromRequest(req, false, false)

	if err != nil {
		panic(err)
	}

	content, err := json.Marshal(map[string]string{
		"filename": file.Filename(),
		"path":     file.Path(),
		"url":      file.URL(),
	})

	if err != nil {
		panic(err)
	}

	res.ContentType("application/json")
	res.ResponseWriter.Write(content)
}

var RedirectHandler Handler = func(res Response, req *Request, app *Application) {
	file, err := app.ImageFileFromRequest(req, false, false)

	if err != nil {
		panic(err)
	}

	res.PermanentRedirect(file.URL())
}
<commit_msg>Set status 201 and add Location header on upload.<commit_after>package application

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/mholt/binding"
	"net/http"
)

func NotFoundHandler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "404 not found", http.StatusNotFound)
	})
}

type Handler func(Response, *Request, *Application)

var ImageHandler Handler = func(res Response, req *Request, app *Application) {
	file, err := app.ImageFileFromRequest(req, true, true)

	if err != nil {
		panic(err)
	}

	res.SetHeaders(file.Headers, true)
	res.ResponseWriter.Write(file.Content())
}

var UploadHandler = func(res Response, req *http.Request, app *Application) {
	if !app.EnableUpload {
		res.Forbidden()
		return
	}

	if app.SourceStorage == nil {
		res.Abort(500, "Your application doesn't have a source storage")
		return
	}

	var err error

	multipartForm := new(MultipartForm)
	errs := binding.Bind(req, multipartForm)
	if errs.Handle(res) {
		return
	}

	file, err := multipartForm.Upload(app.SourceStorage)

	if err != nil {
		panic(err)
	}

	content, err := json.Marshal(map[string]string{
		"filename": file.Filename(),
		"path":     file.Path(),
		"url":      file.URL(),
	})

	if err != nil {
		panic(err)
	}

	res.Header().Add("Location", file.URL())
	res.ContentType("application/json")
	res.ResponseWriter.WriteHeader(http.StatusCreated)
	res.ResponseWriter.Write(content)
}

var DeleteHandler = func(res Response, req *http.Request, app *Application) {
	if app.SourceStorage == nil {
		res.Abort(500, "Your application doesn't have a source storage")
		return
	}

	params := mux.Vars(req)

	filename := params["path"]

	// Delete the image from the source storage right away.
	// Upcoming requests will be able to read stuff from cache, but never
	// create new things after we've deleted the source image.
	//
	// Don't care about an error here. If it's not there, then whatever..
	// Keep going...
	app.Logger.Infof("Deleting source storage file: %s", filename)
	_ = app.SourceStorage.Delete(filename)

	// We can clean up the rest now. Again, don't care about errors.
	// ImageCleanup always succeeds.
	app.ImageCleanup(filename)

	content, err := json.Marshal(map[string]string{
		"filename": filename,
	})

	if err != nil {
		panic(err)
	}

	res.ContentType("application/json")
	res.ResponseWriter.Write(content)
}

var GetHandler Handler = func(res Response, req *Request, app *Application) {
	file, err := app.ImageFileFromRequest(req, false, false)

	if err != nil {
		panic(err)
	}

	content, err := json.Marshal(map[string]string{
		"filename": file.Filename(),
		"path":     file.Path(),
		"url":      file.URL(),
	})

	if err != nil {
		panic(err)
	}

	res.ContentType("application/json")
	res.ResponseWriter.Write(content)
}

var RedirectHandler Handler = func(res Response, req *Request, app *Application) {
	file, err := app.ImageFileFromRequest(req, false, false)

	if err != nil {
		panic(err)
	}

	res.PermanentRedirect(file.URL())
}
<|endoftext|>