<commit_before>// Package alidns implements a DNS provider for solving the DNS-01 challenge using Alibaba Cloud DNS.
package alidns

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
	"github.com/xenolf/lego/challenge/dns01"
	"github.com/xenolf/lego/platform/config/env"
)

const defaultRegionID = "cn-hangzhou"

// Config is used to configure the creation of the DNSProvider
type Config struct {
	APIKey             string
	SecretKey          string
	RegionID           string
	PropagationTimeout time.Duration
	PollingInterval    time.Duration
	TTL                int
	HTTPTimeout        time.Duration
}

// NewDefaultConfig returns a default configuration for the DNSProvider
func NewDefaultConfig() *Config {
	return &Config{
		TTL:                env.GetOrDefaultInt("ALICLOUD_TTL", 600),
		PropagationTimeout: env.GetOrDefaultSecond("ALICLOUD_PROPAGATION_TIMEOUT", dns01.DefaultPropagationTimeout),
		PollingInterval:    env.GetOrDefaultSecond("ALICLOUD_POLLING_INTERVAL", dns01.DefaultPollingInterval),
		HTTPTimeout:        env.GetOrDefaultSecond("ALICLOUD_HTTP_TIMEOUT", 10*time.Second),
	}
}

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	config *Config
	client *alidns.Client
}

// NewDNSProvider returns a DNSProvider instance configured for Alibaba Cloud DNS.
// Credentials must be passed in the environment variables: ALICLOUD_ACCESS_KEY and ALICLOUD_SECRET_KEY.
func NewDNSProvider() (*DNSProvider, error) {
	values, err := env.Get("ALICLOUD_ACCESS_KEY", "ALICLOUD_SECRET_KEY")
	if err != nil {
		return nil, fmt.Errorf("alicloud: %v", err)
	}

	config := NewDefaultConfig()
	config.APIKey = values["ALICLOUD_ACCESS_KEY"]
	config.SecretKey = values["ALICLOUD_SECRET_KEY"]
	config.RegionID = env.GetOrFile("ALICLOUD_REGION_ID")

	return NewDNSProviderConfig(config)
}

// NewDNSProviderConfig return a DNSProvider instance configured for alidns.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
	if config == nil {
		return nil, errors.New("alicloud: the configuration of the DNS provider is nil")
	}

	if config.APIKey == "" || config.SecretKey == "" {
		return nil, fmt.Errorf("alicloud: credentials missing")
	}

	if len(config.RegionID) == 0 {
		config.RegionID = defaultRegionID
	}

	conf := sdk.NewConfig().WithTimeout(config.HTTPTimeout)
	credential := credentials.NewAccessKeyCredential(config.APIKey, config.SecretKey)

	client, err := alidns.NewClientWithOptions(config.RegionID, conf, credential)
	if err != nil {
		return nil, fmt.Errorf("alicloud: credentials failed: %v", err)
	}

	return &DNSProvider{config: config, client: client}, nil
}

// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return d.config.PropagationTimeout, d.config.PollingInterval
}

// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value := dns01.GetRecord(domain, keyAuth)

	_, zoneName, err := d.getHostedZone(domain)
	if err != nil {
		return fmt.Errorf("alicloud: %v", err)
	}

	recordAttributes := d.newTxtRecord(zoneName, fqdn, value)

	_, err = d.client.AddDomainRecord(recordAttributes)
	if err != nil {
		return fmt.Errorf("alicloud: API call failed: %v", err)
	}
	return nil
}

// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _ := dns01.GetRecord(domain, keyAuth)

	records, err := d.findTxtRecords(domain, fqdn)
	if err != nil {
		return fmt.Errorf("alicloud: %v", err)
	}

	_, _, err = d.getHostedZone(domain)
	if err != nil {
		return fmt.Errorf("alicloud: %v", err)
	}

	for _, rec := range records {
		request := alidns.CreateDeleteDomainRecordRequest()
		request.RecordId = rec.RecordId
		_, err = d.client.DeleteDomainRecord(request)
		if err != nil {
			return fmt.Errorf("alicloud: %v", err)
		}
	}
	return nil
}

func (d *DNSProvider) getHostedZone(domain string) (string, string, error) {
	request := alidns.CreateDescribeDomainsRequest()

	var domains []alidns.Domain
	startPage := 1

	for {
		request.PageNumber = requests.NewInteger(startPage)

		response, err := d.client.DescribeDomains(request)
		if err != nil {
			return "", "", fmt.Errorf("API call failed: %v", err)
		}

		domains = append(domains, response.Domains.Domain...)

		if response.PageNumber >= response.PageSize {
			break
		}

		startPage++
	}

	authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
	if err != nil {
		return "", "", err
	}

	var hostedZone alidns.Domain
	for _, zone := range domains {
		if zone.DomainName == dns01.UnFqdn(authZone) {
			hostedZone = zone
		}
	}

	if hostedZone.DomainId == "" {
		return "", "", fmt.Errorf("zone %s not found in AliDNS for domain %s", authZone, domain)
	}
	return fmt.Sprintf("%v", hostedZone.DomainId), hostedZone.DomainName, nil
}

func (d *DNSProvider) newTxtRecord(zone, fqdn, value string) *alidns.AddDomainRecordRequest {
	request := alidns.CreateAddDomainRecordRequest()
	request.Type = "TXT"
	request.DomainName = zone
	request.RR = d.extractRecordName(fqdn, zone)
	request.Value = value
	request.TTL = requests.NewInteger(d.config.TTL)
	return request
}

func (d *DNSProvider) findTxtRecords(domain, fqdn string) ([]alidns.Record, error) {
	_, zoneName, err := d.getHostedZone(domain)
	if err != nil {
		return nil, err
	}

	request := alidns.CreateDescribeDomainRecordsRequest()
	request.DomainName = zoneName
	request.PageSize = requests.NewInteger(500)

	var records []alidns.Record

	result, err := d.client.DescribeDomainRecords(request)
	if err != nil {
		return records, fmt.Errorf("API call has failed: %v", err)
	}

	recordName := d.extractRecordName(fqdn, zoneName)
	for _, record := range result.DomainRecords.Record {
		if record.RR == recordName {
			records = append(records, record)
		}
	}
	return records, nil
}

func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
	name := dns01.UnFqdn(fqdn)
	if idx := strings.Index(name, "."+domain); idx != -1 {
		return name[:idx]
	}
	return name
}
<commit_msg>alicloud: fix pagination. (#767)<commit_after>// Package alidns implements a DNS provider for solving the DNS-01 challenge using Alibaba Cloud DNS.
package alidns

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
	"github.com/xenolf/lego/challenge/dns01"
	"github.com/xenolf/lego/platform/config/env"
)

const defaultRegionID = "cn-hangzhou"

// Config is used to configure the creation of the DNSProvider
type Config struct {
	APIKey             string
	SecretKey          string
	RegionID           string
	PropagationTimeout time.Duration
	PollingInterval    time.Duration
	TTL                int
	HTTPTimeout        time.Duration
}

// NewDefaultConfig returns a default configuration for the DNSProvider
func NewDefaultConfig() *Config {
	return &Config{
		TTL:                env.GetOrDefaultInt("ALICLOUD_TTL", 600),
		PropagationTimeout: env.GetOrDefaultSecond("ALICLOUD_PROPAGATION_TIMEOUT", dns01.DefaultPropagationTimeout),
		PollingInterval:    env.GetOrDefaultSecond("ALICLOUD_POLLING_INTERVAL", dns01.DefaultPollingInterval),
		HTTPTimeout:        env.GetOrDefaultSecond("ALICLOUD_HTTP_TIMEOUT", 10*time.Second),
	}
}

// DNSProvider is an implementation of the acme.ChallengeProvider interface
type DNSProvider struct {
	config *Config
	client *alidns.Client
}

// NewDNSProvider returns a DNSProvider instance configured for Alibaba Cloud DNS.
// Credentials must be passed in the environment variables: ALICLOUD_ACCESS_KEY and ALICLOUD_SECRET_KEY.
func NewDNSProvider() (*DNSProvider, error) {
	values, err := env.Get("ALICLOUD_ACCESS_KEY", "ALICLOUD_SECRET_KEY")
	if err != nil {
		return nil, fmt.Errorf("alicloud: %v", err)
	}

	config := NewDefaultConfig()
	config.APIKey = values["ALICLOUD_ACCESS_KEY"]
	config.SecretKey = values["ALICLOUD_SECRET_KEY"]
	config.RegionID = env.GetOrFile("ALICLOUD_REGION_ID")

	return NewDNSProviderConfig(config)
}

// NewDNSProviderConfig return a DNSProvider instance configured for alidns.
func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
	if config == nil {
		return nil, errors.New("alicloud: the configuration of the DNS provider is nil")
	}

	if config.APIKey == "" || config.SecretKey == "" {
		return nil, fmt.Errorf("alicloud: credentials missing")
	}

	if len(config.RegionID) == 0 {
		config.RegionID = defaultRegionID
	}

	conf := sdk.NewConfig().WithTimeout(config.HTTPTimeout)
	credential := credentials.NewAccessKeyCredential(config.APIKey, config.SecretKey)

	client, err := alidns.NewClientWithOptions(config.RegionID, conf, credential)
	if err != nil {
		return nil, fmt.Errorf("alicloud: credentials failed: %v", err)
	}

	return &DNSProvider{config: config, client: client}, nil
}

// Timeout returns the timeout and interval to use when checking for DNS propagation.
// Adjusting here to cope with spikes in propagation times.
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
	return d.config.PropagationTimeout, d.config.PollingInterval
}

// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
	fqdn, value := dns01.GetRecord(domain, keyAuth)

	_, zoneName, err := d.getHostedZone(domain)
	if err != nil {
		return fmt.Errorf("alicloud: %v", err)
	}

	recordAttributes := d.newTxtRecord(zoneName, fqdn, value)

	_, err = d.client.AddDomainRecord(recordAttributes)
	if err != nil {
		return fmt.Errorf("alicloud: API call failed: %v", err)
	}
	return nil
}

// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _ := dns01.GetRecord(domain, keyAuth)

	records, err := d.findTxtRecords(domain, fqdn)
	if err != nil {
		return fmt.Errorf("alicloud: %v", err)
	}

	_, _, err = d.getHostedZone(domain)
	if err != nil {
		return fmt.Errorf("alicloud: %v", err)
	}

	for _, rec := range records {
		request := alidns.CreateDeleteDomainRecordRequest()
		request.RecordId = rec.RecordId
		_, err = d.client.DeleteDomainRecord(request)
		if err != nil {
			return fmt.Errorf("alicloud: %v", err)
		}
	}
	return nil
}

