<commit_before>package http

import (
	"encoding/json"
	"io/ioutil"
	"strconv"
	"strings"
)

var DEFAULT_CONTROLLER *Controller = new(Controller)

type ControllerIfac interface {
	Init(ctx *Context)
	Finish()
}

type Controller struct {
	Ctx       *Context
	TemplPath string
}

func (this *Controller) Init(ctx *Context) {
	this.Ctx = ctx
}

func (this *Controller) Option() {
	allowMethods := []string{}
	for _, method := range HTTP_METHOD {
		allowMethods = append(allowMethods, method)
	}
	this.Ctx.Resp.Headers.Add(HTTP_HEAD_ALLOW, strings.Join(allowMethods, ", "))
}

func (this *Controller) getString(param string) string {
	if len(this.Ctx.Req.Url.Query().Get(param)) > 0 {
		return this.Ctx.Req.Url.Query().Get(param)[0]
	}
	return ""
}

func (this *Controller) GetString(param string) string {
	return this.getString(param)
}

func (this *Controller) GetInt(param string) int {
	if this.getString(param) != "" {
		i, _ := strconv.Atoi(this.getString(param))
		return i
	}
	return 0
}

func (this *Controller) ServeJson(j interface{}) {
	this.Ctx.Resp.Headers.Add(HTTP_HEAD_CONTENTTYPE, "text/plain; charset=utf-8")
	v, _ := json.Marshal(j)
	this.Ctx.Resp.Body = string(v)
}

func (this *Controller) ServeView(params ...interface{}) {
	if len(params) <= 0 {

	} else if len(params) == 1 {
		this.Ctx.Resp.Headers.Add(HTTP_HEAD_CONTENTTYPE, "text/html; charset=utf-8")
		if templ, exists := ViewsTemplFiles[params[0].(string)]; exists {
			v, _ := ioutil.ReadFile(templ)
			this.Ctx.Resp.Body = string(v)
		} else {
			ErrLog.Println("Can't find the template file", params)
		}
	} else {

	}
}

func (this *Controller) ServeFile(params ...interface{}) {
	if len(params) <= 0 {

	} else if len(params) == 1 {
		if templ, exists := ViewsTemplFiles[params[0].(string)]; exists {
			this.Ctx.Resp.Body = string(templ)
		} else {
			ErrLog.Println("Can't find the template file", params)
		}
	} else {

	}
}

func (this *Controller) Favicon() {
	this.Ctx.Resp.StatusCode = StatusFound
	this.Ctx.Resp.Headers.Add(HTTP_HEAD_LOCATION, "http://7b1h1l.com1.z0.glb.clouddn.com/c32.ico")
}

func (this *Controller) Finish() {
}
<commit_msg>add deboglog<commit_after>package http

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strconv"
	"strings"
)

var DEFAULT_CONTROLLER *Controller = new(Controller)

type ControllerIfac interface {
	Init(ctx *Context)
	Finish()
}

type Controller struct {
	Ctx       *Context
	TemplPath string
}

func (this *Controller) Init(ctx *Context) {
	this.Ctx = ctx
}

func (this *Controller) Option() {
	allowMethods := []string{}
	for _, method := range HTTP_METHOD {
		allowMethods = append(allowMethods, method)
	}
	this.Ctx.Resp.Headers.Add(HTTP_HEAD_ALLOW, strings.Join(allowMethods, ", "))
}

func (this *Controller) getString(param string) string {
	if len(this.Ctx.Req.Url.Query().Get(param)) > 0 {
		return this.Ctx.Req.Url.Query().Get(param)[0]
	}
	return ""
}

func (this *Controller) GetString(param string) string {
	return this.getString(param)
}

func (this *Controller) GetInt(param string) int {
	if this.getString(param) != "" {
		i, _ := strconv.Atoi(this.getString(param))
		return i
	}
	return 0
}

func (this *Controller) ServeJson(j interface{}) {
	this.Ctx.Resp.Headers.Add(HTTP_HEAD_CONTENTTYPE, "text/plain; charset=utf-8")
	v, _ := json.Marshal(j)
	this.Ctx.Resp.Body = string(v)
}

func (this *Controller) ServeView(params ...interface{}) {
	if len(params) <= 0 {

	} else if len(params) == 1 {
		if templ, exists := ViewsTemplFiles[params[0].(string)]; exists {
			this.Ctx.Resp.Headers.Add(HTTP_HEAD_CONTENTTYPE, "text/html; charset=utf-8")
			v, _ := ioutil.ReadFile(templ)
			this.Ctx.Resp.Body = string(v)
		} else {
			this.debugLog(fmt.Sprintf("Can't find the template file %v", params))
			ErrLog.Println("Can't find the template file", params)
		}
	} else {

	}
}

func (this *Controller) ServeFile(params ...interface{}) {
	if len(params) <= 0 {

	} else if len(params) == 1 {
		if templ, exists := ViewsTemplFiles[params[0].(string)]; exists {
			this.Ctx.Resp.Body = string(templ)
		} else {
			ErrLog.Println("Can't find the template file", params)
		}
	} else {

	}
}

func (this *Controller) debugLog(log string) {
	this.Ctx.Resp.Body = log
}

func (this *Controller) Favicon() {
	this.Ctx.Resp.StatusCode = StatusFound
	this.Ctx.Resp.Headers.Add(HTTP_HEAD_LOCATION, "http://7b1h1l.com1.z0.glb.clouddn.com/c32.ico")
}

func (this *Controller) Finish() {
}
<|endoftext|>


<commit_before>package client

import (
	"context"
	"time"

	"koding/klient/machine/index"
)

// DynamicClientFunc is an adapter that allows to dynamically provide clients.
type DynamicClientFunc func() (Client, error)

// Supervised is a decorator type for Clients which will wait for valid client
// if the current client is Disconnected. This type is meant to handle temporary
// network issues or cases when underlying client is not set up yet. Eg. when
// program started but haven't made connection to remote machine yet.
type Supervised struct {
	dcf     DynamicClientFunc
	timeout time.Duration
}

// NewSupervised creates a new Supervised client instance.
func NewSupervised(dcf DynamicClientFunc, timeout time.Duration) *Supervised {
	return &Supervised{
		timeout: timeout,
		dcf:     dcf,
	}
}

// CurrentUser calls registered Client's CurrentUser method and returns its
// result if it's not produced by Disconnected client. If it is, this function
// will wait until valid client is available or timeout is reached.
func (s *Supervised) CurrentUser() (user string, err error) {
	if e := s.call(func(c Client) error {
		user, err = c.CurrentUser()
		return err
	}); e != nil {
		return "", e
	}

	return
}

// SSHAddKeys calls registered Client's SSHAddKeys method and returns its result
// if it's not produced by Disconnected client. If it is, this function will
// wait until valid client is available or timeout is reached.
func (s *Supervised) SSHAddKeys(username string, keys ...string) (err error) {
	if e := s.call(func(c Client) error {
		err = c.SSHAddKeys(username, keys...)
		return err
	}); e != nil {
		return e
	}

	return
}

// MountHeadIndex calls registered Client's MountHeadIndex method and returns
// its result if it's not produced by Disconnected client. If it is, this
// function will wait until valid client is available or timeout is reached.
func (s *Supervised) MountHeadIndex(path string) (absPath string, count int, diskSize int64, err error) {
	if e := s.call(func(c Client) error {
		absPath, count, diskSize, err = c.MountHeadIndex(path)
		return err
	}); e != nil {
		return "", 0, 0, e
	}

	return
}

// MountGetIndex calls registered Client's MountGetIndex method and returns its
// result if it's not produced by Disconnected client. If it is, this function
// will wait until valid client is available or timeout is reached.
func (s *Supervised) MountGetIndex(path string) (idx *index.Index, err error) {
	if e := s.call(func(c Client) error {
		idx, err = c.MountGetIndex(path)
		return err
	}); e != nil {
		return nil, e
	}

	return
}

// Context calls registered Client's Context method and returns its result. If
// there is an error during client retrieving, this function will return
// canceled context.
func (s *Supervised) Context() context.Context {
	c, err := s.dcf()
	if err != nil {
		ctx, cancel := context.WithCancel(context.Background())
		cancel()
		return ctx
	}

	return c.Context()
}

func (s *Supervised) call(f func(Client) error) error {
	c, err := s.dcf()
	if err != nil {
		return err
	}

	ctx := c.Context()
	if err = f(c); err != ErrDisconnected {
		return err
	}

	// Wait for new client.
	ctx, cancel := context.WithTimeout(ctx, s.timeout)
	defer cancel()

	if _ = <-ctx.Done(); ctx.Err() == context.DeadlineExceeded {
		// Client is still disconnected. Return it as is.
		return nil
	}

	// Previous context was canceled. This means that the client changed.
	c, err = s.dcf()
	if err != nil {
		return err
	}

	return f(c)
}
<commit_msg>klient/machine: remove redundant null placeholder<commit_after>package client

import (
	"context"
	"time"

	"koding/klient/machine/index"
)

// DynamicClientFunc is an adapter that allows to dynamically provide clients.
type DynamicClientFunc func() (Client, error)

// Supervised is a decorator type for Clients which will wait for valid client
// if the current client is Disconnected. This type is meant to handle temporary
// network issues or cases when underlying client is not set up yet. Eg. when
// program started but haven't made connection to remote machine yet.
type Supervised struct {
	dcf     DynamicClientFunc
	timeout time.Duration
}

// NewSupervised creates a new Supervised client instance.
func NewSupervised(dcf DynamicClientFunc, timeout time.Duration) *Supervised {
	return &Supervised{
		timeout: timeout,
		dcf:     dcf,
	}
}

// CurrentUser calls registered Client's CurrentUser method and returns its
// result if it's not produced by Disconnected client. If it is, this function
// will wait until valid client is available or timeout is reached.
func (s *Supervised) CurrentUser() (user string, err error) {
	if e := s.call(func(c Client) error {
		user, err = c.CurrentUser()
		return err
	}); e != nil {
		return "", e
	}

	return
}

// SSHAddKeys calls registered Client's SSHAddKeys method and returns its result
// if it's not produced by Disconnected client. If it is, this function will
// wait until valid client is available or timeout is reached.
func (s *Supervised) SSHAddKeys(username string, keys ...string) (err error) {
	if e := s.call(func(c Client) error {
		err = c.SSHAddKeys(username, keys...)
		return err
	}); e != nil {
		return e
	}

	return
}

