<commit_before>/*
Copyright 2019 The Knative 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

    https://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 network

import (
	"net/http"
	"strings"
	"time"
)

const (
	// DefaultConnTimeout specifies a short default connection timeout
	// to avoid hitting the issue fixed in
	// https://github.com/kubernetes/kubernetes/pull/72534 but only
	// avalailable after Kubernetes 1.14.
	//
	// Our connections are usually between pods in the same cluster
	// like activator <-> queue-proxy, or even between containers
	// within the same pod queue-proxy <-> user-container, so a
	// smaller connect timeout would be justifiable.
	//
	// We should consider exposing this as a configuration.
	DefaultConnTimeout = 200 * time.Millisecond

	// DefaultDrainTimeout is the time that Knative components on the data
	// path will wait before shutting down server, but after starting to fail
	// readiness probes to ensure network layer propagation and so that no requests
	// are routed to this pod.
	DefaultDrainTimeout = 30 * time.Second

	// UserAgentKey is the constant for header "User-Agent".
	UserAgentKey = "User-Agent"

	// ProbeHeaderName is the name of a header that can be added to
	// requests to probe the knative networking layer.  Requests
	// with this header will not be passed to the user container or
	// included in request metrics.
	ProbeHeaderName = "K-Network-Probe"

	// Since K8s 1.8, prober requests have
	//   User-Agent = "kube-probe/{major-version}.{minor-version}".
	KubeProbeUAPrefix = "kube-probe/"

	// Istio with mTLS rewrites probes, but their probes pass a different
	// user-agent.  So we augment the probes with this header.
	KubeletProbeHeaderName = "K-Kubelet-Probe"
)

// IsKubeletProbe returns true if the request is a Kubernetes probe.
func IsKubeletProbe(r *http.Request) bool {
	return strings.HasPrefix(r.Header.Get("User-Agent"), KubeProbeUAPrefix) ||
		r.Header.Get(KubeletProbeHeaderName) != ""
}
<commit_msg>Bump the drain timeout (#1501)<commit_after>/*
Copyright 2019 The Knative 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

    https://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 network

import (
	"net/http"
	"strings"
	"time"
)

const (
	// DefaultConnTimeout specifies a short default connection timeout
	// to avoid hitting the issue fixed in
	// https://github.com/kubernetes/kubernetes/pull/72534 but only
	// avalailable after Kubernetes 1.14.
	//
	// Our connections are usually between pods in the same cluster
	// like activator <-> queue-proxy, or even between containers
	// within the same pod queue-proxy <-> user-container, so a
	// smaller connect timeout would be justifiable.
	//
	// We should consider exposing this as a configuration.
	DefaultConnTimeout = 200 * time.Millisecond

	// DefaultDrainTimeout is the time that Knative components on the data
	// path will wait before shutting down server, but after starting to fail
	// readiness probes to ensure network layer propagation and so that no requests
	// are routed to this pod.
	// Note that this was bumped from 30s due to intermittent issues where
	// the webhook would get a bad request from the API Server when running
	// under chaos.
	DefaultDrainTimeout = 45 * time.Second

	// UserAgentKey is the constant for header "User-Agent".
	UserAgentKey = "User-Agent"

	// ProbeHeaderName is the name of a header that can be added to
	// requests to probe the knative networking layer.  Requests
	// with this header will not be passed to the user container or
	// included in request metrics.
	ProbeHeaderName = "K-Network-Probe"

	// Since K8s 1.8, prober requests have
	//   User-Agent = "kube-probe/{major-version}.{minor-version}".
	KubeProbeUAPrefix = "kube-probe/"

	// Istio with mTLS rewrites probes, but their probes pass a different
	// user-agent.  So we augment the probes with this header.
	KubeletProbeHeaderName = "K-Kubelet-Probe"
)

// IsKubeletProbe returns true if the request is a Kubernetes probe.
func IsKubeletProbe(r *http.Request) bool {
	return strings.HasPrefix(r.Header.Get("User-Agent"), KubeProbeUAPrefix) ||
		r.Header.Get(KubeletProbeHeaderName) != ""
}
<|endoftext|>


<commit_before>package sentry

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/mozilla-services/go-bouncer/bouncer"
)

// The default http.Client for HeadLocation
var DefaultClient = &http.Client{
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		if len(via) >= 1 {
			return errors.New("Stopped after 1 redirect")
		}
		return nil
	},
}

// Sentry contains sentry operations
type Sentry struct {
	DB      *bouncer.DB
	Verbose bool

	locations   []*bouncer.LocationsActiveResult
	mirrors     []*bouncer.MirrorsActiveResult
	startTime   time.Time
	runLck      sync.Mutex
	locationSem chan bool
	mirrorSem   chan bool

	client       *http.Client
	roundTripper http.RoundTripper
}

// New returns a new Sentry
func New(db *bouncer.DB, checknow bool, mirror string, mirrorRoutines, locRoutines int) (*Sentry, error) {
	locations, err := db.LocationsActive(checknow)
	if err != nil {
		return nil, fmt.Errorf("db.LocationsActive: %v", err)
	}

	mirrors, err := db.MirrorsActive(mirror)
	if err != nil {
		return nil, fmt.Errorf("db.MirrorsActive: %v", err)
	}

	return &Sentry{
		DB:           db,
		locations:    locations,
		mirrors:      mirrors,
		locationSem:  make(chan bool, locRoutines),
		mirrorSem:    make(chan bool, mirrorRoutines),
		client:       DefaultClient,
		roundTripper: http.DefaultTransport,
	}, nil
}

// Run starts a full sentry run
func (s *Sentry) Run() error {
	s.runLck.Lock()
	defer s.runLck.Unlock()

	wg := sync.WaitGroup{}

	s.startTime = time.Now()
	for _, mirror := range s.mirrors {
		s.mirrorSem <- true
		wg.Add(1)
		go func(mirror *bouncer.MirrorsActiveResult) {
			defer func() {
				<-s.mirrorSem
				wg.Done()
			}()
			if err := s.checkMirror(mirror); err != nil {
				log.Printf("Error checking mirror: %s err: %s", mirror.BaseURL, err)
			}
		}(mirror)
	}

	wg.Wait()
	return nil
}

func boolToString(b bool) string {
	if b {
		return "1"
	}
	return "0"
}

type checkLocationResult struct {
	Active  bool
	Healthy bool
}

func (s *Sentry) checkLocation(mirror *bouncer.MirrorsActiveResult, location *bouncer.LocationsActiveResult, runLog *lockedWriter) *checkLocationResult {
	lang := "en-US"

	if strings.Contains(location.Path, "/firefox/") &&
		!strings.Contains(location.Path, "/namoroka/") &&
		!strings.Contains(location.Path, "/devpreview/") &&
		!strings.Contains(location.Path, "3.6b1") &&
		!strings.Contains(location.Path, "wince-arm") &&
		!strings.Contains(strings.ToLower(location.Path), "euballot") {

		lang = "zh-TW"
	} else if strings.Contains(location.Path, "/thunderbird/") {
		if strings.Contains(location.Path, "3.1a1") {
			lang = "tr"
		} else {
			lang = "zh-TW"
		}
	} else if strings.Contains(location.Path, "/seamonkey/") {
		if strings.Contains(location.Path, "2.0.5") || strings.Contains(location.Path, "2.0.6") {
			lang = "zh-CN"
		} else {
			lang = "tr"
		}
	} else if strings.Contains(strings.ToLower(location.Path), "-euballot") {
		lang = "sv-SE"
	}

	path := strings.Replace(location.Path, ":lang", lang, -1)
	url := mirror.BaseURL + path

	start := time.Now()
	active, healthy := true, false

	resp, err := s.HeadLocation(url)
	elapsed := time.Now().Sub(start)
	if err != nil {
		runLog.Printf("%s TOOK=%v ERR=%v\n", url, elapsed, err)
		return &checkLocationResult{Active: true, Healthy: false}
	}
	defer resp.Body.Close()

	if resp.StatusCode == 200 && !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
		active, healthy = true, true
	} else if resp.StatusCode == 404 || resp.StatusCode == 403 {
		active, healthy = false, false
	}

	runLog.Printf("%s TOOK=%v RC=%d\n", url, elapsed, resp.StatusCode)
	return &checkLocationResult{Active: active, Healthy: healthy}
}

func (s *Sentry) checkMirror(mirror *bouncer.MirrorsActiveResult) error {
	runLog := newLockedWriter()
	runLog.Printf("Checking mirror %s ...\n", mirror.BaseURL)

	// Check overall mirror health
	err := s.HeadMirror(mirror)
	if err != nil {
		if dberr := s.DB.MirrorSetHealth(mirror.ID, "0"); dberr != nil {
			return fmt.Errorf("MirrorSetHealth: %v", dberr)
		}
		if dberr := s.DB.SentryLogInsert(s.startTime, mirror.ID, "0", mirror.Rating, err.Error()); dberr != nil {
			return fmt.Errorf("SentryLogInsert: %v", dberr)
		}
		return fmt.Errorf("HeadMirror: %v", err)
	}

	// Check locations
	wg := sync.WaitGroup{}
	for _, location := range s.locations {
		s.locationSem <- true
		wg.Add(1)
		go func(location *bouncer.LocationsActiveResult) {
			defer func() {
				<-s.locationSem
				wg.Done()
			}()

			res := s.checkLocation(mirror, location, runLog)
			if err := s.DB.MirrorLocationUpdate(location.ID, mirror.ID, boolToString(res.Active), boolToString(res.Healthy)); err != nil {
				runLog.Printf("MirrorLocationUpdate err: %v", err)
				return
			}

		}(location)
	}

	wg.Wait()

	if err := s.DB.SentryLogInsert(s.startTime, mirror.ID, "1", mirror.Rating, runLog.String()); err != nil {
		log.Println(err)
	}

	if s.Verbose {
		log.Println(runLog.String())
	}

	return nil
}

// HeadMirror returns error if mirror is not healthy
func (s *Sentry) HeadMirror(mirror *bouncer.MirrorsActiveResult) error {
	// Check DNS?

	req, err := http.NewRequest("HEAD", mirror.BaseURL, nil)
	if err != nil {
		return err
	}

	resp, err := s.roundTripper.RoundTrip(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 500 {
		return fmt.Errorf("Bad Response: %s", resp.Status)
	}
	return nil

}

// HeadLocation makes a HEAD request to url and returns the response
func (s *Sentry) HeadLocation(url string) (resp *http.Response, err error) {

	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req)
}
<commit_msg>sentry: log with logrus<commit_after>package sentry

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/mozilla-services/go-bouncer/bouncer"
)

// The default http.Client for HeadLocation
var DefaultClient = &http.Client{
	CheckRedirect: func(req *http.Request, via []*http.Request) error {
		if len(via) >= 1 {
			return errors.New("Stopped after 1 redirect")
		}
		return nil
	},
}

// Sentry contains sentry operations
type Sentry struct {
	DB      *bouncer.DB
	Verbose bool

	locations   []*bouncer.LocationsActiveResult
	mirrors     []*bouncer.MirrorsActiveResult
	startTime   time.Time
	runLck      sync.Mutex
	locationSem chan bool
	mirrorSem   chan bool

	client       *http.Client
	roundTripper http.RoundTripper
}

// New returns a new Sentry
func New(db *bouncer.DB, checknow bool, mirror string, mirrorRoutines, locRoutines int) (*Sentry, error) {
	locations, err := db.LocationsActive(checknow)
	if err != nil {
		return nil, fmt.Errorf("db.LocationsActive: %v", err)
	}

	mirrors, err := db.MirrorsActive(mirror)
	if err != nil {
		return nil, fmt.Errorf("db.MirrorsActive: %v", err)
	}

	return &Sentry{
		DB:           db,
		locations:    locations,
		mirrors:      mirrors,
		locationSem:  make(chan bool, locRoutines),
		mirrorSem:    make(chan bool, mirrorRoutines),
		client:       DefaultClient,
		roundTripper: http.DefaultTransport,
	}, nil
}

// Run starts a full sentry run
func (s *Sentry) Run() error {
	s.runLck.Lock()
	defer s.runLck.Unlock()

	wg := sync.WaitGroup{}

	s.startTime = time.Now()
	for _, mirror := range s.mirrors {
		s.mirrorSem <- true
		wg.Add(1)
		go func(mirror *bouncer.MirrorsActiveResult) {
			defer func() {
				<-s.mirrorSem
				wg.Done()
			}()
			if err := s.checkMirror(mirror); err != nil {
				log.Printf("Error checking mirror: %s err: %s", mirror.BaseURL, err)
			}
		}(mirror)
	}

	wg.Wait()
	return nil
}

func boolToString(b bool) string {
	if b {
		return "1"
	}
	return "0"
}

type checkLocationResult struct {
	Active  bool
	Healthy bool
}

func (s *Sentry) checkLocation(mirror *bouncer.MirrorsActiveResult, location *bouncer.LocationsActiveResult, mirrorLog *logrus.Entry) *checkLocationResult {
	locationLog := mirrorLog.WithFields(logrus.Fields{
		"location": location.Path,
	})

	lang := "en-US"

	if strings.Contains(location.Path, "/firefox/") &&
		!strings.Contains(location.Path, "/namoroka/") &&
		!strings.Contains(location.Path, "/devpreview/") &&
		!strings.Contains(location.Path, "3.6b1") &&
		!strings.Contains(location.Path, "wince-arm") &&
		!strings.Contains(strings.ToLower(location.Path), "euballot") {

		lang = "zh-TW"
	} else if strings.Contains(location.Path, "/thunderbird/") {
		if strings.Contains(location.Path, "3.1a1") {
			lang = "tr"
		} else {
			lang = "zh-TW"
		}
	} else if strings.Contains(location.Path, "/seamonkey/") {
		if strings.Contains(location.Path, "2.0.5") || strings.Contains(location.Path, "2.0.6") {
			lang = "zh-CN"
		} else {
			lang = "tr"
		}
	} else if strings.Contains(strings.ToLower(location.Path), "-euballot") {
		lang = "sv-SE"
	}

	path := strings.Replace(location.Path, ":lang", lang, -1)
	url := mirror.BaseURL + path

	start := time.Now()
	active, healthy := true, false

	resp, err := s.HeadLocation(url)
	elapsed := time.Now().Sub(start)
	if err != nil {
		locationLog.WithError(err).Errorf("%s TOOK=%v", url, elapsed)
		return &checkLocationResult{Active: true, Healthy: false}
	}
	defer resp.Body.Close()

	if resp.StatusCode == 200 && !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
		active, healthy = true, true
	} else if resp.StatusCode == 404 || resp.StatusCode == 403 {
		active, healthy = false, false
	}

	locationLog.Infof("%s TOOK=%v RC=%d", url, elapsed, resp.StatusCode)
	return &checkLocationResult{Active: active, Healthy: healthy}
}

func (s *Sentry) checkMirror(mirror *bouncer.MirrorsActiveResult) error {
	mirrorLog := logrus.WithFields(logrus.Fields{
		"mirror": mirror.BaseURL,
	})

	mirrorLog.Infof("Checking mirror...")

	startTime := time.Now()

	// Check overall mirror health
	err := s.HeadMirror(mirror)
	if err != nil {
		mirrorLog.WithError(err).Error("Mirror HEAD failed")
		if dberr := s.DB.MirrorSetHealth(mirror.ID, "0"); dberr != nil {
			return fmt.Errorf("MirrorSetHealth: %v", dberr)
		}
		if dberr := s.DB.SentryLogInsert(s.startTime, mirror.ID, "0", mirror.Rating, err.Error()); dberr != nil {
			return fmt.Errorf("SentryLogInsert: %v", dberr)
		}
		return fmt.Errorf("HeadMirror: %v", err)
	}

	// Check locations
	wg := sync.WaitGroup{}
	for _, location := range s.locations {
		s.locationSem <- true
		wg.Add(1)
		go func(location *bouncer.LocationsActiveResult) {
			defer func() {
				<-s.locationSem
				wg.Done()
			}()

			res := s.checkLocation(mirror, location, mirrorLog)
			if err := s.DB.MirrorLocationUpdate(location.ID, mirror.ID, boolToString(res.Active), boolToString(res.Healthy)); err != nil {
				mirrorLog.WithError(err).Error("MirrorLocationUpdate failed")
				return
			}

		}(location)
	}

	wg.Wait()

	elapsed := time.Now().Sub(startTime)
	mirrorLog.Infof("Finished in %v", elapsed)
	if err := s.DB.SentryLogInsert(s.startTime, mirror.ID, "1", mirror.Rating, fmt.Sprintf("%s finished in %v", mirror.BaseURL, elapsed)); err != nil {
		log.Println(err)
	}

	return nil
}

// HeadMirror returns error if mirror is not healthy
func (s *Sentry) HeadMirror(mirror *bouncer.MirrorsActiveResult) error {
	// Check DNS?

	req, err := http.NewRequest("HEAD", mirror.BaseURL, nil)
	if err != nil {
		return err
	}

	resp, err := s.roundTripper.RoundTrip(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 500 {
		return fmt.Errorf("Bad Response: %s", resp.Status)
	}
	return nil

}

// HeadLocation makes a HEAD request to url and returns the response
func (s *Sentry) HeadLocation(url string) (resp *http.Response, err error) {

	req, err := http.NewRequest("HEAD", url, nil)
	if err != nil {
		return nil, err
	}

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


<commit_before>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
//
// +build !windows

package libfuse

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strings"

	"bazil.org/fuse"
	"github.com/keybase/client/go/kbconst"
	"github.com/keybase/client/go/logger"
)

type mounter struct {
	options StartOptions
	c       *fuse.Conn
	log     logger.Logger
	runMode kbconst.RunMode
}

// fuseMount tries to mount the mountpoint.
// On a force mount then unmount, re-mount if unsuccessful
func (m *mounter) Mount() (err error) {
	m.c, err = fuseMountDir(m.options.MountPoint, m.options.PlatformParams)
	// Exit if we were successful or we are not a force mounting on error.
	// Otherwise, try unmounting and mounting again.
	if err == nil || !m.options.ForceMount {
		return err
	}

	// Mount failed, let's try to unmount and then try mounting again, even
	// if unmounting errors here.
	m.Unmount()

	// In case we are on darwin, ask the installer to reinstall the mount dir
	// and try again as the last resort. This specifically fixes a situation
	// where /keybase gets created and owned by root after Keybase app is
	// started, and `kbfs` later fails to mount because of a permission error.
	m.reinstallMountDirIfPossible()
	m.c, err = fuseMountDir(m.options.MountPoint, m.options.PlatformParams)

	return err
}

func fuseMountDir(dir string, platformParams PlatformParams) (*fuse.Conn, error) {
	fi, err := os.Stat(dir)
	if err != nil {
		return nil, err
	}
	if !fi.IsDir() {
		return nil, errors.New("mount point is not a directory")
	}
	options, err := getPlatformSpecificMountOptions(dir, platformParams)
	if err != nil {
		return nil, err
	}
	c, err := fuse.Mount(dir, options...)
	if err != nil {
		err = translatePlatformSpecificError(err, platformParams)
		return nil, err
	}
	return c, nil
}

func (m *mounter) Unmount() (err error) {
	dir := m.options.MountPoint
	// Try normal unmount
	switch runtime.GOOS {
	case "darwin":
		_, err = exec.Command("/sbin/umount", dir).Output()
	case "linux":
		_, err = exec.Command("fusermount", "-u", dir).Output()
	default:
		err = fuse.Unmount(dir)
	}
	if err != nil && m.options.ForceMount {
		// Unmount failed, so let's try and force it.
		switch runtime.GOOS {
		case "darwin":
			_, err = exec.Command(
				"/usr/sbin/diskutil", "unmountDisk", "force", dir).Output()
		case "linux":
			_, err = exec.Command("fusermount", "-ul", dir).Output()
		default:
			err = errors.New("Forced unmount is not supported on this platform yet")
		}
	}
	if execErr, ok := err.(*exec.ExitError); ok && execErr.Stderr != nil {
		err = fmt.Errorf("%s (%s)", execErr, execErr.Stderr)
	}
	return
}

// volumeName returns the first word of the directory (base) name
func volumeName(dir string) (string, error) {
	volName := path.Base(dir)
	if volName == "." || volName == "/" {
		err := fmt.Errorf("Bad volume name: %v", volName)
		return "", err
	}
	s := strings.Split(volName, " ")
	if len(s) == 0 {
		return "", fmt.Errorf("Bad volume name: %v", volName)
	}
	return s[0], nil
}
<commit_msg>libfuse: Fix issue where fusermount unmount lazy was not being called correctly<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
//
// +build !windows

package libfuse

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path"
	"runtime"
	"strings"

	"bazil.org/fuse"
	"github.com/keybase/client/go/kbconst"
	"github.com/keybase/client/go/logger"
)

type mounter struct {
	options StartOptions
	c       *fuse.Conn
	log     logger.Logger
	runMode kbconst.RunMode
}

// fuseMount tries to mount the mountpoint.
// On a force mount then unmount, re-mount if unsuccessful
func (m *mounter) Mount() (err error) {
	m.c, err = fuseMountDir(m.options.MountPoint, m.options.PlatformParams)
	// Exit if we were successful or we are not a force mounting on error.
	// Otherwise, try unmounting and mounting again.
	if err == nil || !m.options.ForceMount {
		return err
	}

	// Mount failed, let's try to unmount and then try mounting again, even
	// if unmounting errors here.
	m.Unmount()

	// In case we are on darwin, ask the installer to reinstall the mount dir
	// and try again as the last resort. This specifically fixes a situation
	// where /keybase gets created and owned by root after Keybase app is
	// started, and `kbfs` later fails to mount because of a permission error.
	m.reinstallMountDirIfPossible()
	m.c, err = fuseMountDir(m.options.MountPoint, m.options.PlatformParams)

	return err
}

func fuseMountDir(dir string, platformParams PlatformParams) (*fuse.Conn, error) {
	fi, err := os.Stat(dir)
	if err != nil {
		return nil, err
	}
	if !fi.IsDir() {
		return nil, errors.New("mount point is not a directory")
	}
	options, err := getPlatformSpecificMountOptions(dir, platformParams)
	if err != nil {
		return nil, err
	}
	c, err := fuse.Mount(dir, options...)
	if err != nil {
		err = translatePlatformSpecificError(err, platformParams)
		return nil, err
	}
	return c, nil
}

func (m *mounter) Unmount() (err error) {
	dir := m.options.MountPoint
	// Try normal unmount
	switch runtime.GOOS {
	case "darwin":
		_, err = exec.Command("/sbin/umount", dir).Output()
	case "linux":
		_, err = exec.Command("fusermount", "-u", dir).Output()
	default:
		err = fuse.Unmount(dir)
	}
	if err != nil && m.options.ForceMount {
		// Unmount failed, so let's try and force it.
		switch runtime.GOOS {
		case "darwin":
			_, err = exec.Command(
				"/usr/sbin/diskutil", "unmountDisk", "force", dir).Output()
		case "linux":
			// Lazy unmount; will unmount when KBFS is no longer in use
			_, err = exec.Command("fusermount", "-u", "-z", dir).Output()
		default:
			err = errors.New("Forced unmount is not supported on this platform yet")
		}
	}
	if execErr, ok := err.(*exec.ExitError); ok && execErr.Stderr != nil {
		err = fmt.Errorf("%s (%s)", execErr, execErr.Stderr)
	}
	return
}

// volumeName returns the first word of the directory (base) name
func volumeName(dir string) (string, error) {
	volName := path.Base(dir)
	if volName == "." || volName == "/" {
		err := fmt.Errorf("Bad volume name: %v", volName)
		return "", err
	}
	s := strings.Split(volName, " ")
	if len(s) == 0 {
		return "", fmt.Errorf("Bad volume name: %v", volName)
	}
	return s[0], nil
}
<|endoftext|>


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

// Package wrangler contains the Wrangler object to manage complex
// topology actions.
package wrangler

import (
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/tabletmanager/actionnode"
	"github.com/youtube/vitess/go/vt/tabletmanager/tmclient"
	"github.com/youtube/vitess/go/vt/topo"
)

var (
	// DefaultActionTimeout is a good default for interactive
	// remote actions. We usually take a lock then do an action,
	// so basing this to be greater than DefaultLockTimeout is good.
	DefaultActionTimeout = actionnode.DefaultLockTimeout * 4
)

// Wrangler manages complex actions on the topology, like reparents,
// snapshots, restores, ...
//
// FIXME(alainjobart) take the context out of this structure.
// We want the context to come from the outside on every call.
//
// Multiple go routines can use the same Wrangler at the same time,
// provided they want to share the same logger / topo server / lock timeout.
type Wrangler struct {
	logger      logutil.Logger
	ts          topo.Server
	tmc         tmclient.TabletManagerClient
	lockTimeout time.Duration

	// the following fields are protected by the mutex
	mu       sync.Mutex
	ctx      context.Context
	cancel   context.CancelFunc
	deadline time.Time
}

// New creates a new Wrangler object.
//
// actionTimeout: how long should we wait for an action to complete?
// - if using wrangler for just one action, this is set properly
//   upon wrangler creation.
// - if re-using wrangler multiple times, call ResetActionTimeout before
//   every action. Do not use this too much, just for corner cases.
//   It is just much easier to create a new Wrangler object per action.
//
// lockTimeout: how long should we wait for the initial lock to start
// a complex action?  This is distinct from actionTimeout because most
// of the time, we want to immediately know that our action will
// fail. However, automated action will need some time to arbitrate
// the locks.
func New(logger logutil.Logger, ts topo.Server, actionTimeout, lockTimeout time.Duration) *Wrangler {
	ctx, cancel := context.WithTimeout(context.Background(), actionTimeout)
	return &Wrangler{
		logger:      logger,
		ts:          ts,
		tmc:         tmclient.NewTabletManagerClient(),
		ctx:         ctx,
		cancel:      cancel,
		deadline:    time.Now().Add(actionTimeout),
		lockTimeout: lockTimeout,
	}
}

// ActionTimeout returns the timeout to use so the action finishes before
// the deadline.
func (wr *Wrangler) ActionTimeout() time.Duration {
	return wr.deadline.Sub(time.Now())
}

// Context returns the context associated with this Wrangler.
// It is replaced if ResetActionTimeout is called on the Wrangler.
func (wr *Wrangler) Context() context.Context {
	wr.mu.Lock()
	defer wr.mu.Unlock()
	return wr.ctx
}

// Cancel calls the CancelFunc on our Context and therefore interrupts the call.
func (wr *Wrangler) Cancel() {
	wr.mu.Lock()
	defer wr.mu.Unlock()
	wr.cancel()
}

// TopoServer returns the topo.Server this wrangler is using.
func (wr *Wrangler) TopoServer() topo.Server {
	return wr.ts
}

// TabletManagerClient returns the tmclient.TabletManagerClient this
// wrangler is using.
func (wr *Wrangler) TabletManagerClient() tmclient.TabletManagerClient {
	return wr.tmc
}

// SetLogger can be used to change the current logger. Not synchronized,
// no calls to this wrangler should be in progress.
func (wr *Wrangler) SetLogger(logger logutil.Logger) {
	wr.logger = logger
}

// Logger returns the logger associated with this wrangler.
func (wr *Wrangler) Logger() logutil.Logger {
	return wr.logger
}

// ResetActionTimeout should be used before every action on a wrangler
// object that is going to be re-used:
// - vtctl will not call this, as it does one action.
// - vtctld will not call this, as it creates a new Wrangler every time.
// However, some actions may need to do a cleanup phase where the
// original Context may have expired or been cancelled, but still do
// the action.  Wrangler cleaner module is one of these, or the vt
// worker in some corner cases,
func (wr *Wrangler) ResetActionTimeout(actionTimeout time.Duration) {
	wr.mu.Lock()
	defer wr.mu.Unlock()

	wr.ctx, wr.cancel = context.WithTimeout(context.Background(), actionTimeout)
	wr.deadline = time.Now().Add(actionTimeout)
}
<commit_msg>Removing wrangler.ActionTimeout and deadline. Both replaced by context now.<commit_after>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package wrangler contains the Wrangler object to manage complex
// topology actions.
package wrangler

import (
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/vt/logutil"
	"github.com/youtube/vitess/go/vt/tabletmanager/actionnode"
	"github.com/youtube/vitess/go/vt/tabletmanager/tmclient"
	"github.com/youtube/vitess/go/vt/topo"
)

var (
	// DefaultActionTimeout is a good default for interactive
	// remote actions. We usually take a lock then do an action,
	// so basing this to be greater than DefaultLockTimeout is good.
	// Use this as the default value for Context that need a deadline.
	DefaultActionTimeout = actionnode.DefaultLockTimeout * 4
)

// Wrangler manages complex actions on the topology, like reparents,
// snapshots, restores, ...
//
// FIXME(alainjobart) take the context out of this structure.
// We want the context to come from the outside on every call.
//
// Multiple go routines can use the same Wrangler at the same time,
// provided they want to share the same logger / topo server / lock timeout.
type Wrangler struct {
	logger      logutil.Logger
	ts          topo.Server
	tmc         tmclient.TabletManagerClient
	lockTimeout time.Duration

	// the following fields are protected by the mutex
	mu     sync.Mutex
	ctx    context.Context
	cancel context.CancelFunc
}

// New creates a new Wrangler object.
//
// actionTimeout: how long should we wait for an action to complete?
// - if using wrangler for just one action, this is set properly
//   upon wrangler creation.
// - if re-using wrangler multiple times, call ResetActionTimeout before
//   every action. Do not use this too much, just for corner cases.
//   It is just much easier to create a new Wrangler object per action.
//
// lockTimeout: how long should we wait for the initial lock to start
// a complex action?  This is distinct from actionTimeout because most
// of the time, we want to immediately know that our action will
// fail. However, automated action will need some time to arbitrate
// the locks.
func New(logger logutil.Logger, ts topo.Server, actionTimeout, lockTimeout time.Duration) *Wrangler {
	ctx, cancel := context.WithTimeout(context.Background(), actionTimeout)
	return &Wrangler{
		logger:      logger,
		ts:          ts,
		tmc:         tmclient.NewTabletManagerClient(),
		ctx:         ctx,
		cancel:      cancel,
		lockTimeout: lockTimeout,
	}
}

// Context returns the context associated with this Wrangler.
// It is replaced if ResetActionTimeout is called on the Wrangler.
func (wr *Wrangler) Context() context.Context {
	wr.mu.Lock()
	defer wr.mu.Unlock()
	return wr.ctx
}

// Cancel calls the CancelFunc on our Context and therefore interrupts the call.
func (wr *Wrangler) Cancel() {
	wr.mu.Lock()
	defer wr.mu.Unlock()
	wr.cancel()
}

// TopoServer returns the topo.Server this wrangler is using.
func (wr *Wrangler) TopoServer() topo.Server {
	return wr.ts
}

// TabletManagerClient returns the tmclient.TabletManagerClient this
// wrangler is using.
func (wr *Wrangler) TabletManagerClient() tmclient.TabletManagerClient {
	return wr.tmc
}

// SetLogger can be used to change the current logger. Not synchronized,
// no calls to this wrangler should be in progress.
func (wr *Wrangler) SetLogger(logger logutil.Logger) {
	wr.logger = logger
}

// Logger returns the logger associated with this wrangler.
func (wr *Wrangler) Logger() logutil.Logger {
	return wr.logger
}

// ResetActionTimeout should be used before every action on a wrangler
// object that is going to be re-used:
// - vtctl will not call this, as it does one action.
// - vtctld will not call this, as it creates a new Wrangler every time.
// However, some actions may need to do a cleanup phase where the
// original Context may have expired or been cancelled, but still do
// the action.  Wrangler cleaner module is one of these, or the vt
// worker in some corner cases,
func (wr *Wrangler) ResetActionTimeout(actionTimeout time.Duration) {
	wr.mu.Lock()
	defer wr.mu.Unlock()

	wr.ctx, wr.cancel = context.WithTimeout(context.Background(), actionTimeout)
}
<|endoftext|>


<commit_before>package brokers

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/RichardKnop/machinery/v1/signatures"
)

type EagerBroker struct {
	worker TaskProcessor
}

func NewEagerBroker() Broker {
	return &EagerBroker{}
}

type EagerMode interface {
	AssignWorker(p TaskProcessor)
}

//
// Broker interface
//
func (e *EagerBroker) SetRegisteredTaskNames(names []string) {
	// do nothing
}

func (e *EagerBroker)  IsTaskRegistered(name string) bool {
	return true
}

func (e *EagerBroker) StartConsuming(consumerTag string, p TaskProcessor) (bool, error) {
	return true, nil
}

func (e *EagerBroker) StopConsuming() {
	// do nothing
}

func (e *EagerBroker) Publish(task *signatures.TaskSignature) error {
	if e.worker == nil {
		return errors.New("worker is not assigned in eager-mode")
	}

	// faking the behavior to marshal input into json
	// and unmarshal it back
	message, err := json.Marshal(task)
	if err != nil {
		return errors.New(fmt.Sprintf("json marshaling failed: %v", err))
	}

	sig_ := signatures.TaskSignature{}
	err = json.Unmarshal(message, &sig_)
	if err != nil {
		return errors.New(fmt.Sprintf("json unmarshaling failed: %v", err))
	}

	// blocking call to the task directly
	return e.worker.Process(&sig_)
}

//
// Eager interface
//
func (e *EagerBroker) AssignWorker(p TaskProcessor) {
	e.worker = p
}
<commit_msg>go fmt<commit_after>package brokers

import (
	"encoding/json"
	"errors"
	"fmt"

	"github.com/RichardKnop/machinery/v1/signatures"
)

type EagerBroker struct {
	worker TaskProcessor
}

func NewEagerBroker() Broker {
	return &EagerBroker{}
}

type EagerMode interface {
	AssignWorker(p TaskProcessor)
}

//
// Broker interface
//
func (e *EagerBroker) SetRegisteredTaskNames(names []string) {
	// do nothing
}

func (e *EagerBroker) IsTaskRegistered(name string) bool {
	return true
}

func (e *EagerBroker) StartConsuming(consumerTag string, p TaskProcessor) (bool, error) {
	return true, nil
}

func (e *EagerBroker) StopConsuming() {
	// do nothing
}

func (e *EagerBroker) Publish(task *signatures.TaskSignature) error {
	if e.worker == nil {
		return errors.New("worker is not assigned in eager-mode")
	}

	// faking the behavior to marshal input into json
	// and unmarshal it back
	message, err := json.Marshal(task)
	if err != nil {
		return errors.New(fmt.Sprintf("json marshaling failed: %v", err))
	}

	sig_ := signatures.TaskSignature{}
	err = json.Unmarshal(message, &sig_)
	if err != nil {
		return errors.New(fmt.Sprintf("json unmarshaling failed: %v", err))
	}

	// blocking call to the task directly
	return e.worker.Process(&sig_)
}

//
// Eager interface
//
func (e *EagerBroker) AssignWorker(p TaskProcessor) {
	e.worker = p
}
<|endoftext|>


<commit_before>package errors

import (
	"fmt"
	"log"
)

// Fail logs the error and exits the program
// Only use this to handle critical errors
func Fail(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
		panic(fmt.Sprintf("%s: %s", msg, err))
	}
}

// Log only logs the error but doesn't exit the program
// Use this to log errors that should not exit the program
func Log(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}
<commit_msg>A bit more accurate work with logging: - use Panicf instead of Fatalf + manual panic which didn't work as stated - use Printf instead of Fatalf in error which shouldn't kill whole application<commit_after>package errors

import (
	"log"
)

// Fail logs the error and exits the program
// Only use this to handle critical errors
func Fail(err error, msg string) {
	if err != nil {
		log.Panicf("%s: %s", msg, err)
	}
}

// Log only logs the error but doesn't exit the program
// Use this to log errors that should not exit the program
func Log(err error, msg string) {
	if err != nil {
		log.Printf("[ERROR] %s: %s", msg, err)
	}
}
<|endoftext|>


<commit_before>package tokenex

import "encoding/json"

func Tokenize(data string, tokenScheme int) tokenResponse {
	tData := map[string]interface{}{
		"Data":        data,
		"TokenScheme": tokenScheme,
	}
	data = request("Tokenize", tData)
	response := tokenResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Detokenize(token string) valueResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("Detokenize", tData)
	response := valueResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Validate(token string) validateResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("ValidateToken", tData)
	response := validateResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Delete(token string) deleteResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("DeleteToken", tData)
	response := deleteResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}
<commit_msg>:penguin: Added TokenizeFromEncryptedValue()<commit_after>package tokenex

import "encoding/json"

func Tokenize(data string, tokenScheme int) tokenResponse {
	tData := map[string]interface{}{
		"Data":        data,
		"TokenScheme": tokenScheme,
	}
	data = request("Tokenize", tData)
	response := tokenResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func TokenizeFromEncryptedValue(data string, tokenScheme int) tokenResponse {
	tData := map[string]interface{}{
		"EcryptedData": data,
		"TokenScheme":  tokenScheme,
	}
	data = request("TokenizeFromEncryptedValue", tData)
	response := tokenResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Detokenize(token string) valueResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("Detokenize", tData)
	response := valueResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Validate(token string) validateResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("ValidateToken", tData)
	response := validateResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}

func Delete(token string) deleteResponse {
	tData := map[string]interface{}{
		"Token": token,
	}
	data := request("DeleteToken", tData)
	response := deleteResponse{}
	json.Unmarshal([]byte(data), &response)
	return response
}
<|endoftext|>


<commit_before>package websocket

import (
	"context"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingcredit"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingloan"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

type FlagRequest struct {
	Event string `json:"event"`
	Flags int    `json:"flags"`
}

// API for end-users to interact with Bitfinex.

// Send publishes a generic message to the Bitfinex API.
func (c *Client) Send(ctx context.Context, msg interface{}) error {
	socket, err := c.getSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, msg)
}

// Submit a request to enable the given flag
func (c *Client) EnableFlag(ctx context.Context, flag int) (string, error) {
	req := &FlagRequest{
		Event: "conf",
		Flags: flag,
	}
	// TODO enable flag on reconnect?
	// create sublist to stop concurrent map read
	socks := make([]*Socket, len(c.sockets))
	c.mtx.RLock()
	for i, socket := range c.sockets {
		socks[i] = socket
	}
	c.mtx.RUnlock()
	for _, socket := range socks {
		err := socket.Asynchronous.Send(ctx, req)
		if err != nil {
			return "", err
		}
	}
	return "", nil
}

// Gen the count of currently active websocket connections
func (c *Client) ConnectionCount() int {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	return len(c.sockets)
}

// Get the available capacity of the current
// websocket connections
func (c *Client) AvailableCapacity() int {
	return c.getTotalAvailableSocketCapacity()
}

// Start a new websocket connection. This function is only exposed in case you want to
// implicitly add new connections otherwise connection management is already handled for you.
func (c *Client) StartNewConnection() error {
	return c.connectSocket(SocketId(c.ConnectionCount()))
}

func (c *Client) subscribeBySocket(ctx context.Context, socket *Socket, req *SubscriptionRequest) (string, error) {
	c.subscriptions.add(socket.Id, req)
	err := socket.Asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// Submit a request to subscribe to the given SubscriptionRequuest
func (c *Client) Subscribe(ctx context.Context, req *SubscriptionRequest) (string, error) {
	if c.getTotalAvailableSocketCapacity() <= 1 {
		err := c.StartNewConnection()
		if err != nil {
			return "", err
		}
	}
	// get socket with the highest available capacity
	socket, err := c.getMostAvailableSocket()
	if err != nil {
		return "", err
	}
	return c.subscribeBySocket(ctx, socket, req)
}

// Submit a request to receive ticker updates
func (c *Client) SubscribeTicker(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTicker,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// Submit a request to receive trade updates
func (c *Client) SubscribeTrades(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTrades,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// Submit a  subscription request for market data for the given symbol, at the given frequency, with the given precision, returning no more than priceLevels price entries.
// Default values are Precision0, Frequency0, and priceLevels=25.
func (c *Client) SubscribeBook(ctx context.Context, symbol string, precision bitfinex.BookPrecision, frequency bitfinex.BookFrequency, priceLevel int) (string, error) {
	if priceLevel < 0 {
		return "", fmt.Errorf("negative price levels not supported: %d", priceLevel)
	}
	req := &SubscriptionRequest{
		SubID:     c.nonce.GetNonce(),
		Event:     EventSubscribe,
		Channel:   ChanBook,
		Symbol:    symbol,
		Precision: string(precision),
		Len:       fmt.Sprintf("%d", priceLevel), // needed for R0?
	}
	if !bitfinex.IsRawBook(string(precision)) {
		req.Frequency = string(frequency)
	}
	return c.Subscribe(ctx, req)
}

// Submit a subscription request to receive candle updates
func (c *Client) SubscribeCandles(ctx context.Context, symbol string, resolution bitfinex.CandleResolution) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanCandles,
		Key:     fmt.Sprintf("trade:%s:%s", resolution, symbol),
	}
	return c.Subscribe(ctx, req)
}

// Submit a subscription request for status updates
func (c *Client) SubscribeStatus(ctx context.Context, symbol string, sType bitfinex.StatusType) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanStatus,
		Key:     fmt.Sprintf("%s:%s", string(sType), symbol),
	}
	return c.Subscribe(ctx, req)
}

// Retrieve the Orderbook for the given symbol which is managed locally.
// This requires ManageOrderbook=True and an active chanel subscribed to the given
// symbols orderbook
func (c *Client) GetOrderbook(symbol string) (*Orderbook, error) {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	if val, ok := c.orderbooks[symbol]; ok {
		// take dereferenced copy of orderbook
		return val, nil
	}
	return nil, fmt.Errorf("Orderbook %s does not exist", symbol)
}

// Submit a request to create a new order
func (c *Client) SubmitOrder(ctx context.Context, onr *order.NewRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, onr)
}

// Submit and update request to change an existing orders values
func (c *Client) SubmitUpdateOrder(ctx context.Context, our *order.UpdateRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, our)
}

// Submit a cancel request for an existing order
func (c *Client) SubmitCancel(ctx context.Context, ocr *order.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, ocr)
}

// Get a subscription request using a subscription ID
func (c *Client) LookupSubscription(subID string) (*SubscriptionRequest, error) {
	s, err := c.subscriptions.lookupBySubscriptionID(subID)
	if err != nil {
		return nil, err
	}
	return s.Request, nil
}

// Submit a new funding offer request
func (c *Client) SubmitFundingOffer(ctx context.Context, fundingOffer *fundingoffer.SubmitRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, fundingOffer)
}

// Submit a request to cancel and existing funding offer
func (c *Client) SubmitFundingCancel(ctx context.Context, fundingOffer *fundingoffer.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, fundingOffer)
}

// CloseFundingLoan - cancels funding loan by ID. Emits an error if not authenticated.
func (c *Client) CloseFundingLoan(ctx context.Context, flcr *fundingloan.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, flcr)
}

// CloseFundingCredit - cancels funding credit by ID. Emits an error if not authenticated.
func (c *Client) CloseFundingCredit(ctx context.Context, fundingOffer *fundingcredit.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, fundingOffer)
}
<commit_msg>v2/websocket/api.go putting new book package to work<commit_after>package websocket

import (
	"context"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/book"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingcredit"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingloan"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

type FlagRequest struct {
	Event string `json:"event"`
	Flags int    `json:"flags"`
}

// API for end-users to interact with Bitfinex.

// Send publishes a generic message to the Bitfinex API.
func (c *Client) Send(ctx context.Context, msg interface{}) error {
	socket, err := c.getSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, msg)
}

// Submit a request to enable the given flag
func (c *Client) EnableFlag(ctx context.Context, flag int) (string, error) {
	req := &FlagRequest{
		Event: "conf",
		Flags: flag,
	}
	// TODO enable flag on reconnect?
	// create sublist to stop concurrent map read
	socks := make([]*Socket, len(c.sockets))
	c.mtx.RLock()
	for i, socket := range c.sockets {
		socks[i] = socket
	}
	c.mtx.RUnlock()
	for _, socket := range socks {
		err := socket.Asynchronous.Send(ctx, req)
		if err != nil {
			return "", err
		}
	}
	return "", nil
}

// Gen the count of currently active websocket connections
func (c *Client) ConnectionCount() int {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	return len(c.sockets)
}

// Get the available capacity of the current
// websocket connections
func (c *Client) AvailableCapacity() int {
	return c.getTotalAvailableSocketCapacity()
}

// Start a new websocket connection. This function is only exposed in case you want to
// implicitly add new connections otherwise connection management is already handled for you.
func (c *Client) StartNewConnection() error {
	return c.connectSocket(SocketId(c.ConnectionCount()))
}

func (c *Client) subscribeBySocket(ctx context.Context, socket *Socket, req *SubscriptionRequest) (string, error) {
	c.subscriptions.add(socket.Id, req)
	err := socket.Asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// Submit a request to subscribe to the given SubscriptionRequuest
func (c *Client) Subscribe(ctx context.Context, req *SubscriptionRequest) (string, error) {
	if c.getTotalAvailableSocketCapacity() <= 1 {
		err := c.StartNewConnection()
		if err != nil {
			return "", err
		}
	}
	// get socket with the highest available capacity
	socket, err := c.getMostAvailableSocket()
	if err != nil {
		return "", err
	}
	return c.subscribeBySocket(ctx, socket, req)
}

// Submit a request to receive ticker updates
func (c *Client) SubscribeTicker(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTicker,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// Submit a request to receive trade updates
func (c *Client) SubscribeTrades(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTrades,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// Submit a  subscription request for market data for the given symbol, at the given frequency, with the given precision, returning no more than priceLevels price entries.
// Default values are Precision0, Frequency0, and priceLevels=25.
func (c *Client) SubscribeBook(ctx context.Context, symbol string, precision bitfinex.BookPrecision, frequency bitfinex.BookFrequency, priceLevel int) (string, error) {
	if priceLevel < 0 {
		return "", fmt.Errorf("negative price levels not supported: %d", priceLevel)
	}
	req := &SubscriptionRequest{
		SubID:     c.nonce.GetNonce(),
		Event:     EventSubscribe,
		Channel:   ChanBook,
		Symbol:    symbol,
		Precision: string(precision),
		Len:       fmt.Sprintf("%d", priceLevel), // needed for R0?
	}
	if !book.IsRawBook(string(precision)) {
		req.Frequency = string(frequency)
	}
	return c.Subscribe(ctx, req)
}

// Submit a subscription request to receive candle updates
func (c *Client) SubscribeCandles(ctx context.Context, symbol string, resolution bitfinex.CandleResolution) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanCandles,
		Key:     fmt.Sprintf("trade:%s:%s", resolution, symbol),
	}
	return c.Subscribe(ctx, req)
}

// Submit a subscription request for status updates
func (c *Client) SubscribeStatus(ctx context.Context, symbol string, sType bitfinex.StatusType) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanStatus,
		Key:     fmt.Sprintf("%s:%s", string(sType), symbol),
	}
	return c.Subscribe(ctx, req)
}

// Retrieve the Orderbook for the given symbol which is managed locally.
// This requires ManageOrderbook=True and an active chanel subscribed to the given
// symbols orderbook
func (c *Client) GetOrderbook(symbol string) (*Orderbook, error) {
	c.mtx.RLock()
	defer c.mtx.RUnlock()
	if val, ok := c.orderbooks[symbol]; ok {
		// take dereferenced copy of orderbook
		return val, nil
	}
	return nil, fmt.Errorf("Orderbook %s does not exist", symbol)
}

// Submit a request to create a new order
func (c *Client) SubmitOrder(ctx context.Context, onr *order.NewRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, onr)
}

// Submit and update request to change an existing orders values
func (c *Client) SubmitUpdateOrder(ctx context.Context, our *order.UpdateRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, our)
}

// Submit a cancel request for an existing order
func (c *Client) SubmitCancel(ctx context.Context, ocr *order.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, ocr)
}

// Get a subscription request using a subscription ID
func (c *Client) LookupSubscription(subID string) (*SubscriptionRequest, error) {
	s, err := c.subscriptions.lookupBySubscriptionID(subID)
	if err != nil {
		return nil, err
	}
	return s.Request, nil
}

// Submit a new funding offer request
func (c *Client) SubmitFundingOffer(ctx context.Context, fundingOffer *fundingoffer.SubmitRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, fundingOffer)
}

// Submit a request to cancel and existing funding offer
func (c *Client) SubmitFundingCancel(ctx context.Context, fundingOffer *fundingoffer.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, fundingOffer)
}

// CloseFundingLoan - cancels funding loan by ID. Emits an error if not authenticated.
func (c *Client) CloseFundingLoan(ctx context.Context, flcr *fundingloan.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, flcr)
}

// CloseFundingCredit - cancels funding credit by ID. Emits an error if not authenticated.
func (c *Client) CloseFundingCredit(ctx context.Context, fundingOffer *fundingcredit.CancelRequest) error {
	socket, err := c.GetAuthenticatedSocket()
	if err != nil {
		return err
	}
	return socket.Asynchronous.Send(ctx, fundingOffer)
}
<|endoftext|>


<commit_before>package websocket

import (
	"context"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

// API for end-users to interact with Bitfinex.

// SubscribeTicker sends a subscription request for the ticker.
func (c *Client) SubscribeTicker(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTicker,
		Symbol:  symbol,
	}
	c.subscriptions.add(req)
	err := c.asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// SubscribeTrades sends a subscription request for the trade feed.
func (c *Client) SubscribeTrades(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTrades,
		Symbol:  symbol,
	}
	c.subscriptions.add(req)
	err := c.asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// SubscribeBook sends a subscription request for market data.
func (c *Client) SubscribeBook(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanBook,
		Symbol:  symbol,
	}
	c.subscriptions.add(req)
	err := c.asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// SubscribeCandles sends a subscription request for OHLC candles.
func (c *Client) SubscribeCandles(ctx context.Context, symbol string, resolution bitfinex.CandleResolution) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanCandles,
		Key:     fmt.Sprintf("trade:%s:%s", resolution, symbol),
	}
	c.subscriptions.add(req)
	err := c.asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// SubmitOrder sends an order request.
func (c *Client) SubmitOrder(ctx context.Context, order *bitfinex.OrderNewRequest) error {
	return c.asynchronous.Send(ctx, order)
}

// SubmitCancel sends a cancel request.
func (c *Client) SubmitCancel(ctx context.Context, cancel *bitfinex.OrderCancelRequest) error {
	return c.asynchronous.Send(ctx, cancel)
}
<commit_msg>exposed public API subscribe method for raw subscriptions<commit_after>package websocket

import (
	"context"
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/v2"
)

// API for end-users to interact with Bitfinex.

func (c *Client) Subscribe(ctx context.Context, req *SubscriptionRequest) (string, error) {
	c.subscriptions.add(req)
	err := c.asynchronous.Send(ctx, req)
	if err != nil {
		// propagate send error
		return "", err
	}
	return req.SubID, nil
}

// SubscribeTicker sends a subscription request for the ticker.
func (c *Client) SubscribeTicker(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTicker,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// SubscribeTrades sends a subscription request for the trade feed.
func (c *Client) SubscribeTrades(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanTrades,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// SubscribeBook sends a subscription request for market data.
func (c *Client) SubscribeBook(ctx context.Context, symbol string) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanBook,
		Symbol:  symbol,
	}
	return c.Subscribe(ctx, req)
}

// SubscribeCandles sends a subscription request for OHLC candles.
func (c *Client) SubscribeCandles(ctx context.Context, symbol string, resolution bitfinex.CandleResolution) (string, error) {
	req := &SubscriptionRequest{
		SubID:   c.nonce.GetNonce(),
		Event:   EventSubscribe,
		Channel: ChanCandles,
		Key:     fmt.Sprintf("trade:%s:%s", resolution, symbol),
	}
	return c.Subscribe(ctx, req)
}

// SubmitOrder sends an order request.
func (c *Client) SubmitOrder(ctx context.Context, order *bitfinex.OrderNewRequest) error {
	return c.asynchronous.Send(ctx, order)
}

// SubmitCancel sends a cancel request.
func (c *Client) SubmitCancel(ctx context.Context, cancel *bitfinex.OrderCancelRequest) error {
	return c.asynchronous.Send(ctx, cancel)
}
<|endoftext|>


<commit_before>package integration

import (
	"syscall"

	"github.com/docker/libcontainer/configs"
)

var standardEnvironment = []string{
	"HOME=/root",
	"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
	"HOSTNAME=integration",
	"TERM=xterm",
}

const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV

// newTemplateConfig returns a base template for running a container
//
// it uses a network strategy of just setting a loopback interface
// and the default setup for devices
func newTemplateConfig(rootfs string) *configs.Config {
	return &configs.Config{
		Rootfs: rootfs,
		Capabilities: []string{
			"CHOWN",
			"DAC_OVERRIDE",
			"FSETID",
			"FOWNER",
			"MKNOD",
			"NET_RAW",
			"SETGID",
			"SETUID",
			"SETFCAP",
			"SETPCAP",
			"NET_BIND_SERVICE",
			"SYS_CHROOT",
			"KILL",
			"AUDIT_WRITE",
		},
		Namespaces: configs.Namespaces([]configs.Namespace{
			{Type: configs.NEWNS},
			{Type: configs.NEWUTS},
			{Type: configs.NEWIPC},
			{Type: configs.NEWPID},
			{Type: configs.NEWNET},
		}),
		Cgroups: &configs.Cgroup{
			Name:            "test",
			Parent:          "integration",
			AllowAllDevices: false,
			AllowedDevices:  configs.DefaultAllowedDevices,
		},
		MaskPaths: []string{
			"/proc/kcore",
		},
		ReadonlyPaths: []string{
			"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
		},
		Devices:  configs.DefaultAutoCreatedDevices,
		Hostname: "integration",
		Mounts: []*configs.Mount{
			{
				Device:      "tmpfs",
				Source:      "shm",
				Destination: "/dev/shm",
				Data:        "mode=1777,size=65536k",
				Flags:       defaultMountFlags,
			},
			{
				Source:      "mqueue",
				Destination: "/dev/mqueue",
				Device:      "mqueue",
				Flags:       defaultMountFlags,
			},
			{
				Source:      "sysfs",
				Destination: "/sys",
				Device:      "sysfs",
				Flags:       defaultMountFlags | syscall.MS_RDONLY,
			},
		},
		Networks: []*configs.Network{
			{
				Type:    "loopback",
				Address: "127.0.0.1/0",
				Gateway: "localhost",
			},
		},
		Rlimits: []configs.Rlimit{
			{
				Type: syscall.RLIMIT_NOFILE,
				Hard: uint64(1025),
				Soft: uint64(1025),
			},
		},
	}
}
<commit_msg>Update test.<commit_after>package integration

import (
	"syscall"

	"github.com/docker/libcontainer/configs"
)

var standardEnvironment = []string{
	"HOME=/root",
	"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
	"HOSTNAME=integration",
	"TERM=xterm",
}

const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV

// newTemplateConfig returns a base template for running a container
//
// it uses a network strategy of just setting a loopback interface
// and the default setup for devices
func newTemplateConfig(rootfs string) *configs.Config {
	return &configs.Config{
		Rootfs: rootfs,
		Capabilities: []string{
			"CHOWN",
			"DAC_OVERRIDE",
			"FSETID",
			"FOWNER",
			"MKNOD",
			"NET_RAW",
			"SETGID",
			"SETUID",
			"SETFCAP",
			"SETPCAP",
			"NET_BIND_SERVICE",
			"SYS_CHROOT",
			"KILL",
			"AUDIT_WRITE",
		},
		Namespaces: configs.Namespaces([]configs.Namespace{
			{Type: configs.NEWNS},
			{Type: configs.NEWUTS},
			{Type: configs.NEWIPC},
			{Type: configs.NEWPID},
			{Type: configs.NEWNET},
		}),
		Cgroups: &configs.Cgroup{
			Name:            "test",
			Parent:          "integration",
			AllowAllDevices: false,
			AllowedDevices:  configs.DefaultAllowedDevices,
		},
		MaskPaths: []string{
			"/proc/kcore",
		},
		ReadonlyPaths: []string{
			"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
		},
		Devices:  configs.DefaultAutoCreatedDevices,
		Hostname: "integration",
		Mounts: []*configs.Mount{
			{
				Source:      "proc",
				Destination: "/proc",
				Device:      "proc",
				Flags:       defaultMountFlags,
			},
			{
				Source:      "tmpfs",
				Destination: "/dev",
				Device:      "tmpfs",
				Flags:       syscall.MS_NOSUID | syscall.MS_STRICTATIME,
				Data:        "mode=755",
			},
			{
				Source:      "devpts",
				Destination: "/dev/pts",
				Device:      "devpts",
				Flags:       syscall.MS_NOSUID | syscall.MS_NOEXEC,
				Data:        "newinstance,ptmxmode=0666,mode=0620,gid=5",
			},
			{
				Device:      "tmpfs",
				Source:      "shm",
				Destination: "/dev/shm",
				Data:        "mode=1777,size=65536k",
				Flags:       defaultMountFlags,
			},
			{
				Source:      "mqueue",
				Destination: "/dev/mqueue",
				Device:      "mqueue",
				Flags:       defaultMountFlags,
			},
			{
				Source:      "sysfs",
				Destination: "/sys",
				Device:      "sysfs",
				Flags:       defaultMountFlags | syscall.MS_RDONLY,
			},
		},
		Networks: []*configs.Network{
			{
				Type:    "loopback",
				Address: "127.0.0.1/0",
				Gateway: "localhost",
			},
		},
		Rlimits: []configs.Rlimit{
			{
				Type: syscall.RLIMIT_NOFILE,
				Hard: uint64(1025),
				Soft: uint64(1025),
			},
		},
	}
}
<|endoftext|>


<commit_before>// Copyright 2020 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 fake

import (
	"bytes"
	"context"
	"crypto/sha256"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/span"
	errors "golang.org/x/xerrors"
)

// FileEvent wraps the protocol.FileEvent so that it can be associated with a
// workdir-relative path.
type FileEvent struct {
	Path, Content string
	ProtocolEvent protocol.FileEvent
}

// RelativeTo is a helper for operations relative to a given directory.
type RelativeTo string

// AbsPath returns an absolute filesystem path for the workdir-relative path.
func (r RelativeTo) AbsPath(path string) string {
	fp := filepath.FromSlash(path)
	if filepath.IsAbs(fp) {
		return fp
	}
	return filepath.Join(string(r), filepath.FromSlash(path))
}

// RelPath returns a '/'-encoded path relative to the working directory (or an
// absolute path if the file is outside of workdir)
func (r RelativeTo) RelPath(fp string) string {
	root := string(r)
	if rel, err := filepath.Rel(root, fp); err == nil && !strings.HasPrefix(rel, "..") {
		return filepath.ToSlash(rel)
	}
	return filepath.ToSlash(fp)
}

func writeTxtar(txt string, rel RelativeTo) error {
	files := UnpackTxt(txt)
	for name, data := range files {
		if err := WriteFileData(name, data, rel); err != nil {
			return errors.Errorf("writing to workdir: %w", err)
		}
	}
	return nil
}

// WriteFileData writes content to the relative path, replacing the special
// token $SANDBOX_WORKDIR with the relative root given by rel.
func WriteFileData(path string, content []byte, rel RelativeTo) error {
	content = bytes.ReplaceAll(content, []byte("$SANDBOX_WORKDIR"), []byte(rel))
	fp := rel.AbsPath(path)
	if err := os.MkdirAll(filepath.Dir(fp), 0755); err != nil {
		return errors.Errorf("creating nested directory: %w", err)
	}
	backoff := 1 * time.Millisecond
	for {
		err := ioutil.WriteFile(fp, []byte(content), 0644)
		if err != nil {
			if isWindowsErrLockViolation(err) {
				time.Sleep(backoff)
				backoff *= 2
				continue
			}
			return errors.Errorf("writing %q: %w", path, err)
		}
		return nil
	}
}

// isWindowsErrLockViolation reports whether err is ERROR_LOCK_VIOLATION
// on Windows.
var isWindowsErrLockViolation = func(err error) bool { return false }

// Workdir is a temporary working directory for tests. It exposes file
// operations in terms of relative paths, and fakes file watching by triggering
// events on file operations.
type Workdir struct {
	RelativeTo

	watcherMu sync.Mutex
	watchers  []func(context.Context, []FileEvent)

	fileMu sync.Mutex
	files  map[string]string
}

// NewWorkdir writes the txtar-encoded file data in txt to dir, and returns a
// Workir for operating on these files using
func NewWorkdir(dir string) *Workdir {
	return &Workdir{RelativeTo: RelativeTo(dir)}
}

func hashFile(data []byte) string {
	return fmt.Sprintf("%x", sha256.Sum256(data))
}

func (w *Workdir) writeInitialFiles(files map[string][]byte) error {
	w.files = map[string]string{}
	for name, data := range files {
		w.files[name] = hashFile(data)
		if err := WriteFileData(name, data, w.RelativeTo); err != nil {
			return errors.Errorf("writing to workdir: %w", err)
		}
	}
	return nil
}

// RootURI returns the root URI for this working directory of this scratch
// environment.
func (w *Workdir) RootURI() protocol.DocumentURI {
	return toURI(string(w.RelativeTo))
}

// AddWatcher registers the given func to be called on any file change.
func (w *Workdir) AddWatcher(watcher func(context.Context, []FileEvent)) {
	w.watcherMu.Lock()
	w.watchers = append(w.watchers, watcher)
	w.watcherMu.Unlock()
}

// URI returns the URI to a the workdir-relative path.
func (w *Workdir) URI(path string) protocol.DocumentURI {
	return toURI(w.AbsPath(path))
}

// URIToPath converts a uri to a workdir-relative path (or an absolute path,
// if the uri is outside of the workdir).
func (w *Workdir) URIToPath(uri protocol.DocumentURI) string {
	fp := uri.SpanURI().Filename()
	return w.RelPath(fp)
}

func toURI(fp string) protocol.DocumentURI {
	return protocol.DocumentURI(span.URIFromPath(fp))
}

// ReadFile reads a text file specified by a workdir-relative path.
func (w *Workdir) ReadFile(path string) (string, error) {
	b, err := ioutil.ReadFile(w.AbsPath(path))
	if err != nil {
		return "", err
	}
	return string(b), nil
}

func (w *Workdir) RegexpRange(path, re string) (Pos, Pos, error) {
	content, err := w.ReadFile(path)
	if err != nil {
		return Pos{}, Pos{}, err
	}
	return regexpRange(content, re)
}

// RegexpSearch searches the file corresponding to path for the first position
// matching re.
func (w *Workdir) RegexpSearch(path string, re string) (Pos, error) {
	content, err := w.ReadFile(path)
	if err != nil {
		return Pos{}, err
	}
	start, _, err := regexpRange(content, re)
	return start, err
}

// ChangeFilesOnDisk executes the given on-disk file changes in a batch,
// simulating the action of changing branches outside of an editor.
func (w *Workdir) ChangeFilesOnDisk(ctx context.Context, events []FileEvent) error {
	for _, e := range events {
		switch e.ProtocolEvent.Type {
		case protocol.Deleted:
			fp := w.AbsPath(e.Path)
			if err := os.Remove(fp); err != nil {
				return errors.Errorf("removing %q: %w", e.Path, err)
			}
		case protocol.Changed, protocol.Created:
			if _, err := w.writeFile(ctx, e.Path, e.Content); err != nil {
				return err
			}
		}
	}
	w.sendEvents(ctx, events)
	return nil
}

// RemoveFile removes a workdir-relative file path.
func (w *Workdir) RemoveFile(ctx context.Context, path string) error {
	fp := w.AbsPath(path)
	if err := os.RemoveAll(fp); err != nil {
		return errors.Errorf("removing %q: %w", path, err)
	}
	w.fileMu.Lock()
	defer w.fileMu.Unlock()

	evts := []FileEvent{{
		Path: path,
		ProtocolEvent: protocol.FileEvent{
			URI:  w.URI(path),
			Type: protocol.Deleted,
		},
	}}
	w.sendEvents(ctx, evts)
	delete(w.files, path)
	return nil
}

func (w *Workdir) sendEvents(ctx context.Context, evts []FileEvent) {
	if len(evts) == 0 {
		return
	}
	w.watcherMu.Lock()
	watchers := make([]func(context.Context, []FileEvent), len(w.watchers))
	copy(watchers, w.watchers)
	w.watcherMu.Unlock()
	for _, w := range watchers {
		w(ctx, evts)
	}
}

// WriteFiles writes the text file content to workdir-relative paths.
// It batches notifications rather than sending them consecutively.
func (w *Workdir) WriteFiles(ctx context.Context, files map[string]string) error {
	var evts []FileEvent
	for filename, content := range files {
		evt, err := w.writeFile(ctx, filename, content)
		if err != nil {
			return err
		}
		evts = append(evts, evt)
	}
	w.sendEvents(ctx, evts)
	return nil
}

// WriteFile writes text file content to a workdir-relative path.
func (w *Workdir) WriteFile(ctx context.Context, path, content string) error {
	evt, err := w.writeFile(ctx, path, content)
	if err != nil {
		return err
	}
	w.sendEvents(ctx, []FileEvent{evt})
	return nil
}

func (w *Workdir) writeFile(ctx context.Context, path, content string) (FileEvent, error) {
	fp := w.AbsPath(path)
	_, err := os.Stat(fp)
	if err != nil && !os.IsNotExist(err) {
		return FileEvent{}, errors.Errorf("checking if %q exists: %w", path, err)
	}
	var changeType protocol.FileChangeType
	if os.IsNotExist(err) {
		changeType = protocol.Created
	} else {
		changeType = protocol.Changed
	}
	if err := WriteFileData(path, []byte(content), w.RelativeTo); err != nil {
		return FileEvent{}, err
	}
	return FileEvent{
		Path: path,
		ProtocolEvent: protocol.FileEvent{
			URI:  w.URI(path),
			Type: changeType,
		},
	}, nil
}

// listFiles lists files in the given directory, returning a map of relative
// path to modification time.
func (w *Workdir) listFiles(dir string) (map[string]string, error) {
	files := make(map[string]string)
	absDir := w.AbsPath(dir)
	if err := filepath.Walk(absDir, func(fp string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		path := w.RelPath(fp)
		data, err := ioutil.ReadFile(fp)
		if err != nil {
			return err
		}
		files[path] = hashFile(data)
		return nil
	}); err != nil {
		return nil, err
	}
	return files, nil
}

// CheckForFileChanges walks the working directory and checks for any files
// that have changed since the last poll.
func (w *Workdir) CheckForFileChanges(ctx context.Context) error {
	evts, err := w.pollFiles()
	if err != nil {
		return err
	}
	w.sendEvents(ctx, evts)
	return nil
}

// pollFiles updates w.files and calculates FileEvents corresponding to file
// state changes since the last poll. It does not call sendEvents.
func (w *Workdir) pollFiles() ([]FileEvent, error) {
	w.fileMu.Lock()
	defer w.fileMu.Unlock()

	files, err := w.listFiles(".")
	if err != nil {
		return nil, err
	}
	var evts []FileEvent
	// Check which files have been added or modified.
	for path, hash := range files {
		oldhash, ok := w.files[path]
		delete(w.files, path)
		var typ protocol.FileChangeType
		switch {
		case !ok:
			typ = protocol.Created
		case oldhash != hash:
			typ = protocol.Changed
		default:
			continue
		}
		evts = append(evts, FileEvent{
			Path: path,
			ProtocolEvent: protocol.FileEvent{
				URI:  w.URI(path),
				Type: typ,
			},
		})
	}
	// Any remaining files must have been deleted.
	for path := range w.files {
		evts = append(evts, FileEvent{
			Path: path,
			ProtocolEvent: protocol.FileEvent{
				URI:  w.URI(path),
				Type: protocol.Deleted,
			},
		})
	}
	w.files = files
	return evts, nil
}
<commit_msg>internal/lsp/fake: retry ioutil.ReadFile on plan9 if it fails due to exclusive use<commit_after>// Copyright 2020 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 fake

import (
	"bytes"
	"context"
	"crypto/sha256"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/span"
	errors "golang.org/x/xerrors"
)

// FileEvent wraps the protocol.FileEvent so that it can be associated with a
// workdir-relative path.
type FileEvent struct {
	Path, Content string
	ProtocolEvent protocol.FileEvent
}

// RelativeTo is a helper for operations relative to a given directory.
type RelativeTo string

// AbsPath returns an absolute filesystem path for the workdir-relative path.
func (r RelativeTo) AbsPath(path string) string {
	fp := filepath.FromSlash(path)
	if filepath.IsAbs(fp) {
		return fp
	}
	return filepath.Join(string(r), filepath.FromSlash(path))
}

// RelPath returns a '/'-encoded path relative to the working directory (or an
// absolute path if the file is outside of workdir)
func (r RelativeTo) RelPath(fp string) string {
	root := string(r)
	if rel, err := filepath.Rel(root, fp); err == nil && !strings.HasPrefix(rel, "..") {
		return filepath.ToSlash(rel)
	}
	return filepath.ToSlash(fp)
}

func writeTxtar(txt string, rel RelativeTo) error {
	files := UnpackTxt(txt)
	for name, data := range files {
		if err := WriteFileData(name, data, rel); err != nil {
			return errors.Errorf("writing to workdir: %w", err)
		}
	}
	return nil
}

// WriteFileData writes content to the relative path, replacing the special
// token $SANDBOX_WORKDIR with the relative root given by rel.
func WriteFileData(path string, content []byte, rel RelativeTo) error {
	content = bytes.ReplaceAll(content, []byte("$SANDBOX_WORKDIR"), []byte(rel))
	fp := rel.AbsPath(path)
	if err := os.MkdirAll(filepath.Dir(fp), 0755); err != nil {
		return errors.Errorf("creating nested directory: %w", err)
	}
	backoff := 1 * time.Millisecond
	for {
		err := ioutil.WriteFile(fp, []byte(content), 0644)
		if err != nil {
			if isWindowsErrLockViolation(err) {
				time.Sleep(backoff)
				backoff *= 2
				continue
			}
			return errors.Errorf("writing %q: %w", path, err)
		}
		return nil
	}
}

// isWindowsErrLockViolation reports whether err is ERROR_LOCK_VIOLATION
// on Windows.
var isWindowsErrLockViolation = func(err error) bool { return false }

// Workdir is a temporary working directory for tests. It exposes file
// operations in terms of relative paths, and fakes file watching by triggering
// events on file operations.
type Workdir struct {
	RelativeTo

	watcherMu sync.Mutex
	watchers  []func(context.Context, []FileEvent)

	fileMu sync.Mutex
	files  map[string]string
}

// NewWorkdir writes the txtar-encoded file data in txt to dir, and returns a
// Workir for operating on these files using
func NewWorkdir(dir string) *Workdir {
	return &Workdir{RelativeTo: RelativeTo(dir)}
}

func hashFile(data []byte) string {
	return fmt.Sprintf("%x", sha256.Sum256(data))
}

func (w *Workdir) writeInitialFiles(files map[string][]byte) error {
	w.files = map[string]string{}
	for name, data := range files {
		w.files[name] = hashFile(data)
		if err := WriteFileData(name, data, w.RelativeTo); err != nil {
			return errors.Errorf("writing to workdir: %w", err)
		}
	}
	return nil
}

// RootURI returns the root URI for this working directory of this scratch
// environment.
func (w *Workdir) RootURI() protocol.DocumentURI {
	return toURI(string(w.RelativeTo))
}

// AddWatcher registers the given func to be called on any file change.
func (w *Workdir) AddWatcher(watcher func(context.Context, []FileEvent)) {
	w.watcherMu.Lock()
	w.watchers = append(w.watchers, watcher)
	w.watcherMu.Unlock()
}

// URI returns the URI to a the workdir-relative path.
func (w *Workdir) URI(path string) protocol.DocumentURI {
	return toURI(w.AbsPath(path))
}

// URIToPath converts a uri to a workdir-relative path (or an absolute path,
// if the uri is outside of the workdir).
func (w *Workdir) URIToPath(uri protocol.DocumentURI) string {
	fp := uri.SpanURI().Filename()
	return w.RelPath(fp)
}

func toURI(fp string) protocol.DocumentURI {
	return protocol.DocumentURI(span.URIFromPath(fp))
}

// ReadFile reads a text file specified by a workdir-relative path.
func (w *Workdir) ReadFile(path string) (string, error) {
	backoff := 1 * time.Millisecond
	for {
		b, err := ioutil.ReadFile(w.AbsPath(path))
		if err != nil {
			if runtime.GOOS == "plan9" && strings.HasSuffix(err.Error(), " exclusive use file already open") {
				// Plan 9 enforces exclusive access to locked files.
				// Give the owner time to unlock it and retry.
				time.Sleep(backoff)
				backoff *= 2
				continue
			}
			return "", err
		}
		return string(b), nil
	}
}

func (w *Workdir) RegexpRange(path, re string) (Pos, Pos, error) {
	content, err := w.ReadFile(path)
	if err != nil {
		return Pos{}, Pos{}, err
	}
	return regexpRange(content, re)
}

// RegexpSearch searches the file corresponding to path for the first position
// matching re.
func (w *Workdir) RegexpSearch(path string, re string) (Pos, error) {
	content, err := w.ReadFile(path)
	if err != nil {
		return Pos{}, err
	}
	start, _, err := regexpRange(content, re)
	return start, err
}

// ChangeFilesOnDisk executes the given on-disk file changes in a batch,
// simulating the action of changing branches outside of an editor.
func (w *Workdir) ChangeFilesOnDisk(ctx context.Context, events []FileEvent) error {
	for _, e := range events {
		switch e.ProtocolEvent.Type {
		case protocol.Deleted:
			fp := w.AbsPath(e.Path)
			if err := os.Remove(fp); err != nil {
				return errors.Errorf("removing %q: %w", e.Path, err)
			}
		case protocol.Changed, protocol.Created:
			if _, err := w.writeFile(ctx, e.Path, e.Content); err != nil {
				return err
			}
		}
	}
	w.sendEvents(ctx, events)
	return nil
}

// RemoveFile removes a workdir-relative file path.
func (w *Workdir) RemoveFile(ctx context.Context, path string) error {
	fp := w.AbsPath(path)
	if err := os.RemoveAll(fp); err != nil {
		return errors.Errorf("removing %q: %w", path, err)
	}
	w.fileMu.Lock()
	defer w.fileMu.Unlock()

	evts := []FileEvent{{
		Path: path,
		ProtocolEvent: protocol.FileEvent{
			URI:  w.URI(path),
			Type: protocol.Deleted,
		},
	}}
	w.sendEvents(ctx, evts)
	delete(w.files, path)
	return nil
}

func (w *Workdir) sendEvents(ctx context.Context, evts []FileEvent) {
	if len(evts) == 0 {
		return
	}
	w.watcherMu.Lock()
	watchers := make([]func(context.Context, []FileEvent), len(w.watchers))
	copy(watchers, w.watchers)
	w.watcherMu.Unlock()
	for _, w := range watchers {
		w(ctx, evts)
	}
}

// WriteFiles writes the text file content to workdir-relative paths.
// It batches notifications rather than sending them consecutively.
func (w *Workdir) WriteFiles(ctx context.Context, files map[string]string) error {
	var evts []FileEvent
	for filename, content := range files {
		evt, err := w.writeFile(ctx, filename, content)
		if err != nil {
			return err
		}
		evts = append(evts, evt)
	}
	w.sendEvents(ctx, evts)
	return nil
}

// WriteFile writes text file content to a workdir-relative path.
func (w *Workdir) WriteFile(ctx context.Context, path, content string) error {
	evt, err := w.writeFile(ctx, path, content)
	if err != nil {
		return err
	}
	w.sendEvents(ctx, []FileEvent{evt})
	return nil
}

func (w *Workdir) writeFile(ctx context.Context, path, content string) (FileEvent, error) {
	fp := w.AbsPath(path)
	_, err := os.Stat(fp)
	if err != nil && !os.IsNotExist(err) {
		return FileEvent{}, errors.Errorf("checking if %q exists: %w", path, err)
	}
	var changeType protocol.FileChangeType
	if os.IsNotExist(err) {
		changeType = protocol.Created
	} else {
		changeType = protocol.Changed
	}
	if err := WriteFileData(path, []byte(content), w.RelativeTo); err != nil {
		return FileEvent{}, err
	}
	return FileEvent{
		Path: path,
		ProtocolEvent: protocol.FileEvent{
			URI:  w.URI(path),
			Type: changeType,
		},
	}, nil
}

// listFiles lists files in the given directory, returning a map of relative
// path to modification time.
func (w *Workdir) listFiles(dir string) (map[string]string, error) {
	files := make(map[string]string)
	absDir := w.AbsPath(dir)
	if err := filepath.Walk(absDir, func(fp string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			return nil
		}
		path := w.RelPath(fp)
		data, err := ioutil.ReadFile(fp)
		if err != nil {
			return err
		}
		files[path] = hashFile(data)
		return nil
	}); err != nil {
		return nil, err
	}
	return files, nil
}

// CheckForFileChanges walks the working directory and checks for any files
// that have changed since the last poll.
func (w *Workdir) CheckForFileChanges(ctx context.Context) error {
	evts, err := w.pollFiles()
	if err != nil {
		return err
	}
	w.sendEvents(ctx, evts)
	return nil
}

// pollFiles updates w.files and calculates FileEvents corresponding to file
// state changes since the last poll. It does not call sendEvents.
func (w *Workdir) pollFiles() ([]FileEvent, error) {
	w.fileMu.Lock()
	defer w.fileMu.Unlock()

	files, err := w.listFiles(".")
	if err != nil {
		return nil, err
	}
	var evts []FileEvent
	// Check which files have been added or modified.
	for path, hash := range files {
		oldhash, ok := w.files[path]
		delete(w.files, path)
		var typ protocol.FileChangeType
		switch {
		case !ok:
			typ = protocol.Created
		case oldhash != hash:
			typ = protocol.Changed
		default:
			continue
		}
		evts = append(evts, FileEvent{
			Path: path,
			ProtocolEvent: protocol.FileEvent{
				URI:  w.URI(path),
				Type: typ,
			},
		})
	}
	// Any remaining files must have been deleted.
	for path := range w.files {
		evts = append(evts, FileEvent{
			Path: path,
			ProtocolEvent: protocol.FileEvent{
				URI:  w.URI(path),
				Type: protocol.Deleted,
			},
		})
	}
	w.files = files
	return evts, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 SUSE LLC. All rights reserved.
//
// 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 regionsrv

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
)

// ParseStdin parses the standard input as given by zypper and returns a map
// with the parsed parameters.
func ParseStdin() (map[string]string, error) {
	params := make(map[string]string)
	first := true

	// The zypper plugin protocol is based on STOMP. STOMP messages
	// are NUL-terminated. So read the entire message first
	reader := bufio.NewReader(os.Stdin)
	msg, err := reader.ReadBytes(0)
	if err != nil && err != io.EOF {
		return nil, err
	}

	// Now read the message line by line. URL resolver plugin messages
	// are just <key>:<value> header lines and don't contain a body.
	sr := bytes.NewReader(msg)
	scanner := bufio.NewScanner(sr)
	for scanner.Scan() {
		if first {
			first = false
		} else {
			vals := strings.SplitN(scanner.Text(), ":", 2)
			if len(vals) == 2 {
				params[vals[0]] = vals[1]
			}
		}
	}

	if scanner.Err() != nil {
		return nil, scanner.Err()
	}

	return params, nil
}

// PrintResponse prints to standard output with the format expected by zypper.
func PrintResponse(params map[string]string) error {
	cfg, err := ReadConfigFromServer()
	if err != nil {
		return err
	}

	// Error out if we have no information on the credentials.
	if cfg.Username == "" && cfg.Password == "" {
		return errors.New("No credentials given")
	}

	// Safe the contents of the CA file if it doesn't exist already.
	if err = SafeCAFile(cfg.Ca); err != nil {
		return err
	}

	printFromConfiguration(params["path"], cfg)
	return nil
}

func printFromConfiguration(path string, cfg *ContainerBuildConfig) {
	u := url.URL{
		Scheme: "https",
		Host:   cfg.ServerFqdn,
		Path:   path,
		User:   url.UserPassword(cfg.Username, "XXXX"),
	}

	log.Printf("Resulting X-Instance-Data: %s", cfg.InstanceData)
	log.Printf("Resulting URL: %s", u.String())

	// Add user info to URL to avoid password appearing in logs
	u.User = url.UserPassword(cfg.Username, cfg.Password)

	fmt.Printf("RESOLVEDURL\n")
	// Add an extra emptyline to separate Headers from payload
	fmt.Printf("X-Instance-Data:%s\n\n", cfg.InstanceData)
	// Message needs to be NUL-terminated
	fmt.Printf("%s\000", u.String())

}
<commit_msg>Don't leak Instance Data into logfile<commit_after>// Copyright (c) 2020 SUSE LLC. All rights reserved.
//
// 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 regionsrv

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"net/url"
	"os"
	"strings"
)

// ParseStdin parses the standard input as given by zypper and returns a map
// with the parsed parameters.
func ParseStdin() (map[string]string, error) {
	params := make(map[string]string)
	first := true

	// The zypper plugin protocol is based on STOMP. STOMP messages
	// are NUL-terminated. So read the entire message first
	reader := bufio.NewReader(os.Stdin)
	msg, err := reader.ReadBytes(0)
	if err != nil && err != io.EOF {
		return nil, err
	}

	// Now read the message line by line. URL resolver plugin messages
	// are just <key>:<value> header lines and don't contain a body.
	sr := bytes.NewReader(msg)
	scanner := bufio.NewScanner(sr)
	for scanner.Scan() {
		if first {
			first = false
		} else {
			vals := strings.SplitN(scanner.Text(), ":", 2)
			if len(vals) == 2 {
				params[vals[0]] = vals[1]
			}
		}
	}

	if scanner.Err() != nil {
		return nil, scanner.Err()
	}

	return params, nil
}

// PrintResponse prints to standard output with the format expected by zypper.
func PrintResponse(params map[string]string) error {
	cfg, err := ReadConfigFromServer()
	if err != nil {
		return err
	}

	// Error out if we have no information on the credentials.
	if cfg.Username == "" && cfg.Password == "" {
		return errors.New("No credentials given")
	}

	// Safe the contents of the CA file if it doesn't exist already.
	if err = SafeCAFile(cfg.Ca); err != nil {
		return err
	}

	printFromConfiguration(params["path"], cfg)
	return nil
}

func printFromConfiguration(path string, cfg *ContainerBuildConfig) {
	u := url.URL{
		Scheme: "https",
		Host:   cfg.ServerFqdn,
		Path:   path,
		User:   url.UserPassword(cfg.Username, "XXXX"),
	}

	log.Print("Received X-Instance-Data")
	log.Printf("Resulting URL: %s", u.String())

	// Add user info to URL to avoid password appearing in logs
	u.User = url.UserPassword(cfg.Username, cfg.Password)

	fmt.Printf("RESOLVEDURL\n")
	// Add an extra emptyline to separate Headers from payload
	fmt.Printf("X-Instance-Data:%s\n\n", cfg.InstanceData)
	// Message needs to be NUL-terminated
	fmt.Printf("%s\000", u.String())

}
<|endoftext|>