func (d *DNSProvider) getHostedZone(domain string) (string, string, error) {
	request := alidns.CreateDescribeDomainsRequest()

	var domains []alidns.Domain
	startPage := 1

	for {
		request.PageNumber = requests.NewInteger(startPage)

		response, err := d.client.DescribeDomains(request)
		if err != nil {
			return "", "", fmt.Errorf("API call failed: %v", err)
		}

		domains = append(domains, response.Domains.Domain...)

		if response.PageNumber*response.PageSize >= response.TotalCount {
			break
		}

		startPage++
	}

	authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
	if err != nil {
		return "", "", err
	}

	var hostedZone alidns.Domain
	for _, zone := range domains {
		if zone.DomainName == dns01.UnFqdn(authZone) {
			hostedZone = zone
		}
	}

	if hostedZone.DomainId == "" {
		return "", "", fmt.Errorf("zone %s not found in AliDNS for domain %s", authZone, domain)
	}
	return fmt.Sprintf("%v", hostedZone.DomainId), hostedZone.DomainName, nil
}

func (d *DNSProvider) newTxtRecord(zone, fqdn, value string) *alidns.AddDomainRecordRequest {
	request := alidns.CreateAddDomainRecordRequest()
	request.Type = "TXT"
	request.DomainName = zone
	request.RR = d.extractRecordName(fqdn, zone)
	request.Value = value
	request.TTL = requests.NewInteger(d.config.TTL)
	return request
}

func (d *DNSProvider) findTxtRecords(domain, fqdn string) ([]alidns.Record, error) {
	_, zoneName, err := d.getHostedZone(domain)
	if err != nil {
		return nil, err
	}

	request := alidns.CreateDescribeDomainRecordsRequest()
	request.DomainName = zoneName
	request.PageSize = requests.NewInteger(500)

	var records []alidns.Record

	result, err := d.client.DescribeDomainRecords(request)
	if err != nil {
		return records, fmt.Errorf("API call has failed: %v", err)
	}

	recordName := d.extractRecordName(fqdn, zoneName)
	for _, record := range result.DomainRecords.Record {
		if record.RR == recordName {
			records = append(records, record)
		}
	}
	return records, nil
}

func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
	name := dns01.UnFqdn(fqdn)
	if idx := strings.Index(name, "."+domain); idx != -1 {
		return name[:idx]
	}
	return name
}
<|endoftext|>


<commit_before>//
// Copyright 2016 Rackspace
//
// 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 poller

import (
	"context"
	"crypto/tls"
	"io"
	"net"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/racker/rackspace-monitoring-poller/config"
)

// EleConnection implements Connection
// See Connection interface for more information
type EleConnection struct {
	checksReconciler ChecksReconciler

	session Session
	conn    io.ReadWriteCloser

	address string
	guid    string

	connectionTimeout time.Duration

	authenticated chan struct{}
}

// NewConnection instantiates a new EleConnection
// It sets up the address, unique guid, and connection timeout
// for this conneciton
func NewConnection(address string, guid string, checksReconciler ChecksReconciler) Connection {
	return &EleConnection{
		address:           address,
		guid:              guid,
		checksReconciler:  checksReconciler,
		connectionTimeout: time.Duration(10) * time.Second,
		authenticated:     make(chan struct{}, 1),
	}
}

// GetGUID retrieves connection's guid
func (conn *EleConnection) GetGUID() string {
	return conn.guid
}

// GetFarendWriter gets a writer directed towards the endpoint server
func (conn *EleConnection) GetFarendWriter() io.Writer {
	return conn.conn
}

// GetFarendReader gets a reader to consume from the endpoint server
func (conn *EleConnection) GetFarendReader() io.Reader {
	return conn.conn
}

// GetSession retrieves connection's session
func (conn *EleConnection) GetSession() Session {
	return conn.session
}

func (conn *EleConnection) GetClockOffset() int64 {
	return conn.session.GetClockOffset()
}

func (conn *EleConnection) GetLatency() int64 {
	return conn.session.GetLatency()
}

func (conn *EleConnection) HasLatencyMeasurements() bool {
	return conn.session.HasLatencyMeasurements()
}

// SetReadDeadline sets up the read deadline for a socket.
// read deadline - time spent reading response for future calls
func (conn *EleConnection) SetReadDeadline(deadline time.Time) {
	socket, ok := conn.conn.(*net.TCPConn)
	if ok {
		socket.SetReadDeadline(deadline)
	}
}

// SetWriteDeadline sets up the write deadline for a socket.
// write deadline - time spent writing request to socket for future calls
func (conn *EleConnection) SetWriteDeadline(deadline time.Time) {
	socket, ok := conn.conn.(*net.TCPConn)
	if ok {
		socket.SetWriteDeadline(deadline)
	}
}

func (conn *EleConnection) GetLogPrefix() string {
	return conn.address
}

// Connect sets up a tcp connection with connection defined address
// and passed in tlsConfig
// If context is not set, ErrUndefinedContext is returned
// The end result of this function is a usable connection ready to
// send data.
func (conn *EleConnection) Connect(ctx context.Context, config *config.Config, tlsConfig *tls.Config) error {
	if ctx == nil {
		return ErrUndefinedContext
	}
	log.WithFields(log.Fields{
		"prefix":  conn.GetLogPrefix(),
		"timeout": conn.connectionTimeout,
	}).Info("Connecting to agent/poller endpoint")
	nd := net.Dialer{Timeout: conn.connectionTimeout}
	tlsConn, err := tls.DialWithDialer(&nd, "tcp", conn.address, tlsConfig)
	if err != nil {
		return err
	}
	conn.conn = tlsConn
	conn.session = NewSession(ctx, conn, conn.checksReconciler, config)
	log.WithFields(log.Fields{
		"prefix":         conn.GetLogPrefix(),
		"remote_address": tlsConn.RemoteAddr(),
	}).Info("Connected")
	return nil
}

// Close closes the session
func (conn *EleConnection) Close() {
	if conn.conn != nil {
		conn.conn.Close()
		conn.conn = nil
	}
	conn.GetSession().Close()
}

// Wait returns a channel that is populated when the connection is finished or closed.
func (conn *EleConnection) Done() <-chan struct{} {
	return conn.GetSession().Done()
}

func (conn *EleConnection) SetAuthenticated() {
	close(conn.authenticated)
}

func (conn *EleConnection) Authenticated() <-chan struct{} {
	return conn.authenticated
}
<commit_msg>Balance the connection's "Connected" log with "Disconnected" (#122)<commit_after>//
// Copyright 2016 Rackspace
//
// 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 poller

import (
	"context"
	"crypto/tls"
	"io"
	"net"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/racker/rackspace-monitoring-poller/config"
)

// EleConnection implements Connection
// See Connection interface for more information
type EleConnection struct {
	checksReconciler ChecksReconciler

	session Session
	conn    io.ReadWriteCloser

	address string
	guid    string

	connectionTimeout time.Duration

	authenticated chan struct{}
}

// NewConnection instantiates a new EleConnection
// It sets up the address, unique guid, and connection timeout
// for this conneciton
func NewConnection(address string, guid string, checksReconciler ChecksReconciler) Connection {
	return &EleConnection{
		address:           address,
		guid:              guid,
		checksReconciler:  checksReconciler,
		connectionTimeout: time.Duration(10) * time.Second,
		authenticated:     make(chan struct{}, 1),
	}
}

// GetGUID retrieves connection's guid
func (conn *EleConnection) GetGUID() string {
	return conn.guid
}

// GetFarendWriter gets a writer directed towards the endpoint server
func (conn *EleConnection) GetFarendWriter() io.Writer {
	return conn.conn
}

// GetFarendReader gets a reader to consume from the endpoint server
func (conn *EleConnection) GetFarendReader() io.Reader {
	return conn.conn
}

// GetSession retrieves connection's session
func (conn *EleConnection) GetSession() Session {
	return conn.session
}

func (conn *EleConnection) GetClockOffset() int64 {
	return conn.session.GetClockOffset()
}

func (conn *EleConnection) GetLatency() int64 {
	return conn.session.GetLatency()
}

func (conn *EleConnection) HasLatencyMeasurements() bool {
	return conn.session.HasLatencyMeasurements()
}

// SetReadDeadline sets up the read deadline for a socket.
// read deadline - time spent reading response for future calls
func (conn *EleConnection) SetReadDeadline(deadline time.Time) {
	socket, ok := conn.conn.(*net.TCPConn)
	if ok {
		socket.SetReadDeadline(deadline)
	}
}

// SetWriteDeadline sets up the write deadline for a socket.
// write deadline - time spent writing request to socket for future calls
func (conn *EleConnection) SetWriteDeadline(deadline time.Time) {
	socket, ok := conn.conn.(*net.TCPConn)
	if ok {
		socket.SetWriteDeadline(deadline)
	}
}

func (conn *EleConnection) GetLogPrefix() string {
	return conn.address
}

// Connect sets up a tcp connection with connection defined address
// and passed in tlsConfig
// If context is not set, ErrUndefinedContext is returned
// The end result of this function is a usable connection ready to
// send data.
func (conn *EleConnection) Connect(ctx context.Context, config *config.Config, tlsConfig *tls.Config) error {
	if ctx == nil {
		return ErrUndefinedContext
	}
	log.WithFields(log.Fields{
		"prefix":  conn.GetLogPrefix(),
		"timeout": conn.connectionTimeout,
	}).Info("Connecting to agent/poller endpoint")
	nd := net.Dialer{Timeout: conn.connectionTimeout}
	tlsConn, err := tls.DialWithDialer(&nd, "tcp", conn.address, tlsConfig)
	if err != nil {
		return err
	}
	conn.conn = tlsConn
	conn.session = NewSession(ctx, conn, conn.checksReconciler, config)
	log.WithFields(log.Fields{
		"prefix":         conn.GetLogPrefix(),
		"remote_address": tlsConn.RemoteAddr(),
	}).Info("Connected")
	return nil
}

// Close closes the session
func (conn *EleConnection) Close() {
	if conn.conn != nil {
		log.WithFields(log.Fields{
			"prefix":         conn.GetLogPrefix(),
			"remote_address": conn.address,
		}).Info("Disconnected")
		conn.conn.Close()
		conn.conn = nil
	}
	conn.GetSession().Close()
}

// Wait returns a channel that is populated when the connection is finished or closed.
func (conn *EleConnection) Done() <-chan struct{} {
	return conn.GetSession().Done()
}

func (conn *EleConnection) SetAuthenticated() {
	close(conn.authenticated)
}

func (conn *EleConnection) Authenticated() <-chan struct{} {
	return conn.authenticated
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"strconv"

	"gopkg.in/jcelliott/turnpike.v2"
)

const (
	POLONIEX_WEBSOCKET_ADDRESS  = "wss://api.poloniex.com"
	POLONIEX_WEBSOCKET_REALM    = "realm1"
	POLONIEX_WEBSOCKET_TICKER   = "ticker"
	POLONIEX_WEBSOCKET_TROLLBOX = "trollbox"
)

type PoloniexWebsocketTicker struct {
	CurrencyPair  string
	Last          float64
	LowestAsk     float64
	HighestBid    float64
	PercentChange float64
	BaseVolume    float64
	QuoteVolume   float64
	IsFrozen      bool
	High          float64
	Low           float64
}