// MountHeadIndex calls registered Client's MountHeadIndex method and returns
// its result if it's not produced by Disconnected client. If it is, this
// function will wait until valid client is available or timeout is reached.
func (s *Supervised) MountHeadIndex(path string) (absPath string, count int, diskSize int64, err error) {
	if e := s.call(func(c Client) error {
		absPath, count, diskSize, err = c.MountHeadIndex(path)
		return err
	}); e != nil {
		return "", 0, 0, e
	}

	return
}

// MountGetIndex calls registered Client's MountGetIndex method and returns its
// result if it's not produced by Disconnected client. If it is, this function
// will wait until valid client is available or timeout is reached.
func (s *Supervised) MountGetIndex(path string) (idx *index.Index, err error) {
	if e := s.call(func(c Client) error {
		idx, err = c.MountGetIndex(path)
		return err
	}); e != nil {
		return nil, e
	}

	return
}

// Context calls registered Client's Context method and returns its result. If
// there is an error during client retrieving, this function will return
// canceled context.
func (s *Supervised) Context() context.Context {
	c, err := s.dcf()
	if err != nil {
		ctx, cancel := context.WithCancel(context.Background())
		cancel()
		return ctx
	}

	return c.Context()
}

func (s *Supervised) call(f func(Client) error) error {
	c, err := s.dcf()
	if err != nil {
		return err
	}

	ctx := c.Context()
	if err = f(c); err != ErrDisconnected {
		return err
	}

	// Wait for new client.
	ctx, cancel := context.WithTimeout(ctx, s.timeout)
	defer cancel()

	if <-ctx.Done(); ctx.Err() == context.DeadlineExceeded {
		// Client is still disconnected. Return it as is.
		return nil
	}

	// Previous context was canceled. This means that the client changed.
	c, err = s.dcf()
	if err != nil {
		return err
	}

	return f(c)
}
<|endoftext|>


<commit_before>package check

import (
	"fmt"
	"strings"
)

type PackageNotInstalledCheck struct {
	PackageQuery               PackageQuery
	AcceptablePackageVersion   string
	PackageManager             PackageManager
	InstallationDisabled       bool
	DockerInstallationDisabled bool
}

// Check returns true if the specified package is not installed.
// This will also return true if the version installed matches AcceptablePackageVersion.
// When InstallationDisabled is true this check will always return true.
func (c PackageNotInstalledCheck) Check() (bool, error) {
	// don't check when installation is disabled
	if c.InstallationDisabled {
		return true, nil
	}
	// When docker installation is disabled do not check for any packages that contain "docker" in the name
	// The package name could be different, we will only validate the docker executable is present
	if c.DockerInstallationDisabled && strings.Contains(c.PackageQuery.Name, "docker") {
		return true, nil
	}
	// check for the package with optional version is installed
	installed, err := c.PackageManager.IsInstalled(c.PackageQuery)
	if err != nil {
		return false, fmt.Errorf("failed to determine if package is installed: %v", err)
	}
	// return true if nothing is installed
	if !installed {
		return true, nil
	}
	if c.AcceptablePackageVersion == "" {
		return false, fmt.Errorf("package should not be installed")
	}
	// check if the version installed is the acceptable version
	acceptableVersionInstalled, err := c.PackageManager.IsInstalled(PackageQuery{Name: c.PackageQuery.Name, Version: c.AcceptablePackageVersion})
	if err != nil {
		return false, fmt.Errorf("failed to determine if package is installed: %v", err)
	}
	if acceptableVersionInstalled {
		return true, nil
	}
	return false, nil
}
<commit_msg>Minor inspector error message changes [skip ci]<commit_after>package check

import (
	"fmt"
	"strings"
)

type PackageNotInstalledCheck struct {
	PackageQuery               PackageQuery
	AcceptablePackageVersion   string
	PackageManager             PackageManager
	InstallationDisabled       bool
	DockerInstallationDisabled bool
}

// Check returns true if the specified package is not installed.
// This will also return true if the version installed matches AcceptablePackageVersion.
// When InstallationDisabled is true this check will always return true.
func (c PackageNotInstalledCheck) Check() (bool, error) {
	// don't check when installation is disabled
	if c.InstallationDisabled {
		return true, nil
	}
	// When docker installation is disabled do not check for any packages that contain "docker" in the name
	// The package name could be different, we will only validate the docker executable is present
	if c.DockerInstallationDisabled && strings.Contains(c.PackageQuery.Name, "docker") {
		return true, nil
	}
	// check for the package with optional version is installed
	installed, err := c.PackageManager.IsInstalled(c.PackageQuery)
	if err != nil {
		return false, fmt.Errorf("failed to determine if package is installed: %v", err)
	}
	// return true if nothing is installed
	if !installed {
		return true, nil
	}
	if c.AcceptablePackageVersion == "" {
		return false, fmt.Errorf("uninstall package before retrying")
	}
	// check if the version installed is the acceptable version
	acceptableVersionInstalled, err := c.PackageManager.IsInstalled(PackageQuery{Name: c.PackageQuery.Name, Version: c.AcceptablePackageVersion})
	if err != nil {
		return false, fmt.Errorf("failed to determine if package is installed: %v", err)
	}
	if acceptableVersionInstalled {
		return true, nil
	}
	return false, nil
}
<|endoftext|>


<commit_before>// +skip_license_check

/*
This file contains portions of code directly taken from the 'xenolf/lego' project.
A copy of the license for this code can be found in the file named LICENSE in
this directory.
*/

// Package cloudflare implements a DNS provider for solving the DNS-01
// challenge using cloudflare DNS.
package cloudflare

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"

	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util"
	pkgutil "github.com/jetstack/cert-manager/pkg/util"
)

// CloudFlareAPIURL represents the API endpoint to call.
// TODO: Unexport?
const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4"

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	dns01Nameservers []string
	authEmail        string
	authKey          string
	authToken        string
}

// NewDNSProvider returns a DNSProvider instance configured for cloudflare.
// Credentials must be passed in the environment variables: CLOUDFLARE_EMAIL
// and CLOUDFLARE_API_KEY.
func NewDNSProvider(dns01Nameservers []string) (*DNSProvider, error) {
	email := os.Getenv("CLOUDFLARE_EMAIL")
	key := os.Getenv("CLOUDFLARE_API_KEY")
	return NewDNSProviderCredentials(email, key, "", dns01Nameservers)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for cloudflare.
func NewDNSProviderCredentials(email, key, token string, dns01Nameservers []string) (*DNSProvider, error) {
	if (email == "" && key != "") || (key == "" && token == "") {
		return nil, fmt.Errorf("CloudFlare credentials missing")
	}
	if key != "" && token != "" {
		return nil, fmt.Errorf("CloudFlare key and token are both present")
	}
	// cloudflare uses X-Auth-Key as a header for its
	// authentication. However, if it's an invalid value, the go
	// http library will "helpfully" print out the value to help with
	// debugging.
	//
	// Check that the auth key is a valid header value before we leak it to the logs
	if !validHeaderFieldValue(key) {
		return nil, fmt.Errorf("Cloudflare key invalid (does the key contain a newline?)")
	}

	if !validHeaderFieldValue(token) {
		return nil, fmt.Errorf("Cloudflare token invalid (does the token contain a newline?)")
	}

	return &DNSProvider{
		authEmail:        email,
		authKey:          key,
		authToken:        token,
		dns01Nameservers: dns01Nameservers,
	}, nil
}

// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, fqdn, value string) error {
	zoneID, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	record, err := c.findTxtRecord(fqdn)
	if err != nil && err != errNoExistingRecord {
		// this is a real error
		return err
	}
	if record != nil {
		if record.Content == value {
			// the record is already set to the desired value
			return nil
		}

		_, err = c.makeRequest("DELETE", fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil)
		if err != nil {
			return err
		}
	}

	rec := cloudFlareRecord{
		Type:    "TXT",
		Name:    util.UnFqdn(fqdn),
		Content: value,
		TTL:     120,
	}

	body, err := json.Marshal(rec)
	if err != nil {
		return err
	}

	_, err = c.makeRequest("POST", fmt.Sprintf("/zones/%s/dns_records", zoneID), bytes.NewReader(body))
	if err != nil {
		return err
	}

	return nil
}

// CleanUp removes the TXT record matching the specified parameters
func (c *DNSProvider) CleanUp(domain, fqdn, value string) error {
	record, err := c.findTxtRecord(fqdn)
	// Nothing to cleanup
	if err == errNoExistingRecord {
		return nil
	}
	if err != nil {
		return err
	}

	_, err = c.makeRequest("DELETE", fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil)
	if err != nil {
		return err
	}

	return nil
}

func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
	// HostedZone represents a CloudFlare DNS zone
	type HostedZone struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	}

	authZone, err := util.FindZoneByFqdn(fqdn, c.dns01Nameservers)
	if err != nil {
		return "", err
	}

	result, err := c.makeRequest("GET", "/zones?name="+util.UnFqdn(authZone), nil)
	if err != nil {
		return "", err
	}

	var hostedZone []HostedZone
	err = json.Unmarshal(result, &hostedZone)
	if err != nil {
		return "", err
	}

	if len(hostedZone) != 1 {
		return "", fmt.Errorf("Zone %s not found in CloudFlare for domain %s", authZone, fqdn)
	}

	return hostedZone[0].ID, nil
}

var errNoExistingRecord = errors.New("No existing record found")

func (c *DNSProvider) findTxtRecord(fqdn string) (*cloudFlareRecord, error) {
	zoneID, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return nil, err
	}

	result, err := c.makeRequest(
		"GET",
		fmt.Sprintf("/zones/%s/dns_records?per_page=100&type=TXT&name=%s", zoneID, util.UnFqdn(fqdn)),
		nil,
	)
	if err != nil {
		return nil, err
	}

	var records []cloudFlareRecord
	err = json.Unmarshal(result, &records)
	if err != nil {
		return nil, err
	}

	for _, rec := range records {
		if rec.Name == util.UnFqdn(fqdn) {
			return &rec, nil
		}
	}

	return nil, errNoExistingRecord
}