func PoloniexOnTicker(args []interface{}, kwargs map[string]interface{}) {
	ticker := PoloniexWebsocketTicker{}
	ticker.CurrencyPair = args[0].(string)
	ticker.Last, _ = strconv.ParseFloat(args[1].(string), 64)
	ticker.LowestAsk, _ = strconv.ParseFloat(args[2].(string), 64)
	ticker.HighestBid, _ = strconv.ParseFloat(args[3].(string), 64)
	ticker.PercentChange, _ = strconv.ParseFloat(args[4].(string), 64)
	ticker.BaseVolume, _ = strconv.ParseFloat(args[5].(string), 64)
	ticker.QuoteVolume, _ = strconv.ParseFloat(args[6].(string), 64)

	if args[7].(float64) != 0 {
		ticker.IsFrozen = true
	} else {
		ticker.IsFrozen = false
	}

	ticker.High, _ = strconv.ParseFloat(args[8].(string), 64)
	ticker.Low, _ = strconv.ParseFloat(args[9].(string), 64)
}

type PoloniexWebsocketTrollboxMessage struct {
	MessageNumber float64
	Username      string
	Message       string
	Reputation    float64
}

func PoloniexOnTrollbox(args []interface{}, kwargs map[string]interface{}) {
	message := PoloniexWebsocketTrollboxMessage{}
	message.MessageNumber, _ = args[1].(float64)
	message.Username = args[2].(string)
	message.Message = args[3].(string)
	message.Reputation = args[4].(float64)
}

func PoloniexOnDepthOrTrade(args []interface{}, kwargs map[string]interface{}) {
	for x := range args {
		data := args[x].(map[string]interface{})
		msgData := data["data"].(map[string]interface{})
		msgType := data["type"].(string)

		switch msgType {
		case "orderBookModify":
			{
				type PoloniexWebsocketOrderbookModify struct {
					Type   string
					Rate   float64
					Amount float64
				}

				orderModify := PoloniexWebsocketOrderbookModify{}
				orderModify.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderModify.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				orderModify.Amount, _ = strconv.ParseFloat(amountStr, 64)
			}
		case "orderBookRemove":
			{
				type PoloniexWebsocketOrderbookRemove struct {
					Type string
					Rate float64
				}

				orderRemoval := PoloniexWebsocketOrderbookRemove{}
				orderRemoval.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderRemoval.Rate, _ = strconv.ParseFloat(rateStr, 64)
			}
		case "newTrade":
			{
				type PoloniexWebsocketNewTrade struct {
					Type    string
					TradeID int64
					Rate    float64
					Amount  float64
					Date    string
					Total   float64
				}

				trade := PoloniexWebsocketNewTrade{}
				trade.Type = msgData["type"].(string)

				tradeIDstr := msgData["tradeID"].(string)
				trade.TradeID, _ = strconv.ParseInt(tradeIDstr, 10, 64)

				rateStr := msgData["rate"].(string)
				trade.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				trade.Amount, _ = strconv.ParseFloat(amountStr, 64)

				totalStr := msgData["total"].(string)
				trade.Rate, _ = strconv.ParseFloat(totalStr, 64)

				trade.Date = msgData["date"].(string)
			}
		}
	}
}

func (p *Poloniex) WebsocketClient() {
	for p.Enabled && p.Websocket {
		c, err := turnpike.NewWebsocketClient(turnpike.JSON, POLONIEX_WEBSOCKET_ADDRESS, nil)
		if err != nil {
			log.Printf("%s Unable to connect to Websocket. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Connected to Websocket.\n", p.GetName())
		}

		_, err = c.JoinRealm(POLONIEX_WEBSOCKET_REALM, nil)
		if err != nil {
			log.Printf("%s Unable to join realm. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Joined Websocket realm.\n", p.GetName())
		}

		c.ReceiveDone = make(chan bool)

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TICKER, PoloniexOnTicker); err != nil {
			log.Printf("%s Error subscribing to ticker channel: %s\n", p.GetName(), err)
		}

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TROLLBOX, PoloniexOnTrollbox); err != nil {
			log.Printf("%s Error subscribing to trollbox channel: %s\n", p.GetName(), err)
		}

		for x := range p.EnabledPairs {
			currency := p.EnabledPairs[x]
			if err := c.Subscribe(currency, PoloniexOnDepthOrTrade); err != nil {
				log.Printf("%s Error subscribing to %s channel: %s\n", p.GetName(), currency, err)
			}
		}

		if p.Verbose {
			log.Printf("%s Subscribed to websocket channels.\n", p.GetName())
		}

		<-c.ReceiveDone
		log.Printf("%s Websocket client disconnected.\n", p.GetName())
	}
}
<commit_msg>Removes extra argument on poloniex method<commit_after>package main

import (
	"log"
	"strconv"

	"gopkg.in/jcelliott/turnpike.v2"
)

const (
	POLONIEX_WEBSOCKET_ADDRESS  = "wss://api.poloniex.com"
	POLONIEX_WEBSOCKET_REALM    = "realm1"
	POLONIEX_WEBSOCKET_TICKER   = "ticker"
	POLONIEX_WEBSOCKET_TROLLBOX = "trollbox"
)

type PoloniexWebsocketTicker struct {
	CurrencyPair  string
	Last          float64
	LowestAsk     float64
	HighestBid    float64
	PercentChange float64
	BaseVolume    float64
	QuoteVolume   float64
	IsFrozen      bool
	High          float64
	Low           float64
}

func PoloniexOnTicker(args []interface{}, kwargs map[string]interface{}) {
	ticker := PoloniexWebsocketTicker{}
	ticker.CurrencyPair = args[0].(string)
	ticker.Last, _ = strconv.ParseFloat(args[1].(string), 64)
	ticker.LowestAsk, _ = strconv.ParseFloat(args[2].(string), 64)
	ticker.HighestBid, _ = strconv.ParseFloat(args[3].(string), 64)
	ticker.PercentChange, _ = strconv.ParseFloat(args[4].(string), 64)
	ticker.BaseVolume, _ = strconv.ParseFloat(args[5].(string), 64)
	ticker.QuoteVolume, _ = strconv.ParseFloat(args[6].(string), 64)

	if args[7].(float64) != 0 {
		ticker.IsFrozen = true
	} else {
		ticker.IsFrozen = false
	}

	ticker.High, _ = strconv.ParseFloat(args[8].(string), 64)
	ticker.Low, _ = strconv.ParseFloat(args[9].(string), 64)
}

type PoloniexWebsocketTrollboxMessage struct {
	MessageNumber float64
	Username      string
	Message       string
	Reputation    float64
}

func PoloniexOnTrollbox(args []interface{}, kwargs map[string]interface{}) {
	message := PoloniexWebsocketTrollboxMessage{}
	message.MessageNumber, _ = args[1].(float64)
	message.Username = args[2].(string)
	message.Message = args[3].(string)
	message.Reputation = args[4].(float64)
}

func PoloniexOnDepthOrTrade(args []interface{}, kwargs map[string]interface{}) {
	for x := range args {
		data := args[x].(map[string]interface{})
		msgData := data["data"].(map[string]interface{})
		msgType := data["type"].(string)

		switch msgType {
		case "orderBookModify":
			{
				type PoloniexWebsocketOrderbookModify struct {
					Type   string
					Rate   float64
					Amount float64
				}

				orderModify := PoloniexWebsocketOrderbookModify{}
				orderModify.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderModify.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				orderModify.Amount, _ = strconv.ParseFloat(amountStr, 64)
			}
		case "orderBookRemove":
			{
				type PoloniexWebsocketOrderbookRemove struct {
					Type string
					Rate float64
				}

				orderRemoval := PoloniexWebsocketOrderbookRemove{}
				orderRemoval.Type = msgData["type"].(string)

				rateStr := msgData["rate"].(string)
				orderRemoval.Rate, _ = strconv.ParseFloat(rateStr, 64)
			}
		case "newTrade":
			{
				type PoloniexWebsocketNewTrade struct {
					Type    string
					TradeID int64
					Rate    float64
					Amount  float64
					Date    string
					Total   float64
				}

				trade := PoloniexWebsocketNewTrade{}
				trade.Type = msgData["type"].(string)

				tradeIDstr := msgData["tradeID"].(string)
				trade.TradeID, _ = strconv.ParseInt(tradeIDstr, 10, 64)

				rateStr := msgData["rate"].(string)
				trade.Rate, _ = strconv.ParseFloat(rateStr, 64)

				amountStr := msgData["amount"].(string)
				trade.Amount, _ = strconv.ParseFloat(amountStr, 64)

				totalStr := msgData["total"].(string)
				trade.Rate, _ = strconv.ParseFloat(totalStr, 64)

				trade.Date = msgData["date"].(string)
			}
		}
	}
}