func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
	// APIError contains error details for failed requests
	type APIError struct {
		Code       int        `json:"code,omitempty"`
		Message    string     `json:"message,omitempty"`
		ErrorChain []APIError `json:"error_chain,omitempty"`
	}

	// APIResponse represents a response from CloudFlare API
	type APIResponse struct {
		Success bool            `json:"success"`
		Errors  []*APIError     `json:"errors"`
		Result  json.RawMessage `json:"result"`
	}

	req, err := http.NewRequest(method, fmt.Sprintf("%s%s", CloudFlareAPIURL, uri), body)
	if err != nil {
		return nil, err
	}

	if c.authEmail != "" {
		req.Header.Set("X-Auth-Email", c.authEmail)
	}
	if c.authToken != "" {
		req.Header.Set("Authorization", "Bearer "+c.authToken)
	} else {
		req.Header.Set("X-Auth-Key", c.authKey)
	}
	req.Header.Set("User-Agent", pkgutil.CertManagerUserAgent)

	client := http.Client{
		Timeout: 30 * time.Second,
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Error querying Cloudflare API -> %v", err)
	}

	defer resp.Body.Close()

	var r APIResponse
	err = json.NewDecoder(resp.Body).Decode(&r)
	if err != nil {
		return nil, err
	}

	if !r.Success {
		if len(r.Errors) > 0 {
			errStr := ""
			for _, apiErr := range r.Errors {
				errStr += fmt.Sprintf("\t Error: %d: %s", apiErr.Code, apiErr.Message)
				for _, chainErr := range apiErr.ErrorChain {
					errStr += fmt.Sprintf("<- %d: %s", chainErr.Code, chainErr.Message)
				}
			}
			return nil, fmt.Errorf("Cloudflare API Error \n%s", errStr)
		}
		return nil, fmt.Errorf("Cloudflare API error")
	}

	return r.Result, nil
}

// cloudFlareRecord represents a CloudFlare DNS record
type cloudFlareRecord struct {
	Name    string `json:"name"`
	Type    string `json:"type"`
	Content string `json:"content"`
	ID      string `json:"id,omitempty"`
	TTL     int    `json:"ttl,omitempty"`
	ZoneID  string `json:"zone_id,omitempty"`
}

// following functions are copy-pasted from go's internal
// http server
func validHeaderFieldValue(v string) bool {
	for i := 0; i < len(v); i++ {
		b := v[i]
		if isCTL(b) && !isLWS(b) {
			return false
		}
	}
	return true
}

func isCTL(b byte) bool {
	const del = 0x7f // a CTL
	return b < ' ' || b == del
}

func isLWS(b byte) bool { return b == ' ' || b == '\t' }
<commit_msg>Improve error output for Cloudflare<commit_after>// +skip_license_check

/*
This file contains portions of code directly taken from the 'xenolf/lego' project.
A copy of the license for this code can be found in the file named LICENSE in
this directory.
*/

// Package cloudflare implements a DNS provider for solving the DNS-01
// challenge using cloudflare DNS.
package cloudflare

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"

	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util"
	pkgutil "github.com/jetstack/cert-manager/pkg/util"
)

// CloudFlareAPIURL represents the API endpoint to call.
// TODO: Unexport?
const CloudFlareAPIURL = "https://api.cloudflare.com/client/v4"

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	dns01Nameservers []string
	authEmail        string
	authKey          string
	authToken        string
}

// NewDNSProvider returns a DNSProvider instance configured for cloudflare.
// Credentials must be passed in the environment variables: CLOUDFLARE_EMAIL
// and CLOUDFLARE_API_KEY.
func NewDNSProvider(dns01Nameservers []string) (*DNSProvider, error) {
	email := os.Getenv("CLOUDFLARE_EMAIL")
	key := os.Getenv("CLOUDFLARE_API_KEY")
	return NewDNSProviderCredentials(email, key, "", dns01Nameservers)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for cloudflare.
func NewDNSProviderCredentials(email, key, token string, dns01Nameservers []string) (*DNSProvider, error) {
	if (email == "" && key != "") || (key == "" && token == "") {
		return nil, fmt.Errorf("CloudFlare credentials missing")
	}
	if key != "" && token != "" {
		return nil, fmt.Errorf("CloudFlare key and token are both present")
	}
	// cloudflare uses X-Auth-Key as a header for its
	// authentication. However, if it's an invalid value, the go
	// http library will "helpfully" print out the value to help with
	// debugging.
	//
	// Check that the auth key is a valid header value before we leak it to the logs
	if !validHeaderFieldValue(key) {
		return nil, fmt.Errorf("Cloudflare key invalid (does the key contain a newline?)")
	}

	if !validHeaderFieldValue(token) {
		return nil, fmt.Errorf("Cloudflare token invalid (does the token contain a newline?)")
	}

	return &DNSProvider{
		authEmail:        email,
		authKey:          key,
		authToken:        token,
		dns01Nameservers: dns01Nameservers,
	}, nil
}

// Present creates a TXT record to fulfil the dns-01 challenge
func (c *DNSProvider) Present(domain, fqdn, value string) error {
	zoneID, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return err
	}

	record, err := c.findTxtRecord(fqdn)
	if err != nil && err != errNoExistingRecord {
		// this is a real error
		return err
	}
	if record != nil {
		if record.Content == value {
			// the record is already set to the desired value
			return nil
		}

		_, err = c.makeRequest("DELETE", fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil)
		if err != nil {
			return err
		}
	}

	rec := cloudFlareRecord{
		Type:    "TXT",
		Name:    util.UnFqdn(fqdn),
		Content: value,
		TTL:     120,
	}

	body, err := json.Marshal(rec)
	if err != nil {
		return err
	}

	_, err = c.makeRequest("POST", fmt.Sprintf("/zones/%s/dns_records", zoneID), bytes.NewReader(body))
	if err != nil {
		return err
	}

	return nil
}

// CleanUp removes the TXT record matching the specified parameters
func (c *DNSProvider) CleanUp(domain, fqdn, value string) error {
	record, err := c.findTxtRecord(fqdn)
	// Nothing to cleanup
	if err == errNoExistingRecord {
		return nil
	}
	if err != nil {
		return err
	}

	_, err = c.makeRequest("DELETE", fmt.Sprintf("/zones/%s/dns_records/%s", record.ZoneID, record.ID), nil)
	if err != nil {
		return err
	}

	return nil
}

func (c *DNSProvider) getHostedZoneID(fqdn string) (string, error) {
	// HostedZone represents a CloudFlare DNS zone
	type HostedZone struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	}

	authZone, err := util.FindZoneByFqdn(fqdn, c.dns01Nameservers)
	if err != nil {
		return "", err
	}

	result, err := c.makeRequest("GET", "/zones?name="+util.UnFqdn(authZone), nil)
	if err != nil {
		return "", err
	}

	var hostedZone []HostedZone
	err = json.Unmarshal(result, &hostedZone)
	if err != nil {
		return "", err
	}

	if len(hostedZone) != 1 {
		return "", fmt.Errorf("Zone %s not found in CloudFlare for domain %s", authZone, fqdn)
	}

	return hostedZone[0].ID, nil
}

var errNoExistingRecord = errors.New("No existing record found")

func (c *DNSProvider) findTxtRecord(fqdn string) (*cloudFlareRecord, error) {
	zoneID, err := c.getHostedZoneID(fqdn)
	if err != nil {
		return nil, err
	}

	result, err := c.makeRequest(
		"GET",
		fmt.Sprintf("/zones/%s/dns_records?per_page=100&type=TXT&name=%s", zoneID, util.UnFqdn(fqdn)),
		nil,
	)
	if err != nil {
		return nil, err
	}

	var records []cloudFlareRecord
	err = json.Unmarshal(result, &records)
	if err != nil {
		return nil, err
	}

	for _, rec := range records {
		if rec.Name == util.UnFqdn(fqdn) {
			return &rec, nil
		}
	}

	return nil, errNoExistingRecord
}

func (c *DNSProvider) makeRequest(method, uri string, body io.Reader) (json.RawMessage, error) {
	// APIError contains error details for failed requests
	type APIError struct {
		Code       int        `json:"code,omitempty"`
		Message    string     `json:"message,omitempty"`
		ErrorChain []APIError `json:"error_chain,omitempty"`
	}

	// APIResponse represents a response from CloudFlare API
	type APIResponse struct {
		Success bool            `json:"success"`
		Errors  []*APIError     `json:"errors"`
		Result  json.RawMessage `json:"result"`
	}

	req, err := http.NewRequest(method, fmt.Sprintf("%s%s", CloudFlareAPIURL, uri), body)
	if err != nil {
		return nil, err
	}

	if c.authEmail != "" {
		req.Header.Set("X-Auth-Email", c.authEmail)
	}
	if c.authToken != "" {
		req.Header.Set("Authorization", "Bearer "+c.authToken)
	} else {
		req.Header.Set("X-Auth-Key", c.authKey)
	}
	req.Header.Set("User-Agent", pkgutil.CertManagerUserAgent)

	client := http.Client{
		Timeout: 30 * time.Second,
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Error querying Cloudflare API for  %s %q -> %v", method, uri, err)
	}

	defer resp.Body.Close()

	var r APIResponse
	err = json.NewDecoder(resp.Body).Decode(&r)
	if err != nil {
		return nil, err
	}

	if !r.Success {
		if len(r.Errors) > 0 {
			errStr := ""
			for _, apiErr := range r.Errors {
				errStr += fmt.Sprintf("\t Error: %d: %s", apiErr.Code, apiErr.Message)
				for _, chainErr := range apiErr.ErrorChain {
					errStr += fmt.Sprintf("<- %d: %s", chainErr.Code, chainErr.Message)
				}
			}
			return nil, fmt.Errorf("Cloudflare API Error for %s %q \n%s", method, uri, errStr)
		}
		return nil, fmt.Errorf("Cloudflare API error for  %s %q", method, uri)
	}

	return r.Result, nil
}

// cloudFlareRecord represents a CloudFlare DNS record
type cloudFlareRecord struct {
	Name    string `json:"name"`
	Type    string `json:"type"`
	Content string `json:"content"`
	ID      string `json:"id,omitempty"`
	TTL     int    `json:"ttl,omitempty"`
	ZoneID  string `json:"zone_id,omitempty"`
}

// following functions are copy-pasted from go's internal
// http server
func validHeaderFieldValue(v string) bool {
	for i := 0; i < len(v); i++ {
		b := v[i]
		if isCTL(b) && !isLWS(b) {
			return false
		}
	}
	return true
}

func isCTL(b byte) bool {
	const del = 0x7f // a CTL
	return b < ' ' || b == del
}

func isLWS(b byte) bool { return b == ' ' || b == '\t' }
<|endoftext|>


<commit_before>package notifiers

import (
	"os"
	"strconv"
	"time"

	"fmt"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/alerting"
)