func (p *Poloniex) WebsocketClient() {
	for p.Enabled && p.Websocket {
		c, err := turnpike.NewWebsocketClient(turnpike.JSON, POLONIEX_WEBSOCKET_ADDRESS)
		if err != nil {
			log.Printf("%s Unable to connect to Websocket. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Connected to Websocket.\n", p.GetName())
		}

		_, err = c.JoinRealm(POLONIEX_WEBSOCKET_REALM, nil)
		if err != nil {
			log.Printf("%s Unable to join realm. Error: %s\n", p.GetName(), err)
			continue
		}

		if p.Verbose {
			log.Printf("%s Joined Websocket realm.\n", p.GetName())
		}

		c.ReceiveDone = make(chan bool)

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TICKER, PoloniexOnTicker); err != nil {
			log.Printf("%s Error subscribing to ticker channel: %s\n", p.GetName(), err)
		}

		if err := c.Subscribe(POLONIEX_WEBSOCKET_TROLLBOX, PoloniexOnTrollbox); err != nil {
			log.Printf("%s Error subscribing to trollbox channel: %s\n", p.GetName(), err)
		}

		for x := range p.EnabledPairs {
			currency := p.EnabledPairs[x]
			if err := c.Subscribe(currency, PoloniexOnDepthOrTrade); err != nil {
				log.Printf("%s Error subscribing to %s channel: %s\n", p.GetName(), currency, err)
			}
		}

		if p.Verbose {
			log.Printf("%s Subscribed to websocket channels.\n", p.GetName())
		}

		<-c.ReceiveDone
		log.Printf("%s Websocket client disconnected.\n", p.GetName())
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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 ns

import (
	"fmt"
	"os"
	"runtime"
	"syscall"
)

var setNsMap = map[string]uintptr{
	"386":   346,
	"amd64": 308,
	"arm":   374,
}

// SetNS sets the network namespace on a target file.
func SetNS(f *os.File, flags uintptr) error {
	if runtime.GOOS != "linux" {
		return fmt.Errorf("unsupported OS: %s", runtime.GOOS)
	}

	trap, ok := setNsMap[runtime.GOARCH]
	if !ok {
		return fmt.Errorf("unsupported arch: %s", runtime.GOARCH)
	}

	_, _, err := syscall.RawSyscall(trap, f.Fd(), flags, 0)
	if err != 0 {
		return err
	}

	return nil
}

// WithNetNSPath executes the passed closure under the given network
// namespace, restoring the original namespace afterwards.
func WithNetNSPath(nspath string, f func(*os.File) error) error {
	ns, err := os.Open(nspath)
	if err != nil {
		return fmt.Errorf("Failed to open %v: %v", nspath, err)
	}
	defer ns.Close()

	return WithNetNS(ns, f)
}

// WithNetNS executes the passed closure under the given network
// namespace, restoring the original namespace afterwards.
func WithNetNS(ns *os.File, f func(*os.File) error) error {
	// save a handle to current (host) network namespace
	thisNS, err := os.Open("/proc/self/ns/net")
	if err != nil {
		return fmt.Errorf("Failed to open /proc/self/ns/net: %v", err)
	}
	defer thisNS.Close()

	if err = SetNS(ns, syscall.CLONE_NEWNET); err != nil {
		return fmt.Errorf("Error switching to ns %v: %v", ns.Name(), err)
	}

	if err = f(thisNS); err != nil {
		return err
	}

	// switch back
	return SetNS(thisNS, syscall.CLONE_NEWNET)
}
<commit_msg>add DHCP IPAM plugin<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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 ns

import (
	"fmt"
	"os"
	"runtime"
	"syscall"
)

var setNsMap = map[string]uintptr{
	"386":   346,
	"amd64": 308,
	"arm":   374,
}

// SetNS sets the network namespace on a target file.
func SetNS(f *os.File, flags uintptr) error {
	if runtime.GOOS != "linux" {
		return fmt.Errorf("unsupported OS: %s", runtime.GOOS)
	}

	trap, ok := setNsMap[runtime.GOARCH]
	if !ok {
		return fmt.Errorf("unsupported arch: %s", runtime.GOARCH)
	}

	_, _, err := syscall.RawSyscall(trap, f.Fd(), flags, 0)
	if err != 0 {
		return err
	}

	return nil
}

// WithNetNSPath executes the passed closure under the given network
// namespace, restoring the original namespace afterwards.
// Changing namespaces must be done on a goroutine that has been
// locked to an OS thread. If lockThread arg is true, this function
// locks the goroutine prior to change namespace and unlocks before
// returning
func WithNetNSPath(nspath string, lockThread bool, f func(*os.File) error) error {
	ns, err := os.Open(nspath)
	if err != nil {
		return fmt.Errorf("Failed to open %v: %v", nspath, err)
	}
	defer ns.Close()
	return WithNetNS(ns, lockThread, f)
}

// WithNetNS executes the passed closure under the given network
// namespace, restoring the original namespace afterwards.
// Changing namespaces must be done on a goroutine that has been
// locked to an OS thread. If lockThread arg is true, this function
// locks the goroutine prior to change namespace and unlocks before
// returning
func WithNetNS(ns *os.File, lockThread bool, f func(*os.File) error) error {
	if lockThread {
		runtime.LockOSThread()
		defer runtime.UnlockOSThread()
	}
	// save a handle to current (host) network namespace
	thisNS, err := os.Open("/proc/self/ns/net")
	if err != nil {
		return fmt.Errorf("Failed to open /proc/self/ns/net: %v", err)
	}
	defer thisNS.Close()

	if err = SetNS(ns, syscall.CLONE_NEWNET); err != nil {
		return fmt.Errorf("Error switching to ns %v: %v", ns.Name(), err)
	}

	if err = f(thisNS); err != nil {
		return err
	}

	// switch back
	return SetNS(thisNS, syscall.CLONE_NEWNET)
}
<|endoftext|>


<commit_before>package actors

import (
	"github.com/cloudfoundry/cli/cf/actors/broker_builder"
	"github.com/cloudfoundry/cli/cf/actors/service_builder"
	"github.com/cloudfoundry/cli/cf/api/organizations"
	"github.com/cloudfoundry/cli/cf/models"
)

type ServiceActor interface {
	FilterBrokers(brokerFlag string, serviceFlag string, orgFlag string) ([]models.ServiceBroker, error)
}

type ServiceHandler struct {
	orgRepo        organizations.OrganizationRepository
	brokerBuilder  broker_builder.BrokerBuilder
	serviceBuilder service_builder.ServiceBuilder
}

func NewServiceHandler(org organizations.OrganizationRepository, brokerBuilder broker_builder.BrokerBuilder, serviceBuilder service_builder.ServiceBuilder) ServiceHandler {
	return ServiceHandler{
		orgRepo:        org,
		brokerBuilder:  brokerBuilder,
		serviceBuilder: serviceBuilder,
	}
}

func (actor ServiceHandler) FilterBrokers(brokerFlag string, serviceFlag string, orgFlag string) ([]models.ServiceBroker, error) {
	if orgFlag == "" {
		return actor.getServiceBrokers(brokerFlag, serviceFlag)
	}
	err := actor.checkForOrgExistence(orgFlag)
	if err != nil {
		return nil, err
	}
	return actor.buildBrokersVisibleFromOrg(brokerFlag, serviceFlag, orgFlag)
}

func (actor ServiceHandler) checkForOrgExistence(orgName string) error {
	_, err := actor.orgRepo.FindByName(orgName)
	return err
}

func (actor ServiceHandler) getServiceBrokers(brokerName string, serviceName string) ([]models.ServiceBroker, error) {
	if serviceName != "" {
		broker, err := actor.brokerBuilder.GetBrokerWithSpecifiedService(serviceName)
		if err != nil {
			return nil, err
		}

		if brokerName != "" {
			if broker.Name != brokerName {
				return nil, nil
			}
		}
		return []models.ServiceBroker{broker}, nil
	}

	if brokerName != "" && serviceName == "" {
		broker, err := actor.brokerBuilder.GetBrokerWithAllServices(brokerName)
		if err != nil {
			return nil, err
		}
		return []models.ServiceBroker{broker}, nil
	}

	return actor.brokerBuilder.GetAllServiceBrokers()
}

func (actor ServiceHandler) buildBrokersVisibleFromOrg(brokerFlag string, serviceFlag string, orgFlag string) ([]models.ServiceBroker, error) {
	if serviceFlag != "" && brokerFlag != "" {
		service, err := actor.serviceBuilder.GetServiceVisibleToOrg(serviceFlag, orgFlag)
		if err != nil {
			return nil, err
		}
		broker, err := actor.brokerBuilder.AttachSpecificBrokerToServices(brokerFlag, []models.ServiceOffering{service})
		if err != nil {
			return nil, err
		}
		return []models.ServiceBroker{broker}, nil
	}

	if serviceFlag != "" && brokerFlag == "" {
		service, err := actor.serviceBuilder.GetServiceVisibleToOrg(serviceFlag, orgFlag)
		if err != nil {
			return nil, err
		}
		return actor.brokerBuilder.AttachBrokersToServices([]models.ServiceOffering{service})
	}

	if serviceFlag == "" && brokerFlag != "" {
		services, err := actor.serviceBuilder.GetServicesVisibleToOrg(orgFlag)
		if err != nil {
			return nil, err
		}
		broker, err := actor.brokerBuilder.AttachSpecificBrokerToServices(brokerFlag, services)
		if err != nil {
			return nil, err
		}
		return []models.ServiceBroker{broker}, nil
	}

	if serviceFlag == "" && brokerFlag == "" {
		services, err := actor.serviceBuilder.GetServicesVisibleToOrg(orgFlag)
		if err != nil {
			return nil, err
		}
		return actor.brokerBuilder.AttachBrokersToServices(services)
	}

	return nil, nil
}
<commit_msg>Remove checkForOrgExistence<commit_after>package actors

import (
	"github.com/cloudfoundry/cli/cf/actors/broker_builder"
	"github.com/cloudfoundry/cli/cf/actors/service_builder"
	"github.com/cloudfoundry/cli/cf/api/organizations"
	"github.com/cloudfoundry/cli/cf/models"
)

type ServiceActor interface {
	FilterBrokers(brokerFlag string, serviceFlag string, orgFlag string) ([]models.ServiceBroker, error)
}

type ServiceHandler struct {
	orgRepo        organizations.OrganizationRepository
	brokerBuilder  broker_builder.BrokerBuilder
	serviceBuilder service_builder.ServiceBuilder
}

func NewServiceHandler(org organizations.OrganizationRepository, brokerBuilder broker_builder.BrokerBuilder, serviceBuilder service_builder.ServiceBuilder) ServiceHandler {
	return ServiceHandler{
		orgRepo:        org,
		brokerBuilder:  brokerBuilder,
		serviceBuilder: serviceBuilder,
	}
}

func (actor ServiceHandler) FilterBrokers(brokerFlag string, serviceFlag string, orgFlag string) ([]models.ServiceBroker, error) {
	if orgFlag == "" {
		return actor.getServiceBrokers(brokerFlag, serviceFlag)
	}
	_, err := actor.orgRepo.FindByName(orgFlag)
	if err != nil {
		return nil, err
	}
	return actor.buildBrokersVisibleFromOrg(brokerFlag, serviceFlag, orgFlag)
}

func (actor ServiceHandler) getServiceBrokers(brokerName string, serviceName string) ([]models.ServiceBroker, error) {
	if serviceName != "" {
		broker, err := actor.brokerBuilder.GetBrokerWithSpecifiedService(serviceName)
		if err != nil {
			return nil, err
		}

		if brokerName != "" {
			if broker.Name != brokerName {
				return nil, nil
			}
		}
		return []models.ServiceBroker{broker}, nil
	}

	if brokerName != "" && serviceName == "" {
		broker, err := actor.brokerBuilder.GetBrokerWithAllServices(brokerName)
		if err != nil {
			return nil, err
		}
		return []models.ServiceBroker{broker}, nil
	}

	return actor.brokerBuilder.GetAllServiceBrokers()
}

func (actor ServiceHandler) buildBrokersVisibleFromOrg(brokerFlag string, serviceFlag string, orgFlag string) ([]models.ServiceBroker, error) {
	if serviceFlag != "" && brokerFlag != "" {
		service, err := actor.serviceBuilder.GetServiceVisibleToOrg(serviceFlag, orgFlag)
		if err != nil {
			return nil, err
		}
		broker, err := actor.brokerBuilder.AttachSpecificBrokerToServices(brokerFlag, []models.ServiceOffering{service})
		if err != nil {
			return nil, err
		}
		return []models.ServiceBroker{broker}, nil
	}

	if serviceFlag != "" && brokerFlag == "" {
		service, err := actor.serviceBuilder.GetServiceVisibleToOrg(serviceFlag, orgFlag)
		if err != nil {
			return nil, err
		}
		return actor.brokerBuilder.AttachBrokersToServices([]models.ServiceOffering{service})
	}

	if serviceFlag == "" && brokerFlag != "" {
		services, err := actor.serviceBuilder.GetServicesVisibleToOrg(orgFlag)
		if err != nil {
			return nil, err
		}
		broker, err := actor.brokerBuilder.AttachSpecificBrokerToServices(brokerFlag, services)
		if err != nil {
			return nil, err
		}
		return []models.ServiceBroker{broker}, nil
	}

	if serviceFlag == "" && brokerFlag == "" {
		services, err := actor.serviceBuilder.GetServicesVisibleToOrg(orgFlag)
		if err != nil {
			return nil, err
		}
		return actor.brokerBuilder.AttachBrokersToServices(services)
	}

	return nil, nil
}
<|endoftext|>


<commit_before>package glukit

import (
	"appengine"
	"appengine/datastore"
	"appengine/user"
	"fmt"
	"github.com/alexandre-normand/glukit/app/apimodel"
	"github.com/alexandre-normand/glukit/app/model"
	"github.com/alexandre-normand/glukit/app/store"
	"github.com/alexandre-normand/glukit/app/util"
	"github.com/alexandre-normand/glukit/lib/goauth2/oauth"
	"github.com/alexandre-normand/osin"
	"html/template"
	"net/http"
	"strings"
	"time"
)

var server *osin.Server

const (
	TOKEN_ROUTE     = "token"
	AUTHORIZE_ROUTE = "authorize"
)

type oauthAuthenticatedHandler struct {
	authenticatedHandler http.Handler
}

// Some variables that are used during rendering of oauth templates
type OauthRenderVariables struct {
	Code  string
	State string
}

var authorizeLocalAppTemplate = template.Must(template.ParseFiles("view/templates/oauthorize.html"))

func initOauthProvider(writer http.ResponseWriter, request *http.Request) {
	sconfig := osin.NewServerConfig()
	sconfig.AllowedAuthorizeTypes = osin.AllowedAuthorizeType{osin.CODE, osin.TOKEN}
	sconfig.AllowedAccessTypes = osin.AllowedAccessType{osin.AUTHORIZATION_CODE,
		osin.REFRESH_TOKEN}
	// 30 days
	sconfig.AccessExpiration = 60 * 60 * 24 * 30
	sconfig.AllowGetAccessRequest = true
	server = osin.NewServer(sconfig, store.NewOsinAppEngineStoreWithRequest(request))
	muxRouter.Get(AUTHORIZE_ROUTE).HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		c := appengine.NewContext(req)
		user := user.Current(c)
		resp := server.NewResponse()
		req.ParseForm()
		req.SetBasicAuth(req.Form.Get("client_id"), req.Form.Get("client_secret"))
		c.Debugf("Processing authorization request: %v and form [%v]", req, req.PostForm)
		if ar := server.HandleAuthorizeRequest(resp, req); ar != nil {
			// Nothing to do since the page is already login restricted by gae app configuration
			ar.Authorized = true
			ar.UserData = user.Email

			_, _, _, err := store.GetUserData(c, user.Email)
			if err == datastore.ErrNoSuchEntity {
				c.Debugf("Creating GlukitUser on first oauth access for [%s]: ", user.Email)
				// If the user doesn't exist already, create it
				glukitUser := model.GlukitUser{user.Email, "", "", time.Now(),
					model.DIABETES_TYPE_1, "", util.GLUKIT_EPOCH_TIME, apimodel.UNDEFINED_GLUCOSE_READ, oauth.Token{"", "", util.GLUKIT_EPOCH_TIME}, "",
					model.UNDEFINED_SCORE, model.UNDEFINED_SCORE, false, "", time.Now(), model.UNDEFINED_A1C_ESTIMATE}
				_, err = store.StoreUserProfile(c, time.Now(), glukitUser)
				if err != nil {
					resp.SetError(osin.E_SERVER_ERROR, fmt.Sprintf("Fail to initialize user for email [%s]: [%v]", user.Email, err))
					resp.StatusCode = 500
					osin.OutputJSON(resp, writer, request)
					return
				}
			} else if err != nil {
				resp.SetError(osin.E_SERVER_ERROR, fmt.Sprintf("Unable to find user for email [%s]: [%v]", user.Email, err))
				resp.StatusCode = 500
				osin.OutputJSON(resp, writer, request)
				return
			}

			if err != nil {
				util.Propagate(err)
			}

			server.FinishAuthorizeRequest(resp, req, ar)

			data := resp.Output
			if resp.URL == "urn:ietf:wg:oauth:2.0:oob" {
				// Render a page with the title including the code
				renderVariables := &OauthRenderVariables{Code: data["code"].(string), State: data["state"].(string)}

				if err := authorizeLocalAppTemplate.Execute(w, renderVariables); err != nil {
					c.Criticalf("Error executing template [%s]", authorizeLocalAppTemplate.Name())
					http.Error(w, err.Error(), http.StatusInternalServerError)
				}
			} else {
				redirectUrl := fmt.Sprintf("%s?code=%s", resp.URL, data["code"].(string))
				c.Infof("Redirecting to [%s] with valid code.", redirectUrl)
				http.Redirect(w, req, redirectUrl, 200)
				return
			}
		}
		if resp.IsError && resp.InternalError != nil {
			c.Debugf("ERROR: %s\n", resp.InternalError)
		}
		c.Debugf("Writing response: %v", resp.Output)
		osin.OutputJSON(resp, w, req)
	})

	// Access token endpoint
	muxRouter.Get(TOKEN_ROUTE).HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		c := appengine.NewContext(req)
		resp := server.NewResponse()
		req.ParseForm()
		req.SetBasicAuth(req.Form.Get("client_id"), req.Form.Get("client_secret"))
		c.Debugf("Processing token request: %v with form [%v]", req, req.PostForm)
		if ar := server.HandleAccessRequest(resp, req); ar != nil {
			c.Debugf("Retrieved authorize data [%v]", ar)
			ar.Authorized = true
			server.FinishAccessRequest(resp, req, ar)
		}
		c.Debugf("Writing response: %v", resp.Output)
		osin.OutputJSON(resp, w, req)
	})
	context := appengine.NewContext(request)
	context.Debugf("Oauth server loaded: [%v]", server)
}

func (handler *oauthAuthenticatedHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	c := appengine.NewContext(request)
	request.ParseForm()
	c.Debugf("Checking authentication for request [%s]...", request.RequestURI)

	ret := server.NewResponse()
	authorizationValue := request.Header.Get("Authorization")
	if authorizationValue == "" {
		ret.SetError(osin.E_INVALID_REQUEST, "Empty authorization")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	accessCode := strings.TrimPrefix(authorizationValue, "Bearer ")
	if accessCode == "" {
		ret.SetError(osin.E_INVALID_REQUEST, "Empty authorization value")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	var err error

	// load access data
	accessData, err := server.Storage.LoadAccess(accessCode, request)
	if err != nil {
		ret.SetError(osin.E_INVALID_REQUEST, fmt.Sprintf("Error loading access data for code [%s]: [%v]", accessCode, err))
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}
	if accessData.Client == nil {
		ret.SetError(osin.E_UNAUTHORIZED_CLIENT, "")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}
	if accessData.Client.RedirectUri == "" {
		ret.SetError(osin.E_UNAUTHORIZED_CLIENT, "")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}
	if accessData.IsExpired() {
		ret.SetError(osin.E_INVALID_GRANT, "")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	if ret.IsError {
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	handler.authenticatedHandler.ServeHTTP(writer, request)
}

func newOauthAuthenticationHandler(next http.Handler) *oauthAuthenticatedHandler {
	return &oauthAuthenticatedHandler{next}
}
<commit_msg>Fix Oauth Flow For Standard Clients.<commit_after>package glukit

import (
	"appengine"
	"appengine/datastore"
	"appengine/user"
	"fmt"
	"github.com/alexandre-normand/glukit/app/apimodel"
	"github.com/alexandre-normand/glukit/app/model"
	"github.com/alexandre-normand/glukit/app/store"
	"github.com/alexandre-normand/glukit/app/util"
	"github.com/alexandre-normand/glukit/lib/goauth2/oauth"
	"github.com/alexandre-normand/osin"
	"html/template"
	"net/http"
	"strings"
	"time"
)

var server *osin.Server

const (
	TOKEN_ROUTE     = "token"
	AUTHORIZE_ROUTE = "authorize"
)

type oauthAuthenticatedHandler struct {
	authenticatedHandler http.Handler
}

// Some variables that are used during rendering of oauth templates
type OauthRenderVariables struct {
	Code  string
	State string
}

var authorizeLocalAppTemplate = template.Must(template.ParseFiles("view/templates/oauthorize.html"))

func initOauthProvider(writer http.ResponseWriter, request *http.Request) {
	sconfig := osin.NewServerConfig()
	sconfig.AllowedAuthorizeTypes = osin.AllowedAuthorizeType{osin.CODE, osin.TOKEN}
	sconfig.AllowedAccessTypes = osin.AllowedAccessType{osin.AUTHORIZATION_CODE,
		osin.REFRESH_TOKEN}
	// 30 days
	sconfig.AccessExpiration = 60 * 60 * 24 * 30
	sconfig.AllowGetAccessRequest = true
	server = osin.NewServer(sconfig, store.NewOsinAppEngineStoreWithRequest(request))
	muxRouter.Get(AUTHORIZE_ROUTE).HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		c := appengine.NewContext(req)
		user := user.Current(c)
		resp := server.NewResponse()
		req.ParseForm()
		req.SetBasicAuth(req.Form.Get("client_id"), req.Form.Get("client_secret"))
		c.Debugf("Processing authorization request: %v and form [%v]", req, req.PostForm)
		if ar := server.HandleAuthorizeRequest(resp, req); ar != nil {
			// Nothing to do since the page is already login restricted by gae app configuration
			ar.Authorized = true
			ar.UserData = user.Email

			_, _, _, err := store.GetUserData(c, user.Email)
			if err == datastore.ErrNoSuchEntity {
				c.Debugf("Creating GlukitUser on first oauth access for [%s]: ", user.Email)
				// If the user doesn't exist already, create it
				glukitUser := model.GlukitUser{user.Email, "", "", time.Now(),
					model.DIABETES_TYPE_1, "", util.GLUKIT_EPOCH_TIME, apimodel.UNDEFINED_GLUCOSE_READ, oauth.Token{"", "", util.GLUKIT_EPOCH_TIME}, "",
					model.UNDEFINED_SCORE, model.UNDEFINED_SCORE, false, "", time.Now(), model.UNDEFINED_A1C_ESTIMATE}
				_, err = store.StoreUserProfile(c, time.Now(), glukitUser)
				if err != nil {
					resp.SetError(osin.E_SERVER_ERROR, fmt.Sprintf("Fail to initialize user for email [%s]: [%v]", user.Email, err))
					resp.StatusCode = 500
					osin.OutputJSON(resp, writer, request)
					return
				}
			} else if err != nil {
				resp.SetError(osin.E_SERVER_ERROR, fmt.Sprintf("Unable to find user for email [%s]: [%v]", user.Email, err))
				resp.StatusCode = 500
				osin.OutputJSON(resp, writer, request)
				return
			}

			if err != nil {
				util.Propagate(err)
			}

			server.FinishAuthorizeRequest(resp, req, ar)

			data := resp.Output
			if resp.URL == "urn:ietf:wg:oauth:2.0:oob" {
				// Render a page with the title including the code
				renderVariables := &OauthRenderVariables{Code: data["code"].(string), State: data["state"].(string)}

				if err := authorizeLocalAppTemplate.Execute(w, renderVariables); err != nil {
					c.Criticalf("Error executing template [%s]", authorizeLocalAppTemplate.Name())
					http.Error(w, err.Error(), http.StatusInternalServerError)
				}
			} else {
				redirectUrl := fmt.Sprintf("%s?code=%s&state=%s", resp.URL, data["code"].(string), data["state"].(string))
				c.Infof("Redirecting to [%s] with valid code.", redirectUrl)
				http.Redirect(w, req, redirectUrl, 200)
				return
			}
		}
		if resp.IsError && resp.InternalError != nil {
			c.Debugf("ERROR: %s\n", resp.InternalError)
		}
		c.Debugf("Writing response: %v", resp.Output)
		osin.OutputJSON(resp, w, req)
	})

	// Access token endpoint
	muxRouter.Get(TOKEN_ROUTE).HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		c := appengine.NewContext(req)
		resp := server.NewResponse()
		req.ParseForm()
		if _, _, ok := req.BasicAuth(); !ok {
			req.SetBasicAuth(req.Form.Get("client_id"), req.Form.Get("client_secret"))
		}
		c.Debugf("Processing token request: %v with form [%v]", req, req.PostForm)
		if ar := server.HandleAccessRequest(resp, req); ar != nil {
			c.Debugf("Retrieved authorize data [%v]", ar)
			ar.Authorized = true
			server.FinishAccessRequest(resp, req, ar)
		}
		c.Debugf("Writing response: %v", resp.Output)
		osin.OutputJSON(resp, w, req)
	})
	context := appengine.NewContext(request)
	context.Debugf("Oauth server loaded: [%v]", server)
}