func init() {
	alerting.RegisterNotifier(&alerting.NotifierPlugin{
		Type:        "pagerduty",
		Name:        "PagerDuty",
		Description: "Sends notifications to PagerDuty",
		Factory:     NewPagerdutyNotifier,
		OptionsTemplate: `

PagerDuty settings

        Integration Key
        <input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.integrationKey" placeholder="Pagerduty Integration Key"></input>

        <gf-form-switch
           class="gf-form"
           label="Auto resolve incidents"
           label-class="width-14"
           checked="ctrl.model.settings.autoResolve"
           tooltip="Resolve incidents in pagerduty once the alert goes back to ok.">
        </gf-form-switch>

    `,
	})
}

var (
	pagerdutyEventAPIURL = "https://events.pagerduty.com/v2/enqueue"
)

// NewPagerdutyNotifier is the constructor for the PagerDuty notifier
func NewPagerdutyNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
	autoResolve := model.Settings.Get("autoResolve").MustBool(false)
	key := model.Settings.Get("integrationKey").MustString()
	if key == "" {
		return nil, alerting.ValidationError{Reason: "Could not find integration key property in settings"}
	}

	return &PagerdutyNotifier{
		NotifierBase: NewNotifierBase(model),
		Key:          key,
		AutoResolve:  autoResolve,
		log:          log.New("alerting.notifier.pagerduty"),
	}, nil
}

// PagerdutyNotifier is responsible for sending
// alert notifications to pagerduty
type PagerdutyNotifier struct {
	NotifierBase
	Key         string
	AutoResolve bool
	log         log.Logger
}

// Notify sends an alert notification to PagerDuty
func (pn *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {

	if evalContext.Rule.State == models.AlertStateOK && !pn.AutoResolve {
		pn.log.Info("Not sending a trigger to Pagerduty", "state", evalContext.Rule.State, "auto resolve", pn.AutoResolve)
		return nil
	}

	eventType := "trigger"
	if evalContext.Rule.State == models.AlertStateOK {
		eventType = "resolve"
	}
	customData := triggMetrString
	for _, evt := range evalContext.EvalMatches {
		customData = customData + fmt.Sprintf("%s: %v\n", evt.Metric, evt.Value)
	}

	pn.log.Info("Notifying Pagerduty", "event_type", eventType)

	payloadJSON := simplejson.New()
	payloadJSON.Set("summary", evalContext.Rule.Name+" - "+evalContext.Rule.Message)
	if hostname, err := os.Hostname(); err == nil {
		payloadJSON.Set("source", hostname)
	}
	payloadJSON.Set("severity", "critical")
	payloadJSON.Set("timestamp", time.Now())
	payloadJSON.Set("component", "Grafana")
	payloadJSON.Set("custom_details", customData)

	bodyJSON := simplejson.New()
	bodyJSON.Set("routing_key", pn.Key)
	bodyJSON.Set("event_action", eventType)
	bodyJSON.Set("dedup_key", "alertId-"+strconv.FormatInt(evalContext.Rule.ID, 10))
	bodyJSON.Set("payload", payloadJSON)

	ruleURL, err := evalContext.GetRuleURL()
	if err != nil {
		pn.log.Error("Failed get rule link", "error", err)
		return err
	}
	links := make([]interface{}, 1)
	linkJSON := simplejson.New()
	linkJSON.Set("href", ruleURL)
	bodyJSON.Set("client_url", ruleURL)
	bodyJSON.Set("client", "Grafana")
	links[0] = linkJSON
	bodyJSON.Set("links", links)

	if evalContext.ImagePublicURL != "" {
		contexts := make([]interface{}, 1)
		imageJSON := simplejson.New()
		imageJSON.Set("src", evalContext.ImagePublicURL)
		contexts[0] = imageJSON
		bodyJSON.Set("images", contexts)
	}

	body, _ := bodyJSON.MarshalJSON()

	cmd := &models.SendWebhookSync{
		Url:        pagerdutyEventAPIURL,
		Body:       string(body),
		HttpMethod: "POST",
		HttpHeader: map[string]string{
			"Content-Type": "application/json",
		},
	}

	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
		pn.log.Error("Failed to send notification to Pagerduty", "error", err, "body", string(body))
		return err
	}

	return nil
}
<commit_msg>Alerting: Truncate PagerDuty summary when greater than 1024 characters (#18730)<commit_after>package notifiers

import (
	"os"
	"strconv"
	"time"

	"fmt"

	"github.com/grafana/grafana/pkg/bus"
	"github.com/grafana/grafana/pkg/components/simplejson"
	"github.com/grafana/grafana/pkg/infra/log"
	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/alerting"
)

func init() {
	alerting.RegisterNotifier(&alerting.NotifierPlugin{
		Type:        "pagerduty",
		Name:        "PagerDuty",
		Description: "Sends notifications to PagerDuty",
		Factory:     NewPagerdutyNotifier,
		OptionsTemplate: `

PagerDuty settings

        Integration Key
        <input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.integrationKey" placeholder="Pagerduty Integration Key"></input>

        <gf-form-switch
           class="gf-form"
           label="Auto resolve incidents"
           label-class="width-14"
           checked="ctrl.model.settings.autoResolve"
           tooltip="Resolve incidents in pagerduty once the alert goes back to ok.">
        </gf-form-switch>

    `,
	})
}

var (
	pagerdutyEventAPIURL = "https://events.pagerduty.com/v2/enqueue"
)

// NewPagerdutyNotifier is the constructor for the PagerDuty notifier
func NewPagerdutyNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
	autoResolve := model.Settings.Get("autoResolve").MustBool(false)
	key := model.Settings.Get("integrationKey").MustString()
	if key == "" {
		return nil, alerting.ValidationError{Reason: "Could not find integration key property in settings"}
	}

	return &PagerdutyNotifier{
		NotifierBase: NewNotifierBase(model),
		Key:          key,
		AutoResolve:  autoResolve,
		log:          log.New("alerting.notifier.pagerduty"),
	}, nil
}

// PagerdutyNotifier is responsible for sending
// alert notifications to pagerduty
type PagerdutyNotifier struct {
	NotifierBase
	Key         string
	AutoResolve bool
	log         log.Logger
}

// Notify sends an alert notification to PagerDuty
func (pn *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {

	if evalContext.Rule.State == models.AlertStateOK && !pn.AutoResolve {
		pn.log.Info("Not sending a trigger to Pagerduty", "state", evalContext.Rule.State, "auto resolve", pn.AutoResolve)
		return nil
	}

	eventType := "trigger"
	if evalContext.Rule.State == models.AlertStateOK {
		eventType = "resolve"
	}
	customData := triggMetrString
	for _, evt := range evalContext.EvalMatches {
		customData = customData + fmt.Sprintf("%s: %v\n", evt.Metric, evt.Value)
	}

	pn.log.Info("Notifying Pagerduty", "event_type", eventType)

	payloadJSON := simplejson.New()

	summary := evalContext.Rule.Name + " - " + evalContext.Rule.Message
	if len(summary) > 1024 {
		summary = summary[0:1024]
	}
	payloadJSON.Set("summary", summary)

	if hostname, err := os.Hostname(); err == nil {
		payloadJSON.Set("source", hostname)
	}
	payloadJSON.Set("severity", "critical")
	payloadJSON.Set("timestamp", time.Now())
	payloadJSON.Set("component", "Grafana")
	payloadJSON.Set("custom_details", customData)

	bodyJSON := simplejson.New()
	bodyJSON.Set("routing_key", pn.Key)
	bodyJSON.Set("event_action", eventType)
	bodyJSON.Set("dedup_key", "alertId-"+strconv.FormatInt(evalContext.Rule.ID, 10))
	bodyJSON.Set("payload", payloadJSON)

	ruleURL, err := evalContext.GetRuleURL()
	if err != nil {
		pn.log.Error("Failed get rule link", "error", err)
		return err
	}
	links := make([]interface{}, 1)
	linkJSON := simplejson.New()
	linkJSON.Set("href", ruleURL)
	bodyJSON.Set("client_url", ruleURL)
	bodyJSON.Set("client", "Grafana")
	links[0] = linkJSON
	bodyJSON.Set("links", links)

	if evalContext.ImagePublicURL != "" {
		contexts := make([]interface{}, 1)
		imageJSON := simplejson.New()
		imageJSON.Set("src", evalContext.ImagePublicURL)
		contexts[0] = imageJSON
		bodyJSON.Set("images", contexts)
	}

	body, _ := bodyJSON.MarshalJSON()

	cmd := &models.SendWebhookSync{
		Url:        pagerdutyEventAPIURL,
		Body:       string(body),
		HttpMethod: "POST",
		HttpHeader: map[string]string{
			"Content-Type": "application/json",
		},
	}

	if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
		pn.log.Error("Failed to send notification to Pagerduty", "error", err, "body", string(body))
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package gerrit_test

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/andygrunwald/go-gerrit"
)

func ExampleChangesService_QueryChanges() {
	instance := "https://android-review.googlesource.com/"
	client, err := gerrit.NewClient(instance, nil)
	if err != nil {
		panic(err)
	}

	opt := &gerrit.QueryChangeOptions{}
	opt.Query = []string{
		"change:249244",
	}
	opt.Limit = 2
	opt.AdditionalFields = []string{"LABELS"}
	changes, _, err := client.Changes.QueryChanges(opt)
	if err != nil {
		panic(err)
	}

	for _, change := range *changes {
		fmt.Printf("Project: %s -> %s -> %s%d\n", change.Project, change.Subject, instance, change.Number)
	}

	// Output:
	// Project: platform/art -> ART: Change return types of field access entrypoints -> https://android-review.googlesource.com/249244
}

// Prior to fixing #18 this test would fail.
func ExampleChangesService_QueryChangesWithSymbols() { // nolint: vet
	instance := "https://android-review.googlesource.com/"
	client, err := gerrit.NewClient(instance, nil)
	if err != nil {
		panic(err)
	}

	opt := &gerrit.QueryChangeOptions{}
	opt.Query = []string{
		"change:249244+status:merged",
	}
	opt.Limit = 2
	opt.AdditionalFields = []string{"LABELS"}
	changes, _, err := client.Changes.QueryChanges(opt)
	if err != nil {
		panic(err)
	}

	for _, change := range *changes {
		fmt.Printf("Project: %s -> %s -> %s%d\n", change.Project, change.Subject, instance, change.Number)
	}

	// Output:
	// Project: platform/art -> ART: Change return types of field access entrypoints -> https://android-review.googlesource.com/249244
}

func ExampleChangesService_PublishChangeEdit() {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "ok")
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		panic(err)
	}

	_, err = client.Changes.PublishChangeEdit("123", "NONE")
	if err != nil {
		panic(err)
	}
}
<commit_msg>adding tests<commit_after>package gerrit_test

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/andygrunwald/go-gerrit"
)