func (handler *oauthAuthenticatedHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	c := appengine.NewContext(request)
	request.ParseForm()
	c.Debugf("Checking authentication for request [%s]...", request.RequestURI)

	ret := server.NewResponse()
	authorizationValue := request.Header.Get("Authorization")
	if authorizationValue == "" {
		ret.SetError(osin.E_INVALID_REQUEST, "Empty authorization")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	accessCode := strings.TrimPrefix(authorizationValue, "Bearer ")
	if accessCode == "" {
		ret.SetError(osin.E_INVALID_REQUEST, "Empty authorization value")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	var err error

	// load access data
	accessData, err := server.Storage.LoadAccess(accessCode, request)
	if err != nil {
		ret.SetError(osin.E_INVALID_REQUEST, fmt.Sprintf("Error loading access data for code [%s]: [%v]", accessCode, err))
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}
	if accessData.Client == nil {
		ret.SetError(osin.E_UNAUTHORIZED_CLIENT, "")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}
	if accessData.Client.RedirectUri == "" {
		ret.SetError(osin.E_UNAUTHORIZED_CLIENT, "")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}
	if accessData.IsExpired() {
		ret.SetError(osin.E_INVALID_GRANT, "")
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	if ret.IsError {
		ret.StatusCode = 403
		osin.OutputJSON(ret, writer, request)
		return
	}

	handler.authenticatedHandler.ServeHTTP(writer, request)
}

func newOauthAuthenticationHandler(next http.Handler) *oauthAuthenticatedHandler {
	return &oauthAuthenticatedHandler{next}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package chaincfg

import (
	"testing"
)

var (
	consecMask = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0xa, // 0b1010 XXX not consecutive mask
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	tooManyChoices = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
			{
				Id:          "Maybe",
				Description: "Vote for Pedro",
				Bits:        0x6, // 0b0110
				IsAbstain:   false,
				IsNo:        false,
			},
			// XXX here we go out of mask bounds
			{
				Id:          "Hmmmm",
				Description: "Vote for Pedro",
				Bits:        0x6, // 0b0110 XXX invalid bits too
				IsAbstain:   false,
				IsNo:        false,
			},
		},
	}

	notConsec = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			// XXX not consecutive
			{
				Id:          "Maybe",
				Description: "Vote for Pedro",
				Bits:        0x6, // 0b0110
				IsAbstain:   false,
				IsNo:        false,
			},
		},
	}

	invalidAbstain = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0,   // 0b0000
				IsAbstain:   false, // XXX this is the invalid bit
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	invalidVoteBits = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0xc, // 0b1100 XXX invalid bits
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	twoIsAbstain = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2,  // 0b0010
				IsAbstain:   true, // XXX this is the invalid choice
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	twoIsNo = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        true, // XXX this is the invalid choice
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	bothFlags = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2,  // 0b0010
				IsAbstain:   true, // XXX this is the invalid choice
				IsNo:        true, // XXX this is the invalid choice
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	dupChoice = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "Yes", // XXX this is the invalid ID
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}
)

func TestChoices(t *testing.T) {
	tests := []struct {
		name     string
		vote     Vote
		expected error
	}{
		{
			name:     "consecutive mask",
			vote:     consecMask,
			expected: errInvalidMask,
		},
		{
			name:     "not consecutive choices",
			vote:     notConsec,
			expected: errNotConsecutive,
		},
		{
			name:     "too many choices",
			vote:     tooManyChoices,
			expected: errTooManyChoices,
		},
		{
			name:     "invalid ignore",
			vote:     invalidAbstain,
			expected: errInvalidAbstain,
		},
		{
			name:     "invalid vote bits",
			vote:     invalidVoteBits,
			expected: errInvalidBits,
		},
		{
			name:     "2 IsAbstain",
			vote:     twoIsAbstain,
			expected: errInvalidIsAbstain,
		},
		{
			name:     "2 IsNo",
			vote:     twoIsNo,
			expected: errInvalidIsNo,
		},
		{
			name:     "both IsAbstain IsNo",
			vote:     bothFlags,
			expected: errInvalidBothFlags,
		},
		{
			name:     "duplicate choice id",
			vote:     dupChoice,
			expected: errDuplicateChoiceId,
		},
	}

	for _, test := range tests {
		t.Logf("running: %v", test.name)
		err := validateAgenda(test.vote)
		if err != test.expected {
			t.Fatalf("%v: got '%v' expected '%v'", test.name, err,
				test.expected)
		}
	}
}

var (
	dupVote = []ConsensusDeployment{
		{Vote: Vote{Id: "moo"}},
		{Vote: Vote{Id: "moo"}},
	}
)

func TestDeployments(t *testing.T) {
	tests := []struct {
		name        string
		deployments []ConsensusDeployment
		expected    error
	}{
		{
			name:        "duplicate vote id",
			deployments: dupVote,
			expected:    errDuplicateVoteId,
		},
	}

	for _, test := range tests {
		t.Logf("running: %v", test.name)
		_, err := validateDeployments(test.deployments)
		if err != test.expected {
			t.Fatalf("%v: got '%v' expected '%v'", test.name, err,
				test.expected)
		}
	}
}
<commit_msg>chaincfg; Add tests for required unique fields.<commit_after>// Copyright (c) 2017 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package chaincfg

import (
	"testing"

	"github.com/decred/dcrd/wire"
)

var (
	consecMask = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0xa, // 0b1010 XXX not consecutive mask
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	tooManyChoices = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
			{
				Id:          "Maybe",
				Description: "Vote for Pedro",
				Bits:        0x6, // 0b0110
				IsAbstain:   false,
				IsNo:        false,
			},
			// XXX here we go out of mask bounds
			{
				Id:          "Hmmmm",
				Description: "Vote for Pedro",
				Bits:        0x6, // 0b0110 XXX invalid bits too
				IsAbstain:   false,
				IsNo:        false,
			},
		},
	}

	notConsec = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			// XXX not consecutive
			{
				Id:          "Maybe",
				Description: "Vote for Pedro",
				Bits:        0x6, // 0b0110
				IsAbstain:   false,
				IsNo:        false,
			},
		},
	}

	invalidAbstain = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0,   // 0b0000
				IsAbstain:   false, // XXX this is the invalid bit
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	invalidVoteBits = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0xc, // 0b1100 XXX invalid bits
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	twoIsAbstain = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2,  // 0b0010
				IsAbstain:   true, // XXX this is the invalid choice
				IsNo:        false,
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	twoIsNo = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        true, // XXX this is the invalid choice
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	bothFlags = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2,  // 0b0010
				IsAbstain:   true, // XXX this is the invalid choice
				IsNo:        true, // XXX this is the invalid choice
			},
			{
				Id:          "No",
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}

	dupChoice = Vote{
		Id:          "voteforpedro",
		Description: "You should always vote for Pedro",
		Mask:        0x6, // 0b0110
		Choices: []Choice{
			{
				Id:          "Abstain",
				Description: "Abstain voting for Pedro",
				Bits:        0x0, // 0b0000
				IsAbstain:   true,
				IsNo:        false,
			},
			{
				Id:          "Yes",
				Description: "Vote for Pedro",
				Bits:        0x2, // 0b0010
				IsAbstain:   false,
				IsNo:        false,
			},
			{
				Id:          "Yes", // XXX this is the invalid ID
				Description: "Dont vote for Pedro",
				Bits:        0x4, // 0b0100
				IsAbstain:   false,
				IsNo:        true,
			},
		},
	}
)

func TestChoices(t *testing.T) {
	tests := []struct {
		name     string
		vote     Vote
		expected error
	}{
		{
			name:     "consecutive mask",
			vote:     consecMask,
			expected: errInvalidMask,
		},
		{
			name:     "not consecutive choices",
			vote:     notConsec,
			expected: errNotConsecutive,
		},
		{
			name:     "too many choices",
			vote:     tooManyChoices,
			expected: errTooManyChoices,
		},
		{
			name:     "invalid ignore",
			vote:     invalidAbstain,
			expected: errInvalidAbstain,
		},
		{
			name:     "invalid vote bits",
			vote:     invalidVoteBits,
			expected: errInvalidBits,
		},
		{
			name:     "2 IsAbstain",
			vote:     twoIsAbstain,
			expected: errInvalidIsAbstain,
		},
		{
			name:     "2 IsNo",
			vote:     twoIsNo,
			expected: errInvalidIsNo,
		},
		{
			name:     "both IsAbstain IsNo",
			vote:     bothFlags,
			expected: errInvalidBothFlags,
		},
		{
			name:     "duplicate choice id",
			vote:     dupChoice,
			expected: errDuplicateChoiceId,
		},
	}

	for _, test := range tests {
		t.Logf("running: %v", test.name)
		err := validateAgenda(test.vote)
		if err != test.expected {
			t.Fatalf("%v: got '%v' expected '%v'", test.name, err,
				test.expected)
		}
	}
}