func ExampleChangesService_QueryChanges() {
	instance := "https://android-review.googlesource.com/"
	client, err := gerrit.NewClient(instance, nil)
	if err != nil {
		panic(err)
	}

	opt := &gerrit.QueryChangeOptions{}
	opt.Query = []string{
		"change:249244",
	}
	opt.Limit = 2
	opt.AdditionalFields = []string{"LABELS"}
	changes, _, err := client.Changes.QueryChanges(opt)
	if err != nil {
		panic(err)
	}

	for _, change := range *changes {
		fmt.Printf("Project: %s -> %s -> %s%d\n", change.Project, change.Subject, instance, change.Number)
	}

	// Output:
	// Project: platform/art -> ART: Change return types of field access entrypoints -> https://android-review.googlesource.com/249244
}

// Prior to fixing #18 this test would fail.
func ExampleChangesService_QueryChangesWithSymbols() { // nolint: vet
	instance := "https://android-review.googlesource.com/"
	client, err := gerrit.NewClient(instance, nil)
	if err != nil {
		panic(err)
	}

	opt := &gerrit.QueryChangeOptions{}
	opt.Query = []string{
		"change:249244+status:merged",
	}
	opt.Limit = 2
	opt.AdditionalFields = []string{"LABELS"}
	changes, _, err := client.Changes.QueryChanges(opt)
	if err != nil {
		panic(err)
	}

	for _, change := range *changes {
		fmt.Printf("Project: %s -> %s -> %s%d\n", change.Project, change.Subject, instance, change.Number)
	}

	// Output:
	// Project: platform/art -> ART: Change return types of field access entrypoints -> https://android-review.googlesource.com/249244
}

func ExampleChangesService_PublishChangeEdit() {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "ok")
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		panic(err)
	}

	_, err = client.Changes.PublishChangeEdit("123", "NONE")
	if err != nil {
		panic(err)
	}
}

func TestChangesService_SubmitChange(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/changes/123/submit" {
			t.Errorf("%s != /changes/123/submit", r.URL.Path)
		}
		fmt.Fprint(w, `{"id": "123"}`)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	info, _, err := client.Changes.SubmitChange("123", nil)
	if err != nil {
		t.Error(err)
	}
	if info.ID != "123" {
		t.Error("Invalid id")
	}
}

func TestChangesService_SubmitChange_Conflict(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusConflict)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	_, response, _ := client.Changes.SubmitChange("123", nil)
	if response.StatusCode != http.StatusConflict {
		t.Error()
	}
}

func TestChangesService_AbandonChange(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/changes/123/abandon" {
			t.Errorf("%s != /changes/123/abandon", r.URL.Path)
		}
		fmt.Fprint(w, `{"id": "123"}`)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	info, _, err := client.Changes.AbandonChange("123", nil)
	if err != nil {
		t.Error(err)
	}
	if info.ID != "123" {
		t.Error("Invalid id")
	}
}

func TestChangesService_AbandonChange_Conflict(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusConflict)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	_, response, _ := client.Changes.AbandonChange("123", nil)
	if response.StatusCode != http.StatusConflict {
		t.Error()
	}
}

func TestChangesService_RebaseChange(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/changes/123/rebase" {
			t.Errorf("%s != /changes/123/rebase", r.URL.Path)
		}
		fmt.Fprint(w, `{"id": "123"}`)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	info, _, err := client.Changes.RebaseChange("123", nil)
	if err != nil {
		t.Error(err)
	}
	if info.ID != "123" {
		t.Error("Invalid id")
	}
}

func TestChangesService_RebaseChange_Conflict(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusConflict)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	_, response, _ := client.Changes.RebaseChange("123", nil)
	if response.StatusCode != http.StatusConflict {
		t.Error()
	}
}

func TestChangesService_RestoreChange(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/changes/123/restore" {
			t.Errorf("%s != /changes/123/restore", r.URL.Path)
		}
		fmt.Fprint(w, `{"id": "123"}`)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	info, _, err := client.Changes.RestoreChange("123", nil)
	if err != nil {
		t.Error(err)
	}
	if info.ID != "123" {
		t.Error("Invalid id")
	}
}

func TestChangesService_RestoreChange_Conflict(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusConflict)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	_, response, _ := client.Changes.RestoreChange("123", nil)
	if response.StatusCode != http.StatusConflict {
		t.Error()
	}
}

func TestChangesService_RevertChange(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/changes/123/revert" {
			t.Errorf("%s != /changes/123/revert", r.URL.Path)
		}
		fmt.Fprint(w, `{"id": "123"}`)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	info, _, err := client.Changes.RevertChange("123", nil)
	if err != nil {
		t.Error(err)
	}
	if info.ID != "123" {
		t.Error("Invalid id")
	}
}

func TestChangesService_RevertChange_Conflict(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusConflict)
	}))
	defer ts.Close()

	client, err := gerrit.NewClient(ts.URL, nil)
	if err != nil {
		t.Error(err)
	}
	_, response, _ := client.Changes.RevertChange("123", nil)
	if response.StatusCode != http.StatusConflict {
		t.Error()
	}
}
<|endoftext|>


<commit_before>package charts

import (
	"github.com/go-echarts/go-echarts/v2/opts"
	"github.com/go-echarts/go-echarts/v2/render"
	"github.com/go-echarts/go-echarts/v2/types"
)

// Bar3D represents a 3D bar chart.
type Bar3D struct {
	Chart3D
}

// Type returns the chart type.
func (Bar3D) Type() string { return types.ChartBar3D }

// NewBar3D creates a new 3D bar chart.
func NewBar3D() *Bar3D {
	c := &Bar3D{}
	c.initBaseConfiguration()
	c.Renderer = render.NewChartRender(c, c.Validate)
	c.initChart3D()
	return c
}