var (
	dupVote = []ConsensusDeployment{
		{Vote: Vote{Id: "moo"}},
		{Vote: Vote{Id: "moo"}},
	}
)

func TestDeployments(t *testing.T) {
	tests := []struct {
		name        string
		deployments []ConsensusDeployment
		expected    error
	}{
		{
			name:        "duplicate vote id",
			deployments: dupVote,
			expected:    errDuplicateVoteId,
		},
	}

	for _, test := range tests {
		t.Logf("running: %v", test.name)
		_, err := validateDeployments(test.deployments)
		if err != test.expected {
			t.Fatalf("%v: got '%v' expected '%v'", test.name, err,
				test.expected)
		}
	}
}

// allDefaultNetParams returns the parameters for all of the default networks
// for use in the tests.
func allDefaultNetParams() []*Params {
	return []*Params{&MainNetParams, &TestNet3Params, &SimNetParams,
		&RegNetParams}
}

// TestRequiredUnique ensures that the network parameter fields that are
// required to be unique are in fact unique for all of the provided default
// parameters.
func TestRequiredUnique(t *testing.T) {
	var (
		netMagics         = make(map[wire.CurrencyNet]struct{})
		netPrefixes       = make(map[string]struct{})
		pubKeyAddrIDs     = make(map[[2]byte]struct{})
		pubKeyHashAddrIDs = make(map[[2]byte]struct{})
		pkhEdwardsAddrIDs = make(map[[2]byte]struct{})
		pkhSchnorrAddrIDs = make(map[[2]byte]struct{})
		scriptHashAddrIDs = make(map[[2]byte]struct{})
	)

	for _, params := range allDefaultNetParams() {
		if _, ok := netMagics[params.Net]; ok {
			t.Fatalf("%q: duplicate network magic %x", params.Name,
				params.Net)
		}
		netMagics[params.Net] = struct{}{}

		if _, ok := netPrefixes[params.NetworkAddressPrefix]; ok {
			t.Fatalf("%q: duplicate network address prefix %s", params.Name,
				params.NetworkAddressPrefix)
		}
		netPrefixes[params.Name] = struct{}{}

		if _, ok := pubKeyAddrIDs[params.PubKeyAddrID]; ok {
			t.Fatalf("%q: duplicate pubkey addr ID %x", params.Name,
				params.PubKeyAddrID)
		}
		pubKeyAddrIDs[params.PubKeyAddrID] = struct{}{}

		if _, ok := pubKeyHashAddrIDs[params.PubKeyHashAddrID]; ok {
			t.Fatalf("%q: duplicate pubkey hash addr ID %x", params.Name,
				params.PubKeyHashAddrID)
		}
		pubKeyHashAddrIDs[params.PubKeyHashAddrID] = struct{}{}

		if _, ok := pkhEdwardsAddrIDs[params.PKHEdwardsAddrID]; ok {
			t.Fatalf("%q: duplicate edwards pubkey hash addr ID %x",
				params.Name, params.PKHEdwardsAddrID)
		}
		pkhEdwardsAddrIDs[params.PKHEdwardsAddrID] = struct{}{}

		if _, ok := pkhSchnorrAddrIDs[params.PKHSchnorrAddrID]; ok {
			t.Fatalf("%q: duplicate schnorr pubkey hash addr ID %x",
				params.Name, params.PKHSchnorrAddrID)
		}
		pkhSchnorrAddrIDs[params.PKHSchnorrAddrID] = struct{}{}

		if _, ok := scriptHashAddrIDs[params.ScriptHashAddrID]; ok {
			t.Fatalf("%q: duplicate script hash addr ID %x", params.Name,
				params.ScriptHashAddrID)
		}
		scriptHashAddrIDs[params.ScriptHashAddrID] = struct{}{}
	}
}
<|endoftext|>


<commit_before>package main

import (
	zmq "github.com/pebbe/zmq4"
	"github.com/anchor/chevalier"
	"github.com/anchor/picolog"
	"syscall"
)

var IndexerLogger *picolog.Logger

func fullUpdate(w *chevalier.ElasticsearchWriter, endpoint string, origins []string) {
	indexed := 0
	for _, o := range origins {
		// We want to retry if we get interrupted.
		var err error
		var burst *chevalier.DataSourceBurst
		err = syscall.EAGAIN
		for err == syscall.EAGAIN || err == syscall.EINTR {
			burst, err = chevalier.GetContents(endpoint, o)
		}
		if err != nil {
			IndexerLogger.Errorf("Could not read contents for origin %v: %v", o, err)
			continue
		}
		for _, s := range burst.Sources {
			err = w.Write(o, s)
			if err != nil {
				IndexerLogger.Errorf("Could not index source: %v", err)
			} else {
				indexed += 1
			}
		}
	}
	IndexerLogger.Infof("Indexed %v sources.", indexed)
}

func subscribeUpdate(endpoint string) error {
	sock, err := zmq.NewSocket(zmq.SUB)
	if err != nil {
		return err
	}
	sock.SetSubscribe("")
	sock.Connect(endpoint)
	return nil
}

func getElasticsearchWriter(cfg Config) *chevalier.ElasticsearchWriter {
	writer := chevalier.NewElasticsearchWriter(cfg.Elasticsearch.Host, cfg.Elasticsearch.MaxConns, cfg.Elasticsearch.RetrySeconds, cfg.Elasticsearch.DataType, cfg.Elasticsearch.DataType)
	return writer
}

func RunIndexerOnce(cfg Config) {
	IndexerLogger = Logger.NewSubLogger("indexer")
	IndexerLogger.Infof("Starting single indexer run.")
	writer := getElasticsearchWriter(cfg)
	fullUpdate(writer, cfg.Vaultaire.ReadEndpoint, cfg.Vaultaire.Origins)
}

func RunIndexer(cfg Config) {
	Logger.Infof("Starting chevalierd %v in indexer mode.", Version)
	IndexerLogger = Logger.NewSubLogger("indexer")
	writer := getElasticsearchWriter(cfg)
	for {
		IndexerLogger.Infof("Starting run.")
		fullUpdate(writer, cfg.Vaultaire.ReadEndpoint, cfg.Vaultaire.Origins)
	}
}
<commit_msg>Log when we request each origin<commit_after>package main

import (
	zmq "github.com/pebbe/zmq4"
	"github.com/anchor/chevalier"
	"github.com/anchor/picolog"
	"syscall"
)

var IndexerLogger *picolog.Logger

func fullUpdate(w *chevalier.ElasticsearchWriter, endpoint string, origins []string) {
	indexed := 0
	for _, o := range origins {
		IndexerLogger.Infof("Requesting sources for origin %v.", o)
		// We want to retry if we get interrupted.
		var err error
		var burst *chevalier.DataSourceBurst
		err = syscall.EAGAIN
		for err == syscall.EAGAIN || err == syscall.EINTR {
			burst, err = chevalier.GetContents(endpoint, o)
		}
		if err != nil {
			IndexerLogger.Errorf("Could not read contents for origin %v: %v", o, err)
			continue
		}
		for _, s := range burst.Sources {
			err = w.Write(o, s)
			if err != nil {
				IndexerLogger.Errorf("Could not index source: %v", err)
			} else {
				indexed += 1
			}
		}
	}
	IndexerLogger.Infof("Indexed %v sources.", indexed)
}

func subscribeUpdate(endpoint string) error {
	sock, err := zmq.NewSocket(zmq.SUB)
	if err != nil {
		return err
	}
	sock.SetSubscribe("")
	sock.Connect(endpoint)
	return nil
}

func getElasticsearchWriter(cfg Config) *chevalier.ElasticsearchWriter {
	writer := chevalier.NewElasticsearchWriter(cfg.Elasticsearch.Host, cfg.Elasticsearch.MaxConns, cfg.Elasticsearch.RetrySeconds, cfg.Elasticsearch.DataType, cfg.Elasticsearch.DataType)
	return writer
}

func RunIndexerOnce(cfg Config) {
	IndexerLogger = Logger.NewSubLogger("indexer")
	IndexerLogger.Infof("Starting single indexer run.")
	writer := getElasticsearchWriter(cfg)
	fullUpdate(writer, cfg.Vaultaire.ReadEndpoint, cfg.Vaultaire.Origins)
}

func RunIndexer(cfg Config) {
	Logger.Infof("Starting chevalierd %v in indexer mode.", Version)
	IndexerLogger = Logger.NewSubLogger("indexer")
	writer := getElasticsearchWriter(cfg)
	for {
		IndexerLogger.Infof("Starting run.")
		fullUpdate(writer, cfg.Vaultaire.ReadEndpoint, cfg.Vaultaire.Origins)
	}
}
<|endoftext|>


<commit_before>package connection

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestParse(t *testing.T) {
	Convey("Check connection", t, func() {
		db := MustGet()
		So(db, ShouldNotBeNil)
		err := db.Ping()
		So(err, ShouldBeNil)
	})
}
<commit_msg>rename test to a better name<commit_after>package connection

import (
	"testing"

	. "github.com/smartystreets/goconvey/convey"
)

func TestMustGet(t *testing.T) {
	Convey("Check connection", t, func() {
		db := MustGet()
		So(db, ShouldNotBeNil)
		err := db.Ping()
		So(err, ShouldBeNil)
	})
}
<|endoftext|>


<commit_before>// Package datamatrix can create Datamatrix barcodes
package datamatrix

import (
	"errors"

	"github.com/boombuler/barcode"
)

// Encode returns a Datamatrix barcode for the given content
func Encode(content string) (barcode.Barcode, error) {
	data := encodeText(content)

	var size *dmCodeSize
	for _, s := range codeSizes {
		if s.DataCodewords() >= len(data) {
			size = s
			break
		}
	}
	if size == nil {
		return nil, errors.New("to much data to encode")
	}
	data = addPadding(data, size.DataCodewords())
	data = ec.calcECC(data, size)
	code := render(data, size)
	if code != nil {
		code.content = content
		return code, nil
	}
	return nil, errors.New("unable to render barcode")
}

func render(data []byte, size *dmCodeSize) *datamatrixCode {
	cl := newCodeLayout(size)

	cl.SetValues(data)

	return cl.Merge()
}

func encodeText(content string) []byte {
	var result []byte
	input := []byte(content)

	for i := 0; i < len(input); {
		c := input[i]
		i++

		if c >= '0' && c <= '9' && i < len(input) && input[i] >= '0' && input[i] <= '9' {
			// two numbers...
			c2 := input[i]
			i++
			cw := byte(((c-'0')*10 + (c2 - '0')) + 130)
			result = append(result, cw)
		} else if c > 127 {
			// not correct... needs to be redone later...
			result = append(result, 235, c-127)
		} else {
			result = append(result, c+1)
		}
	}
	return result
}