// AddSeries adds the new series.
func (c *Bar3D) AddSeries(name string, data []opts.Chart3DData, options ...SeriesOpts) *Bar3D {
	c.addSeries(types.ChartScatter3D, name, data, options...)
	return c
}
<commit_msg>Bar3D struct should produce Bar3D charts (#170)<commit_after>package charts

import (
	"github.com/go-echarts/go-echarts/v2/opts"
	"github.com/go-echarts/go-echarts/v2/render"
	"github.com/go-echarts/go-echarts/v2/types"
)

// Bar3D represents a 3D bar chart.
type Bar3D struct {
	Chart3D
}

// Type returns the chart type.
func (Bar3D) Type() string { return types.ChartBar3D }

// NewBar3D creates a new 3D bar chart.
func NewBar3D() *Bar3D {
	c := &Bar3D{}
	c.initBaseConfiguration()
	c.Renderer = render.NewChartRender(c, c.Validate)
	c.initChart3D()
	return c
}

// AddSeries adds the new series.
func (c *Bar3D) AddSeries(name string, data []opts.Chart3DData, options ...SeriesOpts) *Bar3D {
	c.addSeries(types.ChartBar3D, name, data, options...)
	return c
}
<|endoftext|>


<commit_before>package main

import (
    "log"
    "flag"
    "net/http"
    "strings"
    "code.google.com/p/gorest"
    "nowac/kegg"
//    "time"
//    "math/rand"
    "strconv"
   // "github.com/fjukstad/gocache"
    "encoding/json"
    "io/ioutil"
    "bytes"
)

func main () {

    var ip = flag.String("ip", "localhost", "ip to run on")
    var port = flag.String("port", ":8080" ,"port to run on")

    flag.Parse()
    address := *ip+*port

    gorest.RegisterService(new(NOWACService))
    http.Handle("/", gorest.Handle())

    log.Println("Starting server on", address)
    err := http.ListenAndServe(address, nil)
    if err != nil{
        log.Panic("Could not start rest-service:", err)
    }

}

type NOWACService struct {
    gorest.RestService `root:"/"
                        consumes:"application/json"
                        produces:"application/json"`

    newPathwayGraph gorest.EndPoint `method:"GET"
                                    path:"/new/graph/pathway/{Pathways:string}"
                                    output:"string"`

    getInfo gorest.EndPoint `method:"GET"
                            path:"/info/{Items:string}/{InfoType:string}"
                            output:"string"`

    getGeneVis gorest.EndPoint `method:"GET"
                            path:"/vis/{Gene:string}"
                            output:"string"`

    datastore gorest.EndPoint `method:"GET"
                                path:"/datastore/{...:string}"
                                output:"string"`

    datastorePost gorest.EndPoint `method:"POST"
                                    path:"/datastore/{...:string}"
                                    postdata:"string"`

    pathways gorest.EndPoint    `method:"GET"
                                path:"/info/gene/{Gene:string}/pathways"
                                output:"string"`

    commonPathways gorest.EndPoint  `method:"GET"
                                    path:"/info/pathway/{Pathways:string}"
                                    output:"string"`

    pathwayGeneCount gorest.EndPoint    `method:"GET"
                                        path:"/info/gene/{Genes:string}/commonpathways"
                                        output:"string"`

    pathwayIDToName gorest.EndPoint `method:"GET"
                                    path:"/info/pathway/{Id:string}/name"
                                    output:"string"`

    commonGenes gorest.EndPoint `method:"GET"
                                path:"/info/pathway/{Pathways:string}/commongenes"
                                output:"int"`
/*
    geneColor gorest.EndPoint `method:"GET"
                                path:"/in*/
}

type PWMap struct {
    Map map[string] int
}

// Returns the common genes shared between multiple pathways
func (serv NOWACService) CommonGenes(Pathways string) int {

    pathwayList := strings.Split(Pathways, " ")
    log.Print(pathwayList)

    allGenes := make(map[string]int)

    // Iterate over all genes from different pathways and set their count
    for _, p := range pathwayList {
        pw := kegg.GetPathway(p)
        log.Println(pw.Genes)
        genes := pw.Genes

        for _, g := range genes {

            count := allGenes[g]
            if count != 0 {
                allGenes[g] = count + 1

            } else {
                allGenes[g] = 1
            }
        }

    }

    // From map of all genes get the ones with count larger than 1
    var commonGenes [] string
    for k, v := range allGenes {
        if v > 1 {
            commonGenes = append(commonGenes, k)
        }
    }

    return len(commonGenes)

}

func (serv NOWACService) PathwayIDToName (Id string) string {
    addAccessControlAllowOriginHeader(serv)
    return kegg.ReadablePathwayName(Id)
}

// Returns a list of pathways and the frequency of given genes. I.e.
// how many of the given genes are represented in different pathways
// Genes is a string that looks like "hsa:123+hsa:321+..."
func (serv NOWACService) PathwayGeneCount (Genes string) string {

	PathwayMap := make(map[string] int, 0)

    log.Print(Genes)
    geneList := strings.Split(Genes, " ")

    // for every gene get its list of pathways
    for _, g := range geneList {

        geneId := strings.Split(g, ":")[1]
        gene := kegg.GetGene(geneId)
        pws := kegg.Pathways(gene)

        // for each of its pathways, increment the counter for number
        // of genes represented in this pathway.
        for _, p := range pws.Pathways {
            if PathwayMap[p] != 0 {
                PathwayMap[p]++
            } else {
                PathwayMap[p] = 1
            }
        }

        log.Println("gene", g)
    }

    log.Println(PathwayMap)

    b, err := json.Marshal(PathwayMap)
    if err != nil {
        log.Panic("marshaling went bad: ",err)
    }

    return string(b)
}

func (serv NOWACService) CommonPathways(Pathways string) string {

    return "Not implemented yet"

}

// Will return a list of pathways for a given gene
func (serv NOWACService) Pathways (Gene string) string {

    geneIdString := strings.Split(Gene, " ")[0]
    geneId := strings.Split(geneIdString, ":")[1]
    gene := kegg.GetGene(geneId)
    pws := kegg.Pathways(gene)
    return kegg.PathwaysJSON(pws)

}

// Handles any requests to the Datastore. Will simply make the request to the
// datastore and return the result
func (serv NOWACService) Datastore(args ...string) string {

    addAccessControlAllowOriginHeader(serv)

    requestURL := serv.Context.Request().URL.Path

    // Where the datastore is running, this would be Stallo in later versions
    datastoreBaseURL := "http://localhost:8888/"

    URL := datastoreBaseURL + strings.Trim(requestURL, "/datastore")

    // NOTE: We are not caching results here, this could have been done, but
    // since we're doing work with a test dataset caching is not done.

    //NOTE: http.GET(URL) failed when the number of these calls were really
    //frequent. now trying gocache.
    resp, err := http.Get(URL)
    if err != nil {
        log.Print("request to datastore failed. ",err)
        serv.ResponseBuilder().SetResponseCode(404).Overide(true)
        return ":("
    }

    defer resp.Body.Close()

    // WARNING: int64 -> int conversion. may crash and burn if more than 2^32
    // - 1 bytes were read. Response from Datastore will typically be much
    // shorter than this, so its not an issue.
    respLength := int(resp.ContentLength)

    // Read the response from the body and return it as a string.
    response := make([]byte, respLength)
    _, err = resp.Body.Read(response)
    if err != nil {
        log.Print("reading response from datastore failed. ", err)
        serv.ResponseBuilder().SetResponseCode(404).Overide(true)
        return ":("
    }

    // Set response code to what was returned from Datastore.
    // Will ensure that if a 404 is returned by datastore this is also passed
    // along
    serv.ResponseBuilder().SetResponseCode(resp.StatusCode).Overide(false)

    return string(response)
}

func (serv NOWACService) DatastorePost( PostData string, varArgs ...string) {
    addAccessControlAllowOriginHeader(serv)

    requestURL := serv.Context.Request().URL.Path

    // Where the datastore is running, this would be Stallo in later versions
    datastoreBaseURL := "http://localhost:8888/"

    URL := datastoreBaseURL + strings.Replace(requestURL, "/datastore/","",-1)

    postContent := bytes.NewBufferString(PostData)

    // Perform the actual http post to the datastore
    // note that we set text as datatype. will fail miserably with anything else
    _, err := http.Post(URL, "text", postContent)
    if err != nil {
        log.Print("Post to datastore failed. ", err)
        serv.ResponseBuilder().SetResponseCode(500).Overide(true)
    }

}

func (serv NOWACService) GetGeneVis(Gene string) string {
    addAccessControlAllowOriginHeader(serv)

    log.Print("Returning the VIS code for gene: ", Gene)

    code := GeneExpression(Gene) // Barchar() // ParallelCoordinates(len(Gene))//GeneVisCode(Gene)
    return code
}

func GeneExpression(geneid string) string {

    id, err := strconv.Atoi(geneid)
    if err != nil {
        log.Panic("that was not a gene id: ", geneid, " ", err)
    }
    ds := GetGeneExpression(id)

    // Header, containing all other js
    header := `

    `

    return header+dataset+vis

}

// Returns all information possible for a gene. This includes stuff
// like id,name,definition etc etc.
func (serv NOWACService) GetInfo(Items string, InfoType string) string {

    //TODO: implement different info types such as name/sequence/ etc

    addAccessControlAllowOriginHeader(serv)

    if(strings.Contains(Items, "hsa")){
        // will get the first gene in the list Items. Could be more than one
        // but for starters we'll do with just one.

        geneIdString := strings.Split(Items, " ")[0]
        geneId := strings.Split(geneIdString, ":")[1]

        gene := kegg.GetGene(geneId)

        //gene.Pathways = kegg.ReadablePathwayNames(gene.Pathways)

        return kegg.GeneJSON(gene)
    }

    return Items;

}

func (serv NOWACService) NewPathwayGraph(Pathways string) string {
    addAccessControlAllowOriginHeader(serv)

    pws := parsePathwayInput(Pathways);
    handlerAddress := kegg.PathwayGraphFrom(pws[0])

    return handlerAddress+"/"+pws[0]

}

func addAccessControlAllowOriginHeader (serv NOWACService) {
    // Allowing access control stuff
    rb := serv.ResponseBuilder()
    rb.AddHeader("Access-Control-Allow-Origin","*")
}

func parsePathwayInput(input string) ([] string) {
        // Remove any unwanted characters
	a := strings.Replace(input, "%3A", ":", -1)
	a = strings.Replace(a, "&", "", -1)
	a = strings.Replace(a, "=", "", -1)

	// Split into separate hsa:... strings
	b := strings.Split(a, "pathwaySelect")

	// Clear out first empty item
	b = b[1:len(b)]

    return b

}

func GetGeneExpression(id int) string {

    datastore := "http://localhost:8888"

    query := "/gene/"+strconv.Itoa(id)
    url := datastore+query
    response, err := http.Get(url)

    if err != nil {
        log.Panic("could not download expression ", err)
    }

    defer response.Body.Close()

	exprs, err := ioutil.ReadAll(response.Body)
    if err != nil {
        log.Panic("Could not read expression ", err)
    }

    log.Print(string(exprs))

    return string(exprs)

}

<commit_msg>Removing some prints etc<commit_after>package main

import (
    "log"
    "flag"
    "net/http"
    "strings"
    "code.google.com/p/gorest"
    "nowac/kegg"
//    "time"
//    "math/rand"
    "strconv"
   // "github.com/fjukstad/gocache"
    "encoding/json"
    "io/ioutil"
    "bytes"
)

func main () {

    var ip = flag.String("ip", "localhost", "ip to run on")
    var port = flag.String("port", ":8080" ,"port to run on")

    flag.Parse()
    address := *ip+*port

    gorest.RegisterService(new(NOWACService))
    http.Handle("/", gorest.Handle())

    log.Println("Starting server on", address)
    err := http.ListenAndServe(address, nil)
    if err != nil{
        log.Panic("Could not start rest-service:", err)
    }

}

type NOWACService struct {
    gorest.RestService `root:"/"
                        consumes:"application/json"
                        produces:"application/json"`

    newPathwayGraph gorest.EndPoint `method:"GET"
                                    path:"/new/graph/pathway/{Pathways:string}"
                                    output:"string"`

    getInfo gorest.EndPoint `method:"GET"
                            path:"/info/{Items:string}/{InfoType:string}"
                            output:"string"`

    getGeneVis gorest.EndPoint `method:"GET"
                            path:"/vis/{Gene:string}"
                            output:"string"`

    datastore gorest.EndPoint `method:"GET"
                                path:"/datastore/{...:string}"
                                output:"string"`

    datastorePost gorest.EndPoint `method:"POST"
                                    path:"/datastore/{...:string}"
                                    postdata:"string"`

    pathways gorest.EndPoint    `method:"GET"
                                path:"/info/gene/{Gene:string}/pathways"
                                output:"string"`

    commonPathways gorest.EndPoint  `method:"GET"
                                    path:"/info/pathway/{Pathways:string}"
                                    output:"string"`

    pathwayGeneCount gorest.EndPoint    `method:"GET"
                                        path:"/info/gene/{Genes:string}/commonpathways"
                                        output:"string"`

    pathwayIDToName gorest.EndPoint `method:"GET"
                                    path:"/info/pathway/{Id:string}/name"
                                    output:"string"`

    commonGenes gorest.EndPoint `method:"GET"
                                path:"/info/pathway/{Pathways:string}/commongenes"
                                output:"int"`
/*
    geneColor gorest.EndPoint `method:"GET"
                                path:"/in*/
}

type PWMap struct {
    Map map[string] int
}

// Returns the number of common genes shared between multiple pathways
func (serv NOWACService) CommonGenes(Pathways string) int {
    addAccessControlAllowOriginHeader(serv)

    pathwayList := strings.Split(Pathways, " ")

    allGenes := make(map[string]int)

    // Iterate over all genes from different pathways and set their count
    for _, p := range pathwayList {
        pw := kegg.GetPathway(p)
        genes := pw.Genes

        for _, g := range genes {

            count := allGenes[g]
            if count != 0 {
                allGenes[g] = count + 1

            } else {
                allGenes[g] = 1
            }
        }

    }

    // From map of all genes get the ones with count larger than 1
    var commonGenes [] string
    for k, v := range allGenes {
        if v > 1 {
            commonGenes = append(commonGenes, k)
        }
    }

    return len(commonGenes)

}

func (serv NOWACService) PathwayIDToName (Id string) string {
    addAccessControlAllowOriginHeader(serv)
    return kegg.ReadablePathwayName(Id)
}

// Returns a list of pathways and the frequency of given genes. I.e.
// how many of the given genes are represented in different pathways
// Genes is a string that looks like "hsa:123+hsa:321+..."
func (serv NOWACService) PathwayGeneCount (Genes string) string {

	PathwayMap := make(map[string] int, 0)

    geneList := strings.Split(Genes, " ")

    // for every gene get its list of pathways
    for _, g := range geneList {

        geneId := strings.Split(g, ":")[1]
        gene := kegg.GetGene(geneId)
        pws := kegg.Pathways(gene)

        // for each of its pathways, increment the counter for number
        // of genes represented in this pathway.
        for _, p := range pws.Pathways {
            if PathwayMap[p] != 0 {
                PathwayMap[p]++
            } else {
                PathwayMap[p] = 1
            }
        }

    }

    b, err := json.Marshal(PathwayMap)
    if err != nil {
        log.Panic("marshaling went bad: ",err)
    }

    return string(b)
}

func (serv NOWACService) CommonPathways(Pathways string) string {

    return "Not implemented yet"

}

// Will return a list of pathways for a given gene
func (serv NOWACService) Pathways (Gene string) string {

    geneIdString := strings.Split(Gene, " ")[0]
    geneId := strings.Split(geneIdString, ":")[1]
    gene := kegg.GetGene(geneId)
    pws := kegg.Pathways(gene)
    return kegg.PathwaysJSON(pws)

}

// Handles any requests to the Datastore. Will simply make the request to the
// datastore and return the result
func (serv NOWACService) Datastore(args ...string) string {

    addAccessControlAllowOriginHeader(serv)

    requestURL := serv.Context.Request().URL.Path

    // Where the datastore is running, this would be Stallo in later versions
    datastoreBaseURL := "http://localhost:8888/"

    URL := datastoreBaseURL + strings.Trim(requestURL, "/datastore")

    // NOTE: We are not caching results here, this could have been done, but
    // since we're doing work with a test dataset caching is not done.

    //NOTE: http.GET(URL) failed when the number of these calls were really
    //frequent. now trying gocache.
    resp, err := http.Get(URL)
    if err != nil {
        log.Print("request to datastore failed. ",err)
        serv.ResponseBuilder().SetResponseCode(404).Overide(true)
        return ":("
    }

    defer resp.Body.Close()

    // WARNING: int64 -> int conversion. may crash and burn if more than 2^32
    // - 1 bytes were read. Response from Datastore will typically be much
    // shorter than this, so its not an issue.
    respLength := int(resp.ContentLength)

    // Read the response from the body and return it as a string.
    response := make([]byte, respLength)
    _, err = resp.Body.Read(response)
    if err != nil {
        log.Print("reading response from datastore failed. ", err)
        serv.ResponseBuilder().SetResponseCode(404).Overide(true)
        return ":("
    }

    // Set response code to what was returned from Datastore.
    // Will ensure that if a 404 is returned by datastore this is also passed
    // along
    serv.ResponseBuilder().SetResponseCode(resp.StatusCode).Overide(false)

    return string(response)
}

func (serv NOWACService) DatastorePost( PostData string, varArgs ...string) {
    addAccessControlAllowOriginHeader(serv)

    requestURL := serv.Context.Request().URL.Path

    // Where the datastore is running, this would be Stallo in later versions
    datastoreBaseURL := "http://localhost:8888/"

    URL := datastoreBaseURL + strings.Replace(requestURL, "/datastore/","",-1)

    postContent := bytes.NewBufferString(PostData)

    // Perform the actual http post to the datastore
    // note that we set text as datatype. will fail miserably with anything else
    _, err := http.Post(URL, "text", postContent)
    if err != nil {
        log.Print("Post to datastore failed. ", err)
        serv.ResponseBuilder().SetResponseCode(500).Overide(true)
    }

}

func (serv NOWACService) GetGeneVis(Gene string) string {
    addAccessControlAllowOriginHeader(serv)

    log.Print("Returning the VIS code for gene: ", Gene)

    code := GeneExpression(Gene) // Barchar() // ParallelCoordinates(len(Gene))//GeneVisCode(Gene)
    return code
}

func GeneExpression(geneid string) string {

    id, err := strconv.Atoi(geneid)
    if err != nil {
        log.Panic("that was not a gene id: ", geneid, " ", err)
    }
    ds := GetGeneExpression(id)

    // Header, containing all other js
    header := `

    `

    return header+dataset+vis

}

// Returns all information possible for a gene. This includes stuff
// like id,name,definition etc etc.
func (serv NOWACService) GetInfo(Items string, InfoType string) string {

    //TODO: implement different info types such as name/sequence/ etc

    addAccessControlAllowOriginHeader(serv)

    if(strings.Contains(Items, "hsa")){
        // will get the first gene in the list Items. Could be more than one
        // but for starters we'll do with just one.

        geneIdString := strings.Split(Items, " ")[0]
        geneId := strings.Split(geneIdString, ":")[1]

        gene := kegg.GetGene(geneId)

        //gene.Pathways = kegg.ReadablePathwayNames(gene.Pathways)

        return kegg.GeneJSON(gene)
    }

    return Items;

}

func (serv NOWACService) NewPathwayGraph(Pathways string) string {
    addAccessControlAllowOriginHeader(serv)

    pws := parsePathwayInput(Pathways);
    handlerAddress := kegg.PathwayGraphFrom(pws[0])

    return handlerAddress+"/"+pws[0]

}

func addAccessControlAllowOriginHeader (serv NOWACService) {
    // Allowing access control stuff
    rb := serv.ResponseBuilder()
    rb.AddHeader("Access-Control-Allow-Origin","*")
}

func parsePathwayInput(input string) ([] string) {
        // Remove any unwanted characters
	a := strings.Replace(input, "%3A", ":", -1)
	a = strings.Replace(a, "&", "", -1)
	a = strings.Replace(a, "=", "", -1)

	// Split into separate hsa:... strings
	b := strings.Split(a, "pathwaySelect")

	// Clear out first empty item
	b = b[1:len(b)]

    return b

}

func GetGeneExpression(id int) string {

    datastore := "http://localhost:8888"

    query := "/gene/"+strconv.Itoa(id)
    url := datastore+query
    response, err := http.Get(url)

    if err != nil {
        log.Panic("could not download expression ", err)
    }

    defer response.Body.Close()

	exprs, err := ioutil.ReadAll(response.Body)
    if err != nil {
        log.Panic("Could not read expression ", err)
    }

    return string(exprs)

}

<|endoftext|>


<commit_before>// Copyright 2015 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 chunkaligned

import (
	"errors"
	"io"
	"math"
	"sort"
	"sync"
)

// An io.SectionReader implements SizeReaderAt.
type SizeReaderAt interface {
	Size() int64
	io.ReaderAt
}

type offsetAndSource struct {
	off int64
	SizeReaderAt
}

type multi struct {
	parts []offsetAndSource
	size  int64
}

func (m *multi) Size() int64 { return m.size }

func (m *multi) ReadAt(p []byte, off int64) (n int, err error) {
	wantN := len(p)

	// Skip past the requested offset.
	skipParts := sort.Search(len(m.parts), func(i int) bool {
		// This function returns whether parts[i] will
		// contribute any bytes to our output.
		part := m.parts[i]
		return part.off+part.Size() > off
	})
	parts := m.parts[skipParts:]

	// How far to skip in the first part.
	needSkip := off
	if len(parts) > 0 {
		needSkip -= parts[0].off
	}

	for len(parts) > 0 && len(p) > 0 {
		readP := p
		partSize := parts[0].Size()
		if int64(len(readP)) > partSize-needSkip {
			readP = readP[:partSize-needSkip]
		}
		pn, err0 := parts[0].ReadAt(readP, needSkip)
		if err0 != nil {
			return n, err0
		}
		n += pn
		p = p[pn:]
		if int64(pn)+needSkip == partSize {
			parts = parts[1:]
		}
		needSkip = 0
	}

	if n != wantN {
		err = io.ErrUnexpectedEOF
	}
	return
}

const (
	chunkSizeLimit = 4 * 1024 * 1024
)

// fixed-length []byte pool, they will not grow as needed
var fixedBytePool = sync.Pool{
	New: func() interface{} { return make([]byte, chunkSizeLimit) },
}

type chunkReaderAt struct {
	size  int
	base  int64
	cache []byte
	r     SizeReaderAt
}

func (c *chunkReaderAt) Size() int64 {
	return int64(c.size)
}

func (c *chunkReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
	wantN := len(p)

	if len(c.cache) == 0 {
		c.base = off
		c.cache = fixedBytePool.Get().([]byte)

		// the offset is aligned
		readN, err := c.r.ReadAt(c.cache[:c.size], off)
		if err != nil {
			if err == io.EOF {
				if readN < wantN {
					fixedBytePool.Put(c.cache)
					c.cache = nil

					// We always know when EOF is coming.
					// If the caller asked for a chunk, there should be a chunk.
					return -1, io.ErrUnexpectedEOF
				}
			} else {
				fixedBytePool.Put(c.cache)
				c.cache = nil
				return -1, err
			}
		}
	}

	needSkip := int(off - c.base)
	n = copy(p, c.cache[needSkip:c.size])
	if (needSkip + n) == c.size {
		fixedBytePool.Put(c.cache)
		c.cache = nil
	}

	if n != wantN {
		err = io.ErrUnexpectedEOF
	}

	return
}

// NewChunkAlignedReaderAt returns a ReaderAt wrapper that is backed
// by a ReaderAt r of size totalSize where the wrapper guarantees that
// all ReadAt calls are aligned to chunkSize boundaries and of size
// chunkSize (except for the final chunk, which may be shorter).
//
// A chunk-aligned reader is good for caching, letting upper layers have
// any access pattern, but guarantees that the wrapped ReaderAt sees
// only nicely-cacheable access patterns & sizes.
func NewChunkAlignedReaderAt(r SizeReaderAt, chunkSize int) (SizeReaderAt, error) {
	if chunkSize > chunkSizeLimit {
		// NOTE(wenjianhn): Do you really need a chunk that is such large?
		return &multi{}, errors.New("chunkaligned: chunk Size Limit Exceeded")
	}

	totalSize := r.Size()

	partN := int(math.Ceil(float64(totalSize) / float64(chunkSize)))
	m := &multi{
		parts: make([]offsetAndSource, partN),
		size:  totalSize,
	}

	left := totalSize
	var offset int64
	for i, _ := range m.parts {
		partSize := chunkSize
		if left < int64(chunkSize) {
			// the final chunk is shorter
			partSize = int(left)
		}
		f := &chunkReaderAt{
			size:  partSize,
			cache: nil,
			r:     r,
		}
		m.parts[i] = offsetAndSource{offset,
			io.NewSectionReader(f, offset, f.Size())}
		offset += f.Size()
		left -= f.Size()
	}
	return m, nil
}
<commit_msg>Use Size() to access multi.size that is not exported<commit_after>// Copyright 2015 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 chunkaligned

import (
	"errors"
	"io"
	"math"
	"sort"
	"sync"
)

// An io.SectionReader implements SizeReaderAt.
type SizeReaderAt interface {
	Size() int64
	io.ReaderAt
}

type offsetAndSource struct {
	off int64
	SizeReaderAt
}

type multi struct {
	parts []offsetAndSource
	size  int64
}

func (m *multi) Size() int64 { return m.size }

func (m *multi) ReadAt(p []byte, off int64) (n int, err error) {
	wantN := len(p)

	// Skip past the requested offset.
	skipParts := sort.Search(len(m.parts), func(i int) bool {
		// This function returns whether parts[i] will
		// contribute any bytes to our output.
		part := m.parts[i]
		return part.off+part.Size() > off
	})
	parts := m.parts[skipParts:]

	// How far to skip in the first part.
	needSkip := off
	if len(parts) > 0 {
		needSkip -= parts[0].off
	}

	for len(parts) > 0 && len(p) > 0 {
		readP := p
		partSize := parts[0].Size()
		if int64(len(readP)) > partSize-needSkip {
			readP = readP[:partSize-needSkip]
		}
		pn, err0 := parts[0].ReadAt(readP, needSkip)
		if err0 != nil {
			return n, err0
		}
		n += pn
		p = p[pn:]
		if int64(pn)+needSkip == partSize {
			parts = parts[1:]
		}
		needSkip = 0
	}

	if n != wantN {
		err = io.ErrUnexpectedEOF
	}
	return
}

const (
	chunkSizeLimit = 4 * 1024 * 1024
)

// fixed-length []byte pool, they will not grow as needed
var fixedBytePool = sync.Pool{
	New: func() interface{} { return make([]byte, chunkSizeLimit) },
}

type chunkReaderAt struct {
	size  int
	base  int64
	cache []byte
	r     SizeReaderAt
}

func (c *chunkReaderAt) Size() int64 {
	return int64(c.size)
}

func (c *chunkReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
	wantN := len(p)

	if len(c.cache) == 0 {
		c.base = off
		c.cache = fixedBytePool.Get().([]byte)

		// the offset is aligned
		readN, err := c.r.ReadAt(c.cache[:c.size], off)
		if err != nil {
			if err == io.EOF {
				if readN < wantN {
					fixedBytePool.Put(c.cache)
					c.cache = nil

					// We always know when EOF is coming.
					// If the caller asked for a chunk, there should be a chunk.
					return -1, io.ErrUnexpectedEOF
				}
			} else {
				fixedBytePool.Put(c.cache)
				c.cache = nil
				return -1, err
			}
		}
	}

	needSkip := int(off - c.base)
	n = copy(p, c.cache[needSkip:c.size])
	if (needSkip + n) == c.size {
		fixedBytePool.Put(c.cache)
		c.cache = nil
	}

	if n != wantN {
		err = io.ErrUnexpectedEOF
	}

	return
}

// NewChunkAlignedReaderAt returns a ReaderAt wrapper that is backed
// by a ReaderAt r of size totalSize where the wrapper guarantees that
// all ReadAt calls are aligned to chunkSize boundaries and of size
// chunkSize (except for the final chunk, which may be shorter).
//
// A chunk-aligned reader is good for caching, letting upper layers have
// any access pattern, but guarantees that the wrapped ReaderAt sees
// only nicely-cacheable access patterns & sizes.
func NewChunkAlignedReaderAt(r SizeReaderAt, chunkSize int) (SizeReaderAt, error) {
	if chunkSize > chunkSizeLimit {
		// NOTE(wenjianhn): Do you really need a chunk that is such large?
		return &multi{}, errors.New("chunkaligned: chunk Size Limit Exceeded")
	}

	totalSize := r.Size()

	partN := int(math.Ceil(float64(totalSize) / float64(chunkSize)))
	m := &multi{
		parts: make([]offsetAndSource, partN),
		size:  totalSize,
	}

	left := m.Size()
	var offset int64
	for i, _ := range m.parts {
		partSize := chunkSize
		if left < int64(chunkSize) {
			// the final chunk is shorter
			partSize = int(left)
		}
		f := &chunkReaderAt{
			size:  partSize,
			cache: nil,
			r:     r,
		}
		m.parts[i] = offsetAndSource{offset,
			io.NewSectionReader(f, offset, f.Size())}
		offset += f.Size()
		left -= f.Size()
	}
	return m, nil
}
<|endoftext|>


<commit_before>package signals

import (
	"encoding/binary"
	"fmt"
	"io"
)

// encode a signal as an unsigned PCM data in a Riff wave container (wav file format)
func Encode(w io.Writer, s Signal, length interval, sampleRate uint32, bytes uint8) {
	binaryWrite := func(w io.Writer, d interface{}) {
		if err := binary.Write(w, binary.LittleEndian, d); err != nil {
			panic(err)
		}
	}
	samplePeriod := MultiplyInterval(1/float32(sampleRate), UnitTime)
	samples := uint32(length/samplePeriod) + 1
	fmt.Fprint(w, "RIFF")
	binaryWrite(w, uint32(samples+36))
	fmt.Fprint(w, "WAVE")
	fmt.Fprint(w, "fmt ")
	binaryWrite(w, uint32(16))
	binaryWrite(w, uint16(1))
	binaryWrite(w, uint16(1))
	binaryWrite(w, sampleRate)
	binaryWrite(w, sampleRate)
	binaryWrite(w, uint16(bytes))
	binaryWrite(w, uint16(8*bytes))
	fmt.Fprint(w, "data")
	binaryWrite(w, uint32(samples))
	var i uint32
	var shift uint8 = LevelBits - 8*bytes
	var offset level = 2 << (bytes*8 - 2)
	for ; i < samples; i++ {
		w.Write([]byte{byte(s.Level(interval(i)*samplePeriod)>>shift + offset)})
	}
}

/* PCM all possible formats

openal takes s16 or u8

 DE alaw            PCM A-law
 DE f32be           PCM 32-bit floating-point big-endian
 DE f32le           PCM 32-bit floating-point little-endian
 DE f64be           PCM 64-bit floating-point big-endian
 DE f64le           PCM 64-bit floating-point little-endian
 DE mulaw           PCM mu-law
 DE s16be           PCM signed 16-bit big-endian
 DE s16le           PCM signed 16-bit little-endian
 DE s24be           PCM signed 24-bit big-endian
 DE s24le           PCM signed 24-bit little-endian
 DE s32be           PCM signed 32-bit big-endian
 DE s32le           PCM signed 32-bit little-endian
 DE s8              PCM signed 8-bit
 DE u16be           PCM unsigned 16-bit big-endian
 DE u16le           PCM unsigned 16-bit little-endian
 DE u24be           PCM unsigned 24-bit big-endian
 DE u24le           PCM unsigned 24-bit little-endian
 DE u32be           PCM unsigned 32-bit big-endian
 DE u32le           PCM unsigned 32-bit little-endian
 DE u8              PCM unsigned 8-bit

*/

<commit_msg>encode signed<commit_after>package signals

import (
	"encoding/binary"
	"bytes"
	"fmt"
	"io"
)

// encode a signal as an unsigned PCM data in a Riff wave container (wav file format)
func Encode(w io.Writer, s Signal, length interval, sampleRate uint32, sampleBytes uint8) {
	binaryWrite := func(w io.Writer, d interface{}) {
		if err := binary.Write(w, binary.LittleEndian, d); err != nil {
			panic(err)
		}
	}
	samplePeriod := MultiplyInterval(1/float32(sampleRate), UnitTime)
	samples := uint32(length/samplePeriod) + 1
	fmt.Fprint(w, "RIFF")
	binaryWrite(w, samples*uint32(sampleBytes)+36)
	fmt.Fprint(w, "WAVE")
	fmt.Fprint(w, "fmt ")
	binaryWrite(w, uint32(16))
	binaryWrite(w, uint16(1))
	binaryWrite(w, uint16(1))
	binaryWrite(w, sampleRate)
	binaryWrite(w, sampleRate*uint32(sampleBytes))
	binaryWrite(w, uint16(sampleBytes))
	binaryWrite(w, uint16(8*sampleBytes))
	fmt.Fprint(w, "data")
	binaryWrite(w, samples*uint32(sampleBytes))
	var shift uint8 = LevelBits - 8*sampleBytes
	switch sampleBytes{
	case 1:
		var i uint32
		for ; i < samples; i++ {
			l:=s.Level(interval(i)*samplePeriod)
			binaryWrite(w,uint8(l>>shift+128))
		}
	case 2:
		var i uint32
		for ; i < samples; i++ {
			l:=s.Level(interval(i)*samplePeriod)
			binaryWrite(w,int16(l>>shift))
		}
	case 3:
		var i uint32
		buf:= bytes.NewBuffer(make([]bytes,4))
		for ; i < samples; i++ {
			l:=s.Level(interval(i)*samplePeriod)
			binaryWrite(buf,int32(l>>shift))
		}
	case 4:
		var i uint32
		for ; i < samples; i++ {
			l:=s.Level(interval(i)*samplePeriod)
			binaryWrite(w,int32(l>>shift))
		}
	}
}

/* PCM all possible formats

openal takes s16 or u8

 DE alaw            PCM A-law
 DE f32be           PCM 32-bit floating-point big-endian
 DE f32le           PCM 32-bit floating-point little-endian
 DE f64be           PCM 64-bit floating-point big-endian
 DE f64le           PCM 64-bit floating-point little-endian
 DE mulaw           PCM mu-law
 DE s16be           PCM signed 16-bit big-endian
 DE s16le           PCM signed 16-bit little-endian
 DE s24be           PCM signed 24-bit big-endian
 DE s24le           PCM signed 24-bit little-endian
 DE s32be           PCM signed 32-bit big-endian
 DE s32le           PCM signed 32-bit little-endian
 DE s8              PCM signed 8-bit
 DE u16be           PCM unsigned 16-bit big-endian
 DE u16le           PCM unsigned 16-bit little-endian
 DE u24be           PCM unsigned 24-bit big-endian
 DE u24le           PCM unsigned 24-bit little-endian
 DE u32be           PCM unsigned 32-bit big-endian
 DE u32le           PCM unsigned 32-bit little-endian
 DE u8              PCM unsigned 8-bit

*/

<|endoftext|>