func addPadding(data []byte, toCount int) []byte {
	if len(data) < toCount {
		data = append(data, 129)
	}
	for len(data) < toCount {
		R := ((149 * (len(data) + 1)) % 253) + 1
		data = append(data, byte((129+R)%254))
	}
	return data
}
<commit_msg>Fix bug in DataMatrix padding algorithm<commit_after>// Package datamatrix can create Datamatrix barcodes
package datamatrix

import (
	"errors"

	"github.com/boombuler/barcode"
)

// Encode returns a Datamatrix barcode for the given content
func Encode(content string) (barcode.Barcode, error) {
	data := encodeText(content)

	var size *dmCodeSize
	for _, s := range codeSizes {
		if s.DataCodewords() >= len(data) {
			size = s
			break
		}
	}
	if size == nil {
		return nil, errors.New("to much data to encode")
	}
	data = addPadding(data, size.DataCodewords())
	data = ec.calcECC(data, size)
	code := render(data, size)
	if code != nil {
		code.content = content
		return code, nil
	}
	return nil, errors.New("unable to render barcode")
}

func render(data []byte, size *dmCodeSize) *datamatrixCode {
	cl := newCodeLayout(size)

	cl.SetValues(data)

	return cl.Merge()
}

func encodeText(content string) []byte {
	var result []byte
	input := []byte(content)

	for i := 0; i < len(input); {
		c := input[i]
		i++

		if c >= '0' && c <= '9' && i < len(input) && input[i] >= '0' && input[i] <= '9' {
			// two numbers...
			c2 := input[i]
			i++
			cw := byte(((c-'0')*10 + (c2 - '0')) + 130)
			result = append(result, cw)
		} else if c > 127 {
			// not correct... needs to be redone later...
			result = append(result, 235, c-127)
		} else {
			result = append(result, c+1)
		}
	}
	return result
}

func addPadding(data []byte, toCount int) []byte {
	if len(data) < toCount {
		data = append(data, 129)
	}
	for len(data) < toCount {
		R := ((149 * (len(data) + 1)) % 253) + 1
		tmp := 129 + R;
		if (tmp > 254) {
			tmp = tmp - 254
		}

		data = append(data, byte(tmp))
	}
	return data
}
<|endoftext|>


<commit_before>package systray

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"syscall"
	"unsafe"
)

var (
	iconFiles = make([]*os.File, 0)
	dllDir    = path.Join(os.Getenv("APPDATA"), "systray")
	dllFile   = path.Join(dllDir, "systray.dll")

	mod                      = syscall.NewLazyDLL(dllFile)
	_nativeLoop              = mod.NewProc("nativeLoop")
	_quit                    = mod.NewProc("quit")
	_setIcon                 = mod.NewProc("setIcon")
	_setTitle                = mod.NewProc("setTitle")
	_setTooltip              = mod.NewProc("setTooltip")
	_add_or_update_menu_item = mod.NewProc("add_or_update_menu_item")
)

func init() {
	// Write DLL to file
	b, err := Asset("systray.dll")
	if err != nil {
		panic(fmt.Errorf("Unable to read systray.dll: %v", err))
	}

	err = os.MkdirAll(dllDir, 0755)
	if err != nil {
		panic(fmt.Errorf("Unable to create directory %v to hold systray.dll: %v", dllDir, err))
	}

	err = ioutil.WriteFile(dllFile, b, 0644)
	if err != nil {
		panic(fmt.Errorf("Unable to save systray.dll to %v: %v", dllFile, err))
	}
}

func nativeLoop() {
	_nativeLoop.Call(
		syscall.NewCallbackCDecl(systray_ready),
		syscall.NewCallbackCDecl(systray_menu_item_selected))
}

func quit() {
	_quit.Call()
	for _, f := range iconFiles {
		err := os.Remove(f.Name())
		if err != nil {
			log.Debugf("Unable to delete temporary icon file %v: %v", f.Name(), err)
		}
	}
}

// SetIcon sets the systray icon.
// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
// for other platforms.
func SetIcon(iconBytes []byte) {
	f, err := ioutil.TempFile("", "systray_temp_icon")
	if err != nil {
		log.Errorf("Unable to create temp icon: %v", err)
		return
	}
	defer f.Close()
	_, err = f.Write(iconBytes)
	if err != nil {
		log.Errorf("Unable to write icon to temp file %v: %v", f.Name(), f)
		return
	}
	// Need to close file before we load it to make sure contents is flushed.
	f.Close()
	u16, name, err := strPtr(f.Name())
	if err != nil {
		log.Errorf("Unable to convert name to string pointer: %v", err)
		return
	}
	_setIcon.Call(name)
	noop(u16)
}

// SetTitle sets the systray title, only available on Mac.
func SetTitle(title string) {
	// do nothing
}

// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
// only available on Mac and Windows.
func SetTooltip(tooltip string) {
	u16, t, err := strPtr(tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_setTooltip.Call(t)
	noop(u16)
}

func addOrUpdateMenuItem(item *MenuItem) {
	var disabled = 0
	if item.disabled {
		disabled = 1
	}
	var checked = 0
	if item.checked {
		checked = 1
	}
	u16a, title, err := strPtr(item.title)
	if err != nil {
		log.Errorf("Unable to convert title to string pointer: %v", err)
		return
	}
	u16b, tooltip, err := strPtr(item.tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_add_or_update_menu_item.Call(
		uintptr(item.id),
		title,
		tooltip,
		uintptr(disabled),
		uintptr(checked),
	)
	noop(u16a)
	noop(u16b)
}

// strPrt converts a Go string into a wchar_t*
func strPtr(s string) ([]uint16, uintptr, error) {
	u16, err := syscall.UTF16FromString(s)
	if err != nil {
		return nil, 0, err
	}
	return u16, uintptr(unsafe.Pointer(&u16[0])), nil
}

// noop does nothing. We just call it so that we're doing something with the u16
// variable, which we just hang on to to prevent it being gc'd.
func noop(u16 []uint16) {
	// do nothing
}

// systray_ready takes an ignored parameter just so we can compile a callback
// (for some reason in Go 1.4.x, syscall.NewCallback panics if there's no
// parameter to the function).
func systray_ready(ignore uintptr) uintptr {
	systrayReady()
	return 0
}

func systray_menu_item_selected(id uintptr) uintptr {
	systrayMenuItemSelected(int32(id))
	return 0
}
<commit_msg>Added comment to strPtr<commit_after>package systray

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"syscall"
	"unsafe"
)

var (
	iconFiles = make([]*os.File, 0)
	dllDir    = path.Join(os.Getenv("APPDATA"), "systray")
	dllFile   = path.Join(dllDir, "systray.dll")

	mod                      = syscall.NewLazyDLL(dllFile)
	_nativeLoop              = mod.NewProc("nativeLoop")
	_quit                    = mod.NewProc("quit")
	_setIcon                 = mod.NewProc("setIcon")
	_setTitle                = mod.NewProc("setTitle")
	_setTooltip              = mod.NewProc("setTooltip")
	_add_or_update_menu_item = mod.NewProc("add_or_update_menu_item")
)

func init() {
	// Write DLL to file
	b, err := Asset("systray.dll")
	if err != nil {
		panic(fmt.Errorf("Unable to read systray.dll: %v", err))
	}

	err = os.MkdirAll(dllDir, 0755)
	if err != nil {
		panic(fmt.Errorf("Unable to create directory %v to hold systray.dll: %v", dllDir, err))
	}

	err = ioutil.WriteFile(dllFile, b, 0644)
	if err != nil {
		panic(fmt.Errorf("Unable to save systray.dll to %v: %v", dllFile, err))
	}
}

func nativeLoop() {
	_nativeLoop.Call(
		syscall.NewCallbackCDecl(systray_ready),
		syscall.NewCallbackCDecl(systray_menu_item_selected))
}

func quit() {
	_quit.Call()
	for _, f := range iconFiles {
		err := os.Remove(f.Name())
		if err != nil {
			log.Debugf("Unable to delete temporary icon file %v: %v", f.Name(), err)
		}
	}
}

// SetIcon sets the systray icon.
// iconBytes should be the content of .ico for windows and .ico/.jpg/.png
// for other platforms.
func SetIcon(iconBytes []byte) {
	f, err := ioutil.TempFile("", "systray_temp_icon")
	if err != nil {
		log.Errorf("Unable to create temp icon: %v", err)
		return
	}
	defer f.Close()
	_, err = f.Write(iconBytes)
	if err != nil {
		log.Errorf("Unable to write icon to temp file %v: %v", f.Name(), f)
		return
	}
	// Need to close file before we load it to make sure contents is flushed.
	f.Close()
	u16, name, err := strPtr(f.Name())
	if err != nil {
		log.Errorf("Unable to convert name to string pointer: %v", err)
		return
	}
	_setIcon.Call(name)
	noop(u16)
}

// SetTitle sets the systray title, only available on Mac.
func SetTitle(title string) {
	// do nothing
}

// SetTooltip sets the systray tooltip to display on mouse hover of the tray icon,
// only available on Mac and Windows.
func SetTooltip(tooltip string) {
	u16, t, err := strPtr(tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_setTooltip.Call(t)
	noop(u16)
}

func addOrUpdateMenuItem(item *MenuItem) {
	var disabled = 0
	if item.disabled {
		disabled = 1
	}
	var checked = 0
	if item.checked {
		checked = 1
	}
	u16a, title, err := strPtr(item.title)
	if err != nil {
		log.Errorf("Unable to convert title to string pointer: %v", err)
		return
	}
	u16b, tooltip, err := strPtr(item.tooltip)
	if err != nil {
		log.Errorf("Unable to convert tooltip to string pointer: %v", err)
		return
	}
	_add_or_update_menu_item.Call(
		uintptr(item.id),
		title,
		tooltip,
		uintptr(disabled),
		uintptr(checked),
	)
	noop(u16a)
	noop(u16b)
}

// strPrt converts a Go string into a wchar_t*. It returns the underlying UTF-16
// array, which needs to be referenced until after it's been passed to the DLL
// to avoid it being garbage collected.
func strPtr(s string) ([]uint16, uintptr, error) {
	u16, err := syscall.UTF16FromString(s)
	if err != nil {
		return nil, 0, err
	}
	return u16, uintptr(unsafe.Pointer(&u16[0])), nil
}

// noop does nothing. We just call it so that we're doing something with the u16
// variable, which we just hang on to to prevent it being gc'd.
func noop(u16 []uint16) {
	// do nothing
}

// systray_ready takes an ignored parameter just so we can compile a callback
// (for some reason in Go 1.4.x, syscall.NewCallback panics if there's no
// parameter to the function).
func systray_ready(ignore uintptr) uintptr {
	systrayReady()
	return 0
}

func systray_menu_item_selected(id uintptr) uintptr {
	systrayMenuItemSelected(int32(id))
	return 0
}
<|endoftext|>