<commit_before>// Copyright 2013 M-Lab
//
// 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.

// +build appengine

package data

import (
	"appengine"
	"appengine/datastore"
	"errors"
	"math/rand"
	"net"
)

var (
	ErrNoMatchingSliverTool = errors.New("")
)

func GetSliverToolsWithToolID(c appengine.Context, toolID string) ([]*SliverTool, error) {
	q := datastore.NewQuery("SliverTool").Filter("tool_id =", toolID)
	var slivers []*SliverTool
	if err := QueryData(c, toolID, q, slivers); err != nil {
		return nil, err
	}
	return slivers, nil
}

func GetRandomSliverToolWithToolID(c appengine.Context, toolID string) (*SliverTool, error) {
	slivers, err := GetSliverToolsWithToolID(c, toolID)
	if err != nil {
		return nil, err
	}
	idx := rand.Int() % len(slivers)
	return slivers[idx], nil
}

func GetSiteWithSiteID(c appengine.Context, siteID string) (*Site, error) {
	q := datastore.NewQuery("Site").Filter("site_id =", siteID)
	var site *Site
	if err := QueryData(c, siteID, q, site); err != nil {
		return nil, err
	}
	return site, nil
}

func GetSliverToolWithIP(c appengine.Context, toolID string, ip net.IP) (*SliverTool, error) {
	slivers, err := GetSliverToolsWithToolID(c, toolID)
	if err != nil {
		return nil, err
	}
	for _, s := range slivers {
		if net.IP(s.SliverIPv4).Equal(ip) || net.IP(s.SliverIPv6).Equal(ip) {
			return s, nil
		}
	}
	return nil, ErrNoMatchingSliverTool
}
<commit_msg>Optimise GetSliverToolWithIP just a bit<commit_after>// Copyright 2013 M-Lab
//
// 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.

// +build appengine

package data

import (
	"appengine"
	"appengine/datastore"
	"errors"
	"math/rand"
	"net"
)

var (
	ErrNoMatchingSliverTool = errors.New("")
)

func GetSliverToolsWithToolID(c appengine.Context, toolID string) ([]*SliverTool, error) {
	q := datastore.NewQuery("SliverTool").Filter("tool_id =", toolID)
	var slivers []*SliverTool
	if err := QueryData(c, toolID, q, slivers); err != nil {
		return nil, err
	}
	return slivers, nil
}

func GetRandomSliverToolWithToolID(c appengine.Context, toolID string) (*SliverTool, error) {
	slivers, err := GetSliverToolsWithToolID(c, toolID)
	if err != nil {
		return nil, err
	}
	idx := rand.Int() % len(slivers)
	return slivers[idx], nil
}

func GetSiteWithSiteID(c appengine.Context, siteID string) (*Site, error) {
	q := datastore.NewQuery("Site").Filter("site_id =", siteID)
	var site *Site
	if err := QueryData(c, siteID, q, site); err != nil {
		return nil, err
	}
	return site, nil
}

func GetSliverToolWithIP(c appengine.Context, toolID string, ip net.IP) (*SliverTool, error) {
	slivers, err := GetSliverToolsWithToolID(c, toolID)
	if err != nil {
		return nil, err
	}
	for _, s := range slivers {
		if ip.To4() == nil {
			// ip is IPv6 address
			if net.IP(s.SliverIPv6).Equal(ip) {
				return s, nil
			}
		} else {
			// ip is IPv4 address
			if net.IP(s.SliverIPv4).Equal(ip) {
				return s, nil
			}
		}
	}
	return nil, ErrNoMatchingSliverTool
}
<|endoftext|>


<commit_before>package oauth1

import (
	"crypto"
	crand "crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

// Out-Of-Band mode, used for applications that do not have
// a callback URL, such as mobile phones or command-line
// utilities.
const OOB = "oob"

// Consumer represents a website or application that uses the
// OAuth 1.0a protocol to access protected resources on behalf
// of a User.
type Consumer struct {
	// A value used by the Consumer to identify itself
	// to the Service Provider.
	ConsumerKey string

	// A secret used by the Consumer to establish
	// ownership of the Consumer Key.
	ConsumerSecret string

	// A path to the private pem key used to sign request
	ConsumerPrivateKeyPem string

	// An absolute URL to which the Service Provider will redirect
	// the User back when the Obtaining User Authorization step
	// is completed.
	//
	// If the Consumer is unable to receive callbacks or a callback
	// URL has been established via other means, the parameter
	// value MUST be set to oob (case sensitive), to indicate
	// an out-of-band configuration.
	CallbackURL string

	// The URL used to obtain an unauthorized
	// Request Token.
	RequestTokenURL string

	// The URL used to obtain User authorization
	// for Consumer access.
	AccessTokenURL string

	// The URL used to exchange the User-authorized
	// Request Token for an Access Token.
	AuthorizationURL string
}

func (c *Consumer) RequestToken() (*RequestToken, error) {

	// create the http request to fetch a Request Token.
	requestTokenUrl, _ := url.Parse(c.RequestTokenURL)
	req := http.Request{
		URL:        requestTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, nil, map[string]string{"oauth_callback": c.CallbackURL})
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	requestToken, err := ParseRequestToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return requestToken, nil
}

// AuthorizeRedirect constructs the request URL that should be used
// to redirect the User to verify User identify and consent.
func (c *Consumer) AuthorizeRedirect(t *RequestToken) (string, error) {
	redirect, err := url.Parse(c.AuthorizationURL)
	if err != nil {
		return "", err
	}

	params := make(url.Values)
	params.Add("oauth_token", t.token)
	redirect.RawQuery = params.Encode()

	u := redirect.String()
	if strings.HasPrefix(u, "https://bitbucket.org/%21api/") {
		u = strings.Replace(u, "/%21api/", "/!api/", -1)
	}

	return u, nil
}

func (c *Consumer) AuthorizeToken(t *RequestToken, verifier string) (*AccessToken, error) {

	// create the http request to fetch a Request Token.
	accessTokenUrl, _ := url.Parse(c.AccessTokenURL)
	req := http.Request{
		URL:        accessTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, t, map[string]string{"oauth_verifier": verifier})
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	accessToken, err := ParseAccessToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return accessToken, nil
}

// Sign will sign an http.Request using the provided token.
func (c *Consumer) Sign(req *http.Request, token Token) error {
	return c.SignParams(req, token, nil)
}

// Sign will sign an http.Request using the provided token, and additional
// parameters.
func (c *Consumer) SignParams(req *http.Request, token Token, params map[string]string) error {

	// ensure the parameter map is not nil
	if params == nil {
		params = map[string]string{}
	}

	// ensure default parameters are set
	//params["oauth_token"] = token.Token()
	params["oauth_consumer_key"] = c.ConsumerKey
	params["oauth_nonce"] = nonce()
	params["oauth_signature_method"] = "RSA-SHA1"
	params["oauth_timestamp"] = timestamp()
	params["oauth_version"] = "1.0"

	// we'll need to sign any form values?
	if req.Form != nil {
		for k, _ := range req.Form {
			params[k] = req.Form.Get(k)
		}
	}

	// we'll also need to sign any URL parameter
	queryParams := req.URL.Query()
	for k, _ := range queryParams {
		params[k] = queryParams.Get(k)
	}

	//var tokenSecret string
	if token != nil {
		//tokenSecret = token.Secret()
		params["oauth_token"] = token.Token()
	}

	// create the oauth signature
	//key := escape(c.ConsumerSecret) + "&" + escape(tokenSecret)
	key := c.ConsumerPrivateKeyPem
	base := requestString(req.Method, req.URL.String(), params)
	params["oauth_signature"] = sign(base, key)

	//HACK: we were previously including params in the Authorization
	//      header that shouldn't be. so for now, we'll filter
	//authStringParams := map[string]string{}
	//for k,v := range params {
	//	if strings.HasPrefix(k, "oauth_") {
	//		authStringParams[k]=v
	//	}
	//}

	// ensure the http.Request's Header is not nil
	if req.Header == nil {
		req.Header = http.Header{}
	}

	// add the authorization header string
	req.Header.Add("Authorization", authorizationString(params)) //params))

	// ensure the appropriate content-type is set for POST,
	// assuming the field is not populated
	if (req.Method == "POST" || req.Method == "PUT") && len(req.Header.Get("Content-Type")) == 0 {
		req.Header.Set("Content-Type", "application/json")
	}

	return nil
}

// -----------------------------------------------------------------------------
// Private Helper Functions

// Nonce generator, seeded with current time
var nonceGenerator = rand.New(rand.NewSource(time.Now().Unix()))

// Nonce generates a random string. Nonce's are uniquely generated
// for each request.
func nonce() string {
	return strconv.FormatInt(nonceGenerator.Int63(), 10)
}

// Timestamp generates a timestamp, expressed in the number of seconds
// since January 1, 1970 00:00:00 GMT.
func timestamp() string {
	return strconv.FormatInt(time.Now().Unix(), 10)
}

// Generates an RSA SHA1 Signature for an OAuth1.0a request.
func sign(message, key string) string {
	privateKeyBytes, _ := ioutil.ReadFile(key)
	block, _ := pem.Decode(privateKeyBytes)
	privateInterface, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
	privateKey, _ := privateInterface.(*rsa.PrivateKey)

	hashfun := sha1.New()
	hashfun.Write([]byte(message))
	rawsignature := hashfun.Sum(nil)

	cipher, _ := rsa.SignPKCS1v15(crand.Reader, privateKey, crypto.SHA1,
		rawsignature)

	base64signature := make([]byte, base64.StdEncoding.EncodedLen(len(cipher)))
	base64.StdEncoding.Encode(base64signature, cipher)

	return string(base64signature)
}

// Gets the default set of OAuth1.0a headers.
func headers(consumerKey string) map[string]string {
	return map[string]string{
		"oauth_consumer_key":     consumerKey,
		"oauth_nonce":            nonce(),
		"oauth_signature_method": "RSA-SHA1",
		"oauth_timestamp":        timestamp(),
		"oauth_version":          "1.0",
	}
}

func requestString(method string, uri string, params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	result := method + "&" + escape(uri)

	// loop through sorted params and append to the string
	for pos, key := range keys {
		if pos == 0 {
			result += "&"
		} else {
			result += escape("&")
		}

		result += escape(fmt.Sprintf("%s=%s", key, escape(params[key])))
	}

	return result
}

func authorizationString(params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	var str string
	var cnt = 0

	// loop through sorted params and append to the string
	for _, key := range keys {

		// we previously encoded all params (url params, form data & oauth params)
		// but for the authorization string we should only encode the oauth params
		if !strings.HasPrefix(key, "oauth_") {
			continue
		}

		if cnt > 0 {
			str += ","
		}

		str += fmt.Sprintf("%s=%q", key, escape(params[key]))
		cnt++
	}

	return fmt.Sprintf("OAuth %s", str)
}

func escape(s string) string {
	t := make([]byte, 0, 3*len(s))
	for i := 0; i < len(s); i++ {
		c := s[i]
		if isEscapable(c) {
			t = append(t, '%')
			t = append(t, "0123456789ABCDEF"[c>>4])
			t = append(t, "0123456789ABCDEF"[c&15])
		} else {
			t = append(t, s[i])
		}
	}
	return string(t)
}

func isEscapable(b byte) bool {
	return !('A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' || b == '-' || b == '.' || b == '_' || b == '~')

}
<commit_msg>oauth1 signing is against url without query params<commit_after>package oauth1

import (
	"crypto"
	crand "crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

// Out-Of-Band mode, used for applications that do not have
// a callback URL, such as mobile phones or command-line
// utilities.
const OOB = "oob"

// Consumer represents a website or application that uses the
// OAuth 1.0a protocol to access protected resources on behalf
// of a User.
type Consumer struct {
	// A value used by the Consumer to identify itself
	// to the Service Provider.
	ConsumerKey string

	// A secret used by the Consumer to establish
	// ownership of the Consumer Key.
	ConsumerSecret string

	// A path to the private pem key used to sign request
	ConsumerPrivateKeyPem string

	// An absolute URL to which the Service Provider will redirect
	// the User back when the Obtaining User Authorization step
	// is completed.
	//
	// If the Consumer is unable to receive callbacks or a callback
	// URL has been established via other means, the parameter
	// value MUST be set to oob (case sensitive), to indicate
	// an out-of-band configuration.
	CallbackURL string

	// The URL used to obtain an unauthorized
	// Request Token.
	RequestTokenURL string

	// The URL used to obtain User authorization
	// for Consumer access.
	AccessTokenURL string

	// The URL used to exchange the User-authorized
	// Request Token for an Access Token.
	AuthorizationURL string
}

func (c *Consumer) RequestToken() (*RequestToken, error) {

	// create the http request to fetch a Request Token.
	requestTokenUrl, _ := url.Parse(c.RequestTokenURL)
	req := http.Request{
		URL:        requestTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, nil, map[string]string{"oauth_callback": c.CallbackURL})
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	requestToken, err := ParseRequestToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return requestToken, nil
}

// AuthorizeRedirect constructs the request URL that should be used
// to redirect the User to verify User identify and consent.
func (c *Consumer) AuthorizeRedirect(t *RequestToken) (string, error) {
	redirect, err := url.Parse(c.AuthorizationURL)
	if err != nil {
		return "", err
	}

	params := make(url.Values)
	params.Add("oauth_token", t.token)
	redirect.RawQuery = params.Encode()

	u := redirect.String()
	if strings.HasPrefix(u, "https://bitbucket.org/%21api/") {
		u = strings.Replace(u, "/%21api/", "/!api/", -1)
	}

	return u, nil
}

func (c *Consumer) AuthorizeToken(t *RequestToken, verifier string) (*AccessToken, error) {

	// create the http request to fetch a Request Token.
	accessTokenUrl, _ := url.Parse(c.AccessTokenURL)
	req := http.Request{
		URL:        accessTokenUrl,
		Method:     "POST",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Close:      true,
	}

	// sign the request
	err := c.SignParams(&req, t, map[string]string{"oauth_verifier": verifier})
	if err != nil {
		return nil, err
	}

	// make the http request and get the response
	resp, err := http.DefaultClient.Do(&req)
	if err != nil {
		return nil, err
	}

	// parse the Request's Body
	accessToken, err := ParseAccessToken(resp.Body)
	if err != nil {
		return nil, err
	}

	return accessToken, nil
}

// Sign will sign an http.Request using the provided token.
func (c *Consumer) Sign(req *http.Request, token Token) error {
	return c.SignParams(req, token, nil)
}

// Sign will sign an http.Request using the provided token, and additional
// parameters.
func (c *Consumer) SignParams(req *http.Request, token Token, params map[string]string) error {

	// ensure the parameter map is not nil
	if params == nil {
		params = map[string]string{}
	}

	// ensure default parameters are set
	//params["oauth_token"] = token.Token()
	params["oauth_consumer_key"] = c.ConsumerKey
	params["oauth_nonce"] = nonce()
	params["oauth_signature_method"] = "RSA-SHA1"
	params["oauth_timestamp"] = timestamp()
	params["oauth_version"] = "1.0"

	// we'll need to sign any form values?
	if req.Form != nil {
		for k, _ := range req.Form {
			params[k] = req.Form.Get(k)
		}
	}

	// we'll also need to sign any URL parameter
	queryParams := req.URL.Query()
	for k, _ := range queryParams {
		params[k] = queryParams.Get(k)
	}

	//var tokenSecret string
	if token != nil {
		//tokenSecret = token.Secret()
		params["oauth_token"] = token.Token()
	}

	// create the oauth signature
	//key := escape(c.ConsumerSecret) + "&" + escape(tokenSecret)
	key := c.ConsumerPrivateKeyPem
	url := fmt.Sprintf("%s://%s%s", req.URL.Scheme, req.URL.Host, req.URL.Path)
	base := requestString(req.Method, url, params)
	params["oauth_signature"] = sign(base, key)

	//HACK: we were previously including params in the Authorization
	//      header that shouldn't be. so for now, we'll filter
	//authStringParams := map[string]string{}
	//for k,v := range params {
	//	if strings.HasPrefix(k, "oauth_") {
	//		authStringParams[k]=v
	//	}
	//}

	// ensure the http.Request's Header is not nil
	if req.Header == nil {
		req.Header = http.Header{}
	}

	// add the authorization header string
	req.Header.Add("Authorization", authorizationString(params)) //params))

	// ensure the appropriate content-type is set for POST,
	// assuming the field is not populated
	if (req.Method == "POST" || req.Method == "PUT") && len(req.Header.Get("Content-Type")) == 0 {
		req.Header.Set("Content-Type", "application/json")
	}

	return nil
}

// -----------------------------------------------------------------------------
// Private Helper Functions

// Nonce generator, seeded with current time
var nonceGenerator = rand.New(rand.NewSource(time.Now().Unix()))

// Nonce generates a random string. Nonce's are uniquely generated
// for each request.
func nonce() string {
	return strconv.FormatInt(nonceGenerator.Int63(), 10)
}

// Timestamp generates a timestamp, expressed in the number of seconds
// since January 1, 1970 00:00:00 GMT.
func timestamp() string {
	return strconv.FormatInt(time.Now().Unix(), 10)
}

// Generates an RSA SHA1 Signature for an OAuth1.0a request.
func sign(message, key string) string {
	privateKeyBytes, _ := ioutil.ReadFile(key)
	block, _ := pem.Decode(privateKeyBytes)
	privateInterface, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
	privateKey, _ := privateInterface.(*rsa.PrivateKey)

	hashfun := sha1.New()
	hashfun.Write([]byte(message))
	rawsignature := hashfun.Sum(nil)

	cipher, _ := rsa.SignPKCS1v15(crand.Reader, privateKey, crypto.SHA1,
		rawsignature)

	base64signature := make([]byte, base64.StdEncoding.EncodedLen(len(cipher)))
	base64.StdEncoding.Encode(base64signature, cipher)

	return string(base64signature)
}

// Gets the default set of OAuth1.0a headers.
func headers(consumerKey string) map[string]string {
	return map[string]string{
		"oauth_consumer_key":     consumerKey,
		"oauth_nonce":            nonce(),
		"oauth_signature_method": "RSA-SHA1",
		"oauth_timestamp":        timestamp(),
		"oauth_version":          "1.0",
	}
}

func requestString(method string, uri string, params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	result := method + "&" + escape(uri)

	// loop through sorted params and append to the string
	for pos, key := range keys {
		if pos == 0 {
			result += "&"
		} else {
			result += escape("&")
		}

		result += escape(fmt.Sprintf("%s=%s", key, escape(params[key])))
	}

	return result
}

func authorizationString(params map[string]string) string {

	// loop through params, add keys to map
	var keys []string
	for key, _ := range params {
		keys = append(keys, key)
	}

	// sort the array of header keys
	sort.StringSlice(keys).Sort()

	// create the signed string
	var str string
	var cnt = 0

	// loop through sorted params and append to the string
	for _, key := range keys {

		// we previously encoded all params (url params, form data & oauth params)
		// but for the authorization string we should only encode the oauth params
		if !strings.HasPrefix(key, "oauth_") {
			continue
		}

		if cnt > 0 {
			str += ","
		}

		str += fmt.Sprintf("%s=%q", key, escape(params[key]))
		cnt++
	}

	return fmt.Sprintf("OAuth %s", str)
}

func escape(s string) string {
	t := make([]byte, 0, 3*len(s))
	for i := 0; i < len(s); i++ {
		c := s[i]
		if isEscapable(c) {
			t = append(t, '%')
			t = append(t, "0123456789ABCDEF"[c>>4])
			t = append(t, "0123456789ABCDEF"[c&15])
		} else {
			t = append(t, s[i])
		}
	}
	return string(t)
}

func isEscapable(b byte) bool {
	return !('A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' || b == '-' || b == '.' || b == '_' || b == '~')

}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 obcca

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"crypto/x509/pkix"
	"database/sql"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"
	"time"

	_ "github.com/mattn/go-sqlite3"
	"golang.org/x/crypto/sha3"
	"github.com/spf13/viper"
)

// CA is the base certificate authority.
//
type CA struct {
	db *sql.DB

	path string

	priv *ecdsa.PrivateKey
	cert *x509.Certificate
	raw []byte
}

// NewCA sets up a new CA.
//
func NewCA(name string) *CA {
	ca := new(CA)
	ca.path = viper.GetString("server.rootpath")+"/"+viper.GetString("server.cadir")

	if _, err := os.Stat(ca.path); err != nil {
		Info.Println("Fresh start; creating databases, key pairs, and certificates.")

		if err := os.MkdirAll(ca.path, 0755); err != nil {
			Panic.Panicln(err)
		}
	}

	// open or create certificate database
	db, err := sql.Open("sqlite3", ca.path+"/"+name+".db")
	if err != nil {
		Panic.Panicln(err)
	}

	if err := db.Ping(); err != nil {
		Panic.Panicln(err)
	}
	if _, err := db.Exec("CREATE TABLE IF NOT EXISTS Certificates (row INTEGER PRIMARY KEY, id VARCHAR(64), timestamp INTEGER, usage INTEGER, cert BLOB, hash BLOB, kdfkey BLOB)"); err != nil {
		Panic.Panicln(err)
	}
	if _, err := db.Exec("CREATE TABLE IF NOT EXISTS Users (row INTEGER PRIMARY KEY, id VARCHAR(64), role INTEGER, token BLOB, state INTEGER, key BLOB)"); err != nil {
		Panic.Panicln(err)
	}
	ca.db = db

	// read or create signing key pair
	priv, err := ca.readCAPrivateKey(name)
	if err != nil {
		priv = ca.createCAKeyPair(name)
	}
	ca.priv = priv

	// read CA certificate, or create a self-signed CA certificate
	raw, err := ca.readCACertificate(name)
	if err != nil {
		raw = ca.createCACertificate(name, &ca.priv.PublicKey)
	}
	cert, err := x509.ParseCertificate(raw)
	if err != nil {
		Panic.Panicln(err)
	}

	ca.raw = raw
	ca.cert = cert

	return ca
}

// Close closes down the CA.
//
func (ca *CA) Close() {
	ca.db.Close()
}

func (ca *CA) createCAKeyPair(name string) *ecdsa.PrivateKey {
	Trace.Println("Creating CA key pair.")

	curve := elliptic.P384()

	priv, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err == nil {
		raw, _ := x509.MarshalECPrivateKey(priv)
		cooked := pem.EncodeToMemory(
			&pem.Block{
				Type:  "ECDSA PRIVATE KEY",
				Bytes: raw,
			})
		err := ioutil.WriteFile(ca.path+"/"+name+".priv", cooked, 0644)
		if err != nil {
			Panic.Panicln(err)
		}

		raw, _ = x509.MarshalPKIXPublicKey(&priv.PublicKey)
		cooked = pem.EncodeToMemory(
			&pem.Block{
				Type:  "ECDSA PUBLIC KEY",
				Bytes: raw,
			})
		err = ioutil.WriteFile(ca.path+"/"+name+".pub", cooked, 0644)
		if err != nil {
			Panic.Panicln(err)
		}
	}
	if err != nil {
		Panic.Panicln(err)
	}

	return priv
}

func (ca *CA) readCAPrivateKey(name string) (*ecdsa.PrivateKey, error) {
	Trace.Println("Reading CA private key.")

	cooked, err := ioutil.ReadFile(ca.path + "/" + name + ".priv")
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(cooked)
	return x509.ParseECPrivateKey(block.Bytes)
}

func (ca *CA) createCACertificate(name string, pub *ecdsa.PublicKey) []byte {
	Trace.Println("Creating CA certificate.")

	raw, err := ca.newCertificate(name, pub, x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, nil)
	if err != nil {
		Panic.Panicln(err)
	}

	cooked := pem.EncodeToMemory(
		&pem.Block{
			Type:  "CERTIFICATE",
			Bytes: raw,
		})
	err = ioutil.WriteFile(ca.path+"/"+name+".cert", cooked, 0644)
	if err != nil {
		Panic.Panicln(err)
	}

	return raw
}

func (ca *CA) readCACertificate(name string) ([]byte, error) {
	Trace.Println("Reading CA certificate.")

	cooked, err := ioutil.ReadFile(ca.path+"/"+name+".cert")
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(cooked)
	return block.Bytes, nil
}

func (ca *CA) createCertificate(id string, pub interface{}, usage x509.KeyUsage, timestamp int64, kdfKey []byte, opt ...pkix.Extension) ([]byte, error) {
	Trace.Println("Creating certificate for "+id+".")

	raw, err := ca.newCertificate(id, pub, usage, opt)
	if err != nil {
		Error.Println(err)
		return nil, err
	}

	hash := sha3.New384()
	hash.Write(raw)
	if _, err = ca.db.Exec("INSERT INTO Certificates (id, timestamp, usage, cert, hash, kdfkey) VALUES (?, ?, ?, ?, ?, ?)", id, timestamp, usage, raw, hash.Sum(nil), kdfKey); err != nil {
		Error.Println(err)
	}

	return raw, err
}

func (ca *CA) newCertificate(id string, pub interface{}, usage x509.KeyUsage, ext []pkix.Extension) ([]byte, error) {
	notBefore := time.Now()
	notAfter := notBefore.Add(time.Hour * 24 * 90)

	parent := ca.cert
	isCA := parent == nil

	tmpl := x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject: pkix.Name{
			CommonName:   id,
			Organization: []string{"IBM"},
			Country:      []string{"US"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,

		SubjectKeyId:       []byte{1, 2, 3, 4},
		SignatureAlgorithm: x509.ECDSAWithSHA384,
		KeyUsage:           usage,

		BasicConstraintsValid: true,
		IsCA: isCA,
	}

	if len(ext) > 0 {
		tmpl.Extensions = ext
		tmpl.ExtraExtensions = ext
	}
	if isCA {
		parent = &tmpl
	}

	raw, err := x509.CreateCertificate(
		rand.Reader,
		&tmpl,
		parent,
		pub,
		ca.priv,
	)
	if isCA && err != nil {
		Panic.Panicln(err)
	}

	return raw, err
}

func (ca *CA) readCertificate(id string, usage x509.KeyUsage) ([]byte, error) {
	Trace.Println("Reading certificate for "+id+".")

	var raw []byte
	err := ca.db.QueryRow("SELECT cert FROM Certificates WHERE id=? AND usage=?", id, usage).Scan(&raw)

	return raw, err
}

func (ca *CA) readCertificate1(id string, ts int64) ([]byte, error) {
	Trace.Println("Reading certificate for "+id+".")

	var raw []byte
	err := ca.db.QueryRow("SELECT cert FROM Certificates WHERE id=? AND timestamp=?", id, ts).Scan(&raw)

	return raw, err
}

func (ca *CA) readCertificates(id string, opt ...int64) (*sql.Rows, error) {
	Trace.Println("Reading certificatess for "+id+".")

	if len(opt) > 0 && opt[0] != 0 {
		return ca.db.Query("SELECT cert, kdfkey FROM Certificates ORDER BY usage WHERE id=? AND timestamp=?", id, opt[0])
	}

	return ca.db.Query("SELECT cert, kdfkey FROM Certificates WHERE id=?", id)
}

func (ca *CA) readCertificateByHash(hash []byte) ([]byte, error) {
	Trace.Println("Reading certificate for hash "+string(hash)+".")

	var raw []byte
	row := ca.db.QueryRow("SELECT cert FROM Certificates WHERE hash=?", hash)
	err := row.Scan(&raw)

	return raw, err
}

func (ca *CA) registerUser(id string, role int, opt ...string) (string, error) {
	Trace.Println("Registering user "+id+" as "+strconv.FormatInt(int64(role), 2)+".")

	var row int
	err := ca.db.QueryRow("SELECT row FROM Users WHERE id=?", id).Scan(&row)
	if err == nil {
		return "", errors.New("user is already registered")
	}

	var tok string
	if len(opt) > 0 && len(opt[0]) > 0 {
		tok = opt[0]
	} else {
		tok = randomString(12)
	}

	_, err = ca.db.Exec("INSERT INTO Users (id, role, token, state) VALUES (?, ?, ?, ?)", id, role, tok, 0)
	if err != nil {
		Error.Println(err)

	}

	return tok, err
}

func (ca *CA) deleteUser(id string) (error) {
	Trace.Println("Deleting user "+id+".")

	var row int
	err := ca.db.QueryRow("SELECT row FROM Users WHERE id=?", id).Scan(&row)
	if err == nil {
		_, err = ca.db.Exec("DELETE FROM Certificates Where id=?", id)
		if err != nil {
			Error.Println(err)
		}

		_, err = ca.db.Exec("DELETE FROM Users WHERE row=?", row)
		if err != nil {
			Error.Println(err)
		}
	}

	return err
}

func (ca *CA) readToken(id string) *sql.Row {
	Trace.Println("Reading token for "+id+".")

	return ca.db.QueryRow("SELECT token, state, key FROM Users WHERE id=?", id)
}

func (ca *CA) readRole(id string) int {
	Trace.Println("Reading role for "+id+".")

	var role int
	err := ca.db.QueryRow("SELECT role FROM Users WHERE id=?", id).Scan(&role)
	if err != nil {
		Panic.Panicln(err)
	}

	return role
}
<commit_msg>Removed impossible error condition.<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 obcca

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"crypto/x509/pkix"
	"database/sql"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"math/big"
	"os"
	"strconv"
	"time"

	_ "github.com/mattn/go-sqlite3"
	"golang.org/x/crypto/sha3"
	"github.com/spf13/viper"
)

// CA is the base certificate authority.
//
type CA struct {
	db *sql.DB

	path string

	priv *ecdsa.PrivateKey
	cert *x509.Certificate
	raw []byte
}

// NewCA sets up a new CA.
//
func NewCA(name string) *CA {
	ca := new(CA)
	ca.path = viper.GetString("server.rootpath")+"/"+viper.GetString("server.cadir")

	if _, err := os.Stat(ca.path); err != nil {
		Info.Println("Fresh start; creating databases, key pairs, and certificates.")

		if err := os.MkdirAll(ca.path, 0755); err != nil {
			Panic.Panicln(err)
		}
	}

	// open or create certificate database
	db, err := sql.Open("sqlite3", ca.path+"/"+name+".db")
	if err != nil {
		Panic.Panicln(err)
	}

	if err := db.Ping(); err != nil {
		Panic.Panicln(err)
	}
	if _, err := db.Exec("CREATE TABLE IF NOT EXISTS Certificates (row INTEGER PRIMARY KEY, id VARCHAR(64), timestamp INTEGER, usage INTEGER, cert BLOB, hash BLOB, kdfkey BLOB)"); err != nil {
		Panic.Panicln(err)
	}
	if _, err := db.Exec("CREATE TABLE IF NOT EXISTS Users (row INTEGER PRIMARY KEY, id VARCHAR(64), role INTEGER, token BLOB, state INTEGER, key BLOB)"); err != nil {
		Panic.Panicln(err)
	}
	ca.db = db

	// read or create signing key pair
	priv, err := ca.readCAPrivateKey(name)
	if err != nil {
		priv = ca.createCAKeyPair(name)
	}
	ca.priv = priv

	// read CA certificate, or create a self-signed CA certificate
	raw, err := ca.readCACertificate(name)
	if err != nil {
		raw = ca.createCACertificate(name, &ca.priv.PublicKey)
	}
	cert, err := x509.ParseCertificate(raw)
	if err != nil {
		Panic.Panicln(err)
	}

	ca.raw = raw
	ca.cert = cert

	return ca
}

// Close closes down the CA.
//
func (ca *CA) Close() {
	ca.db.Close()
}

func (ca *CA) createCAKeyPair(name string) *ecdsa.PrivateKey {
	Trace.Println("Creating CA key pair.")

	curve := elliptic.P384()

	priv, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err == nil {
		raw, _ := x509.MarshalECPrivateKey(priv)
		cooked := pem.EncodeToMemory(
			&pem.Block{
				Type:  "ECDSA PRIVATE KEY",
				Bytes: raw,
			})
		err := ioutil.WriteFile(ca.path+"/"+name+".priv", cooked, 0644)
		if err != nil {
			Panic.Panicln(err)
		}

		raw, _ = x509.MarshalPKIXPublicKey(&priv.PublicKey)
		cooked = pem.EncodeToMemory(
			&pem.Block{
				Type:  "ECDSA PUBLIC KEY",
				Bytes: raw,
			})
		err = ioutil.WriteFile(ca.path+"/"+name+".pub", cooked, 0644)
		if err != nil {
			Panic.Panicln(err)
		}
	}
	if err != nil {
		Panic.Panicln(err)
	}

	return priv
}

func (ca *CA) readCAPrivateKey(name string) (*ecdsa.PrivateKey, error) {
	Trace.Println("Reading CA private key.")

	cooked, err := ioutil.ReadFile(ca.path + "/" + name + ".priv")
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(cooked)
	return x509.ParseECPrivateKey(block.Bytes)
}

func (ca *CA) createCACertificate(name string, pub *ecdsa.PublicKey) []byte {
	Trace.Println("Creating CA certificate.")

	raw, err := ca.newCertificate(name, pub, x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, nil)
	if err != nil {
		Panic.Panicln(err)
	}

	cooked := pem.EncodeToMemory(
		&pem.Block{
			Type:  "CERTIFICATE",
			Bytes: raw,
		})
	err = ioutil.WriteFile(ca.path+"/"+name+".cert", cooked, 0644)
	if err != nil {
		Panic.Panicln(err)
	}

	return raw
}

func (ca *CA) readCACertificate(name string) ([]byte, error) {
	Trace.Println("Reading CA certificate.")

	cooked, err := ioutil.ReadFile(ca.path+"/"+name+".cert")
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(cooked)
	return block.Bytes, nil
}

func (ca *CA) createCertificate(id string, pub interface{}, usage x509.KeyUsage, timestamp int64, kdfKey []byte, opt ...pkix.Extension) ([]byte, error) {
	Trace.Println("Creating certificate for "+id+".")

	raw, err := ca.newCertificate(id, pub, usage, opt)
	if err != nil {
		Error.Println(err)
		return nil, err
	}

	hash := sha3.New384()
	hash.Write(raw)
	if _, err = ca.db.Exec("INSERT INTO Certificates (id, timestamp, usage, cert, hash, kdfkey) VALUES (?, ?, ?, ?, ?, ?)", id, timestamp, usage, raw, hash.Sum(nil), kdfKey); err != nil {
		Error.Println(err)
	}

	return raw, err
}

func (ca *CA) newCertificate(id string, pub interface{}, usage x509.KeyUsage, ext []pkix.Extension) ([]byte, error) {
	notBefore := time.Now()
	notAfter := notBefore.Add(time.Hour * 24 * 90)

	parent := ca.cert
	isCA := parent == nil

	tmpl := x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject: pkix.Name{
			CommonName:   id,
			Organization: []string{"IBM"},
			Country:      []string{"US"},
		},
		NotBefore: notBefore,
		NotAfter:  notAfter,

		SubjectKeyId:       []byte{1, 2, 3, 4},
		SignatureAlgorithm: x509.ECDSAWithSHA384,
		KeyUsage:           usage,

		BasicConstraintsValid: true,
		IsCA: isCA,
	}

	if len(ext) > 0 {
		tmpl.Extensions = ext
		tmpl.ExtraExtensions = ext
	}
	if isCA {
		parent = &tmpl
	}

	raw, err := x509.CreateCertificate(
		rand.Reader,
		&tmpl,
		parent,
		pub,
		ca.priv,
	)
	if isCA && err != nil {
		Panic.Panicln(err)
	}

	return raw, err
}

func (ca *CA) readCertificate(id string, usage x509.KeyUsage) ([]byte, error) {
	Trace.Println("Reading certificate for "+id+".")

	var raw []byte
	err := ca.db.QueryRow("SELECT cert FROM Certificates WHERE id=? AND usage=?", id, usage).Scan(&raw)

	return raw, err
}

func (ca *CA) readCertificate1(id string, ts int64) ([]byte, error) {
	Trace.Println("Reading certificate for "+id+".")

	var raw []byte
	err := ca.db.QueryRow("SELECT cert FROM Certificates WHERE id=? AND timestamp=?", id, ts).Scan(&raw)

	return raw, err
}

func (ca *CA) readCertificates(id string, opt ...int64) (*sql.Rows, error) {
	Trace.Println("Reading certificatess for "+id+".")

	if len(opt) > 0 && opt[0] != 0 {
		return ca.db.Query("SELECT cert, kdfkey FROM Certificates ORDER BY usage WHERE id=? AND timestamp=?", id, opt[0])
	}

	return ca.db.Query("SELECT cert, kdfkey FROM Certificates WHERE id=?", id)
}

func (ca *CA) readCertificateByHash(hash []byte) ([]byte, error) {
	Trace.Println("Reading certificate for hash "+string(hash)+".")

	var raw []byte
	row := ca.db.QueryRow("SELECT cert FROM Certificates WHERE hash=?", hash)
	err := row.Scan(&raw)

	return raw, err
}

func (ca *CA) registerUser(id string, role int, opt ...string) (string, error) {
	Trace.Println("Registering user "+id+" as "+strconv.FormatInt(int64(role), 2)+".")

	var row int
	err := ca.db.QueryRow("SELECT row FROM Users WHERE id=?", id).Scan(&row)
	if err == nil {
		return "", errors.New("user is already registered")
	}

	var tok string
	if len(opt) > 0 && len(opt[0]) > 0 {
		tok = opt[0]
	} else {
		tok = randomString(12)
	}

	_, err = ca.db.Exec("INSERT INTO Users (id, role, token, state) VALUES (?, ?, ?, ?)", id, role, tok, 0)
	if err != nil {
		Error.Println(err)

	}

	return tok, err
}

func (ca *CA) deleteUser(id string) (error) {
	Trace.Println("Deleting user "+id+".")

	var row int
	err := ca.db.QueryRow("SELECT row FROM Users WHERE id=?", id).Scan(&row)
	if err == nil {
		_, err = ca.db.Exec("DELETE FROM Certificates Where id=?", id)
		if err != nil {
			Error.Println(err)
		}

		_, err = ca.db.Exec("DELETE FROM Users WHERE row=?", row)
		if err != nil {
			Error.Println(err)
		}
	}

	return err
}

func (ca *CA) readToken(id string) *sql.Row {
	Trace.Println("Reading token for "+id+".")

	return ca.db.QueryRow("SELECT token, state, key FROM Users WHERE id=?", id)
}

func (ca *CA) readRole(id string) int {
	Trace.Println("Reading role for "+id+".")

	var role int
	ca.db.QueryRow("SELECT role FROM Users WHERE id=?", id).Scan(&role)

	return role
}
<|endoftext|>


<commit_before>package redis

import (
	"container/list"
	"errors"
	"fmt"
	"log"
	"net"
	"sync"
	"time"

	"gopkg.in/bufio.v1"
)

var (
	errClosed = errors.New("redis: client is closed")
)

var (
	zeroTime = time.Time{}
)

type pool interface {
	Get() (*conn, bool, error)
	Put(*conn) error
	Remove(*conn) error
	Len() int
	Size() int
	Close() error
	Filter(func(*conn) bool)
}

//------------------------------------------------------------------------------

type conn struct {
	netcn net.Conn
	rd    *bufio.Reader
	buf   []byte

	inUse  bool
	usedAt time.Time

	readTimeout  time.Duration
	writeTimeout time.Duration

	elem *list.Element
}

func newConnFunc(dial func() (net.Conn, error)) func() (*conn, error) {
	return func() (*conn, error) {
		netcn, err := dial()
		if err != nil {
			return nil, err
		}
		cn := &conn{
			netcn: netcn,
			buf:   make([]byte, 0, 64),
		}
		cn.rd = bufio.NewReader(cn)
		return cn, nil
	}
}

func (cn *conn) Read(b []byte) (int, error) {
	if cn.readTimeout != 0 {
		cn.netcn.SetReadDeadline(time.Now().Add(cn.readTimeout))
	} else {
		cn.netcn.SetReadDeadline(zeroTime)
	}
	return cn.netcn.Read(b)
}

func (cn *conn) Write(b []byte) (int, error) {
	if cn.writeTimeout != 0 {
		cn.netcn.SetWriteDeadline(time.Now().Add(cn.writeTimeout))
	} else {
		cn.netcn.SetWriteDeadline(zeroTime)
	}
	return cn.netcn.Write(b)
}

func (cn *conn) RemoteAddr() net.Addr {
	return cn.netcn.RemoteAddr()
}

func (cn *conn) Close() error {
	return cn.netcn.Close()
}

//------------------------------------------------------------------------------

type connPool struct {
	dial func() (*conn, error)
	rl   *rateLimiter

	opt *options

	cond  *sync.Cond
	conns *list.List

	idleNum int
	closed  bool

	lastDialErr error
}

func newConnPool(dial func() (*conn, error), opt *options) *connPool {
	return &connPool{
		dial: dial,
		rl:   newRateLimiter(time.Second, 2*opt.PoolSize),

		opt: opt,

		cond:  sync.NewCond(&sync.Mutex{}),
		conns: list.New(),
	}
}

func (p *connPool) new() (*conn, error) {
	if !p.rl.Check() {
		err := fmt.Errorf(
			"redis: you open connections too fast (last error: %s)",
			p.lastDialErr,
		)
		return nil, err
	}
	cn, err := p.dial()
	if err != nil {
		p.lastDialErr = err
	}
	return cn, err
}

func (p *connPool) Get() (*conn, bool, error) {
	p.cond.L.Lock()

	if p.closed {
		p.cond.L.Unlock()
		return nil, false, errClosed
	}

	if p.opt.IdleTimeout > 0 {
		for el := p.conns.Front(); el != nil; el = el.Next() {
			cn := el.Value.(*conn)
			if cn.inUse {
				break
			}
			if time.Since(cn.usedAt) > p.opt.IdleTimeout {
				if err := p.remove(cn); err != nil {
					log.Printf("remove failed: %s", err)
				}
			}
		}
	}

	for p.conns.Len() >= p.opt.PoolSize && p.idleNum == 0 {
		p.cond.Wait()
	}

	if p.idleNum > 0 {
		elem := p.conns.Front()
		cn := elem.Value.(*conn)
		if cn.inUse {
			panic("pool: precondition failed")
		}
		cn.inUse = true
		p.conns.MoveToBack(elem)
		p.idleNum--

		p.cond.L.Unlock()
		return cn, false, nil
	}

	if p.conns.Len() < p.opt.PoolSize {
		cn, err := p.new()
		if err != nil {
			p.cond.L.Unlock()
			return nil, false, err
		}

		cn.inUse = true
		cn.elem = p.conns.PushBack(cn)

		p.cond.L.Unlock()
		return cn, true, nil
	}

	panic("not reached")
}

func (p *connPool) Put(cn *conn) error {
	if cn.rd.Buffered() != 0 {
		b, _ := cn.rd.ReadN(cn.rd.Buffered())
		log.Printf("redis: connection has unread data: %q", b)
		return p.Remove(cn)
	}

	if p.opt.IdleTimeout > 0 {
		cn.usedAt = time.Now()
	}

	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return errClosed
	}
	cn.inUse = false
	p.conns.MoveToFront(cn.elem)
	p.idleNum++
	p.cond.Signal()
	p.cond.L.Unlock()

	return nil
}

func (p *connPool) Remove(cn *conn) error {
	p.cond.L.Lock()
	if p.closed {
		// Noop, connection is already closed.
		p.cond.L.Unlock()
		return nil
	}
	err := p.remove(cn)
	p.cond.Signal()
	p.cond.L.Unlock()
	return err
}

func (p *connPool) remove(cn *conn) error {
	p.conns.Remove(cn.elem)
	cn.elem = nil
	if !cn.inUse {
		p.idleNum--
	}
	return cn.Close()
}

// Len returns number of idle connections.
func (p *connPool) Len() int {
	defer p.cond.L.Unlock()
	p.cond.L.Lock()
	return p.idleNum
}

// Size returns number of connections in the pool.
func (p *connPool) Size() int {
	defer p.cond.L.Unlock()
	p.cond.L.Lock()
	return p.conns.Len()
}

func (p *connPool) Filter(f func(*conn) bool) {
	p.cond.L.Lock()
	for el, next := p.conns.Front(), p.conns.Front(); el != nil; el = next {
		next = el.Next()
		cn := el.Value.(*conn)
		if !f(cn) {
			p.remove(cn)
		}
	}
	p.cond.L.Unlock()
}

func (p *connPool) Close() error {
	defer p.cond.L.Unlock()
	p.cond.L.Lock()
	if p.closed {
		return nil
	}
	p.closed = true
	p.rl.Close()
	var retErr error
	for {
		e := p.conns.Front()
		if e == nil {
			break
		}
		if err := p.remove(e.Value.(*conn)); err != nil {
			log.Printf("cn.Close failed: %s", err)
			retErr = err
		}
	}
	return retErr
}

//------------------------------------------------------------------------------

type singleConnPool struct {
	pool pool

	cnMtx sync.Mutex
	cn    *conn

	reusable bool

	closed bool
}

func newSingleConnPool(pool pool, reusable bool) *singleConnPool {
	return &singleConnPool{
		pool:     pool,
		reusable: reusable,
	}
}

func (p *singleConnPool) SetConn(cn *conn) {
	p.cnMtx.Lock()
	p.cn = cn
	p.cnMtx.Unlock()
}

func (p *singleConnPool) Get() (*conn, bool, error) {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()

	if p.closed {
		return nil, false, errClosed
	}
	if p.cn != nil {
		return p.cn, false, nil
	}

	cn, isNew, err := p.pool.Get()
	if err != nil {
		return nil, false, err
	}
	p.cn = cn

	return p.cn, isNew, nil
}

func (p *singleConnPool) Put(cn *conn) error {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn != cn {
		panic("p.cn != cn")
	}
	if p.closed {
		return errClosed
	}
	return nil
}

func (p *singleConnPool) put() error {
	err := p.pool.Put(p.cn)
	p.cn = nil
	return err
}

func (p *singleConnPool) Remove(cn *conn) error {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn == nil {
		panic("p.cn == nil")
	}
	if p.cn != cn {
		panic("p.cn != cn")
	}
	if p.closed {
		return errClosed
	}
	return p.remove()
}

func (p *singleConnPool) remove() error {
	err := p.pool.Remove(p.cn)
	p.cn = nil
	return err
}

func (p *singleConnPool) Len() int {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn == nil {
		return 0
	}
	return 1
}

func (p *singleConnPool) Size() int {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn == nil {
		return 0
	}
	return 1
}

func (p *singleConnPool) Filter(f func(*conn) bool) {
	p.cnMtx.Lock()
	if p.cn != nil {
		if !f(p.cn) {
			p.remove()
		}
	}
	p.cnMtx.Unlock()
}

func (p *singleConnPool) Close() error {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.closed {
		return nil
	}
	p.closed = true
	var err error
	if p.cn != nil {
		if p.reusable {
			err = p.put()
		} else {
			err = p.remove()
		}
	}
	return err
}
<commit_msg>Minor. Report rate-limiter errors correctly.<commit_after>package redis

import (
	"container/list"
	"errors"
	"fmt"
	"log"
	"net"
	"sync"
	"time"

	"gopkg.in/bufio.v1"
)

var (
	errClosed = errors.New("redis: client is closed")
)

var (
	zeroTime = time.Time{}
)

type pool interface {
	Get() (*conn, bool, error)
	Put(*conn) error
	Remove(*conn) error
	Len() int
	Size() int
	Close() error
	Filter(func(*conn) bool)
}

//------------------------------------------------------------------------------

type conn struct {
	netcn net.Conn
	rd    *bufio.Reader
	buf   []byte

	inUse  bool
	usedAt time.Time

	readTimeout  time.Duration
	writeTimeout time.Duration

	elem *list.Element
}

func newConnFunc(dial func() (net.Conn, error)) func() (*conn, error) {
	return func() (*conn, error) {
		netcn, err := dial()
		if err != nil {
			return nil, err
		}
		cn := &conn{
			netcn: netcn,
			buf:   make([]byte, 0, 64),
		}
		cn.rd = bufio.NewReader(cn)
		return cn, nil
	}
}

func (cn *conn) Read(b []byte) (int, error) {
	if cn.readTimeout != 0 {
		cn.netcn.SetReadDeadline(time.Now().Add(cn.readTimeout))
	} else {
		cn.netcn.SetReadDeadline(zeroTime)
	}
	return cn.netcn.Read(b)
}

func (cn *conn) Write(b []byte) (int, error) {
	if cn.writeTimeout != 0 {
		cn.netcn.SetWriteDeadline(time.Now().Add(cn.writeTimeout))
	} else {
		cn.netcn.SetWriteDeadline(zeroTime)
	}
	return cn.netcn.Write(b)
}

func (cn *conn) RemoteAddr() net.Addr {
	return cn.netcn.RemoteAddr()
}

func (cn *conn) Close() error {
	return cn.netcn.Close()
}

//------------------------------------------------------------------------------

type connPool struct {
	dial func() (*conn, error)
	rl   *rateLimiter

	opt *options

	cond  *sync.Cond
	conns *list.List

	idleNum int
	closed  bool

	lastDialErr error
}

func newConnPool(dial func() (*conn, error), opt *options) *connPool {
	return &connPool{
		dial: dial,
		rl:   newRateLimiter(time.Second, 2*opt.PoolSize),

		opt: opt,

		cond:  sync.NewCond(&sync.Mutex{}),
		conns: list.New(),
	}
}

func (p *connPool) new() (*conn, error) {
	if !p.rl.Check() {
		err := fmt.Errorf(
			"redis: you open connections too fast (last error: %v)",
			p.lastDialErr,
		)
		return nil, err
	}
	cn, err := p.dial()
	if err != nil {
		p.lastDialErr = err
	}
	return cn, err
}

func (p *connPool) Get() (*conn, bool, error) {
	p.cond.L.Lock()

	if p.closed {
		p.cond.L.Unlock()
		return nil, false, errClosed
	}

	if p.opt.IdleTimeout > 0 {
		for el := p.conns.Front(); el != nil; el = el.Next() {
			cn := el.Value.(*conn)
			if cn.inUse {
				break
			}
			if time.Since(cn.usedAt) > p.opt.IdleTimeout {
				if err := p.remove(cn); err != nil {
					log.Printf("remove failed: %s", err)
				}
			}
		}
	}

	for p.conns.Len() >= p.opt.PoolSize && p.idleNum == 0 {
		p.cond.Wait()
	}

	if p.idleNum > 0 {
		elem := p.conns.Front()
		cn := elem.Value.(*conn)
		if cn.inUse {
			panic("pool: precondition failed")
		}
		cn.inUse = true
		p.conns.MoveToBack(elem)
		p.idleNum--

		p.cond.L.Unlock()
		return cn, false, nil
	}

	if p.conns.Len() < p.opt.PoolSize {
		cn, err := p.new()
		if err != nil {
			p.cond.L.Unlock()
			return nil, false, err
		}

		cn.inUse = true
		cn.elem = p.conns.PushBack(cn)

		p.cond.L.Unlock()
		return cn, true, nil
	}

	panic("not reached")
}

func (p *connPool) Put(cn *conn) error {
	if cn.rd.Buffered() != 0 {
		b, _ := cn.rd.ReadN(cn.rd.Buffered())
		log.Printf("redis: connection has unread data: %q", b)
		return p.Remove(cn)
	}

	if p.opt.IdleTimeout > 0 {
		cn.usedAt = time.Now()
	}

	p.cond.L.Lock()
	if p.closed {
		p.cond.L.Unlock()
		return errClosed
	}
	cn.inUse = false
	p.conns.MoveToFront(cn.elem)
	p.idleNum++
	p.cond.Signal()
	p.cond.L.Unlock()

	return nil
}

func (p *connPool) Remove(cn *conn) error {
	p.cond.L.Lock()
	if p.closed {
		// Noop, connection is already closed.
		p.cond.L.Unlock()
		return nil
	}
	err := p.remove(cn)
	p.cond.Signal()
	p.cond.L.Unlock()
	return err
}

func (p *connPool) remove(cn *conn) error {
	p.conns.Remove(cn.elem)
	cn.elem = nil
	if !cn.inUse {
		p.idleNum--
	}
	return cn.Close()
}

// Len returns number of idle connections.
func (p *connPool) Len() int {
	defer p.cond.L.Unlock()
	p.cond.L.Lock()
	return p.idleNum
}

// Size returns number of connections in the pool.
func (p *connPool) Size() int {
	defer p.cond.L.Unlock()
	p.cond.L.Lock()
	return p.conns.Len()
}

func (p *connPool) Filter(f func(*conn) bool) {
	p.cond.L.Lock()
	for el, next := p.conns.Front(), p.conns.Front(); el != nil; el = next {
		next = el.Next()
		cn := el.Value.(*conn)
		if !f(cn) {
			p.remove(cn)
		}
	}
	p.cond.L.Unlock()
}

func (p *connPool) Close() error {
	defer p.cond.L.Unlock()
	p.cond.L.Lock()
	if p.closed {
		return nil
	}
	p.closed = true
	p.rl.Close()
	var retErr error
	for {
		e := p.conns.Front()
		if e == nil {
			break
		}
		if err := p.remove(e.Value.(*conn)); err != nil {
			log.Printf("cn.Close failed: %s", err)
			retErr = err
		}
	}
	return retErr
}

//------------------------------------------------------------------------------

type singleConnPool struct {
	pool pool

	cnMtx sync.Mutex
	cn    *conn

	reusable bool

	closed bool
}

func newSingleConnPool(pool pool, reusable bool) *singleConnPool {
	return &singleConnPool{
		pool:     pool,
		reusable: reusable,
	}
}

func (p *singleConnPool) SetConn(cn *conn) {
	p.cnMtx.Lock()
	p.cn = cn
	p.cnMtx.Unlock()
}

func (p *singleConnPool) Get() (*conn, bool, error) {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()

	if p.closed {
		return nil, false, errClosed
	}
	if p.cn != nil {
		return p.cn, false, nil
	}

	cn, isNew, err := p.pool.Get()
	if err != nil {
		return nil, false, err
	}
	p.cn = cn

	return p.cn, isNew, nil
}

func (p *singleConnPool) Put(cn *conn) error {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn != cn {
		panic("p.cn != cn")
	}
	if p.closed {
		return errClosed
	}
	return nil
}

func (p *singleConnPool) put() error {
	err := p.pool.Put(p.cn)
	p.cn = nil
	return err
}

func (p *singleConnPool) Remove(cn *conn) error {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn == nil {
		panic("p.cn == nil")
	}
	if p.cn != cn {
		panic("p.cn != cn")
	}
	if p.closed {
		return errClosed
	}
	return p.remove()
}

func (p *singleConnPool) remove() error {
	err := p.pool.Remove(p.cn)
	p.cn = nil
	return err
}

func (p *singleConnPool) Len() int {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn == nil {
		return 0
	}
	return 1
}

func (p *singleConnPool) Size() int {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.cn == nil {
		return 0
	}
	return 1
}

func (p *singleConnPool) Filter(f func(*conn) bool) {
	p.cnMtx.Lock()
	if p.cn != nil {
		if !f(p.cn) {
			p.remove()
		}
	}
	p.cnMtx.Unlock()
}

func (p *singleConnPool) Close() error {
	defer p.cnMtx.Unlock()
	p.cnMtx.Lock()
	if p.closed {
		return nil
	}
	p.closed = true
	var err error
	if p.cn != nil {
		if p.reusable {
			err = p.put()
		} else {
			err = p.remove()
		}
	}
	return err
}
<|endoftext|>


<commit_before>package worker

import (
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"golang.org/x/net/context"
)

const (
	DefaultWorkersCount = 10
)

var (
	DefaultTTR  time.Duration = 60 * time.Second
	DefaultWait time.Duration = 5 * time.Second
)

type response struct {
	Msg *Message
	Err error
}

// Pool represents a pool of workers connected to a queue.
type Pool struct {
	count int   // workers count
	queue Queue // input queue

	middleware middleware
	handlers   []Handler
	wait       time.Duration
	mux        map[string]Factory
	logger     *log.Logger
}

// SetQueue assigns a custom queue to worker pool.
func SetQueue(q Queue) func(*Pool) {
	return func(p *Pool) {
		p.queue = q
	}
}

// SetWorkers configures the pool concurrency.
func SetWorkers(n int) func(*Pool) {
	return func(p *Pool) {
		p.count = n
	}
}

// NewPool returns a new Pool instance.
func NewPool(opts ...func(*Pool)) *Pool {
	pool := &Pool{
		count:    DefaultWorkersCount,
		queue:    NewMemoryQueue(),
		wait:     DefaultWait,
		mux:      map[string]Factory{},
		logger:   log.New(os.Stdout, "[worker] ", 0),
		handlers: CommonStack(),
	}

	// Apply options.
	for _, opt := range opts {
		opt(pool)
	}

	// Init middleware stack.
	pool.middleware = pool.build(pool.handlers)

	return pool
}

// Add registers a new job factory.
func (p *Pool) Add(f Factory) error {
	typ, err := StructType(f)
	if err != nil {
		return err
	}

	if _, ok := p.mux[typ]; ok {
		return NewErrorFmt("factory %q exists already", typ)
	}
	p.mux[typ] = f
	return nil
}

// Use appends a new middleware to current stack.
func (p *Pool) Use(h Handler) {
	p.handlers = append(p.handlers, h)
	p.middleware = p.build(p.handlers)
}

// build iterates over the handlers, it returns a
// list of middlewares with each item linked to
// the next one.
func (p *Pool) build(hs []Handler) middleware {
	if len(hs) == 0 {
		return p.last()
	}
	next := p.build(hs[1:])
	return middleware{hs[0], &next}
}

// last builds and returns the last middleware, which will
// execute the job without calling next middleware.
func (p *Pool) last() middleware {
	return middleware{
		HandlerFunc(func(sw StatusWriter, fact string, args *Args, next JobRunner) {
			err := p.execute(fact, args)
			sw.Set(err)
		}),
		&middleware{},
	}
}

// Run starts processing jobs from the queue.
func (p *Pool) Run(ctx context.Context) error {
	var wg sync.WaitGroup

	// Handle unix signals.
	sig := p.trap()

	ctx, cancel := context.WithCancel(ctx)

	// Fan-out channel.
	c := make(chan *Message)

	// Start workers.
	wg.Add(p.count + 1)
	for i := 0; i < p.count; i++ {
		go func() {
			defer wg.Done()
			p.worker(ctx, c)
		}()
	}

	// Start the master.
	go func() {
		defer wg.Done()
		p.master(ctx, c)
	}()

	var err error
	select {
	case <-ctx.Done():
		err = ctx.Err()
	case <-sig:
		cancel()
	}

	close(c)
	wg.Wait()
	return p.Shutdown(err)
}

// Shutdown waits wait time to allow workers to complete the job.
func (p *Pool) Shutdown(err error) error {
	p.logger.Println("Shutdown completed!")
	return err
}

func (p *Pool) master(ctx context.Context, c chan<- *Message) {
	var r *response
	for {
		select {
		case <-ctx.Done():
			return
		case r = <-p.get():
		}

		if r.Err != nil {
			if wkerr, ok := r.Err.(*Error); ok && wkerr.Temporary() {
				continue
			}
			return
		}

		select {
		case <-ctx.Done():
			return
		case c <- r.Msg:
		}
	}
}

// worker executes jobs from the in channel in a separate goroutine.
func (p *Pool) worker(ctx context.Context, in <-chan *Message) {
	for msg := range in {
		status := NewStatusWriter()
		done := make(chan struct{}, 1)

		// Start the job in a separate goroutine.
		go func() {
			p.Exec(status, msg.Type(), msg.Args())
			done <- struct{}{}
		}()

		// Wait job completion.
		select {
		case <-ctx.Done():
			return
		case <-done:
			if status.OK() {
				if err := p.queue.Delete(msg); err != nil {
					p.logger.Println("delete:", msg, err)
				}
			} else {
				if err := p.queue.Reject(msg); err != nil {
					p.logger.Println("reject:", msg, err)
				}
			}
		}
	}
}

// Exec runs the job passing it through the middleware stack.
func (p *Pool) Exec(sw StatusWriter, fact string, args *Args) {
	p.middleware.Exec(sw, fact, args)
}

// execute runs the job without passing it through the
// middleware stack.
func (p *Pool) execute(fact string, args *Args) error {
	f, ok := p.mux[fact]
	if !ok {
		return NewErrorFmt("bad type: %v", fact)
	}

	j, err := f.Make(args)
	if err != nil {
		return NewErrorFmt("make: %v", err)
	}

	if err := j.Run(); err != nil {
		return NewErrorFmt("run: %v", err)
	}

	return nil
}

// trap traps OS signals to allow clean exit.
func (p *Pool) trap() <-chan struct{} {
	out := make(chan struct{}, 1)
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		defer close(out)
		for s := range signals {
			switch s {
			case syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM:
				p.logger.Println("Quit signal received ...")
				out <- struct{}{}
				return
			}
		}
	}()

	return out
}

// get service peeks a message from queue and
// returns it through a channel without blocking
// the caller.
func (p *Pool) get() <-chan *response {
	// Buffered channel to avoid goroutine leaking.
	out := make(chan *response, 1)

	// Start a gorouting to avoid blocking.
	go func() {
		defer close(out)

		msg, err := p.queue.Get()
		if err != nil {
			out <- &response{Err: err}
			return
		}

		out <- &response{Msg: msg}
	}()

	return out
}
<commit_msg>Remove unused variables<commit_after>package worker

import (
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"golang.org/x/net/context"
)

const (
	DefaultWorkersCount = 10
)

var (
	DefaultTTR time.Duration = 60 * time.Second
)

type response struct {
	Msg *Message
	Err error
}

// Pool represents a pool of workers connected to a queue.
type Pool struct {
	count int   // workers count
	queue Queue // input queue

	middleware middleware
	handlers   []Handler
	mux        map[string]Factory
	logger     *log.Logger
}

// SetQueue assigns a custom queue to worker pool.
func SetQueue(q Queue) func(*Pool) {
	return func(p *Pool) {
		p.queue = q
	}
}

// SetWorkers configures the pool concurrency.
func SetWorkers(n int) func(*Pool) {
	return func(p *Pool) {
		p.count = n
	}
}

// NewPool returns a new Pool instance.
func NewPool(opts ...func(*Pool)) *Pool {
	pool := &Pool{
		count:    DefaultWorkersCount,
		queue:    NewMemoryQueue(),
		mux:      map[string]Factory{},
		logger:   log.New(os.Stdout, "[worker] ", 0),
		handlers: CommonStack(),
	}

	// Apply options.
	for _, opt := range opts {
		opt(pool)
	}

	// Init middleware stack.
	pool.middleware = pool.build(pool.handlers)

	return pool
}

// Add registers a new job factory.
func (p *Pool) Add(f Factory) error {
	typ, err := StructType(f)
	if err != nil {
		return err
	}

	if _, ok := p.mux[typ]; ok {
		return NewErrorFmt("factory %q exists already", typ)
	}
	p.mux[typ] = f
	return nil
}

// Use appends a new middleware to current stack.
func (p *Pool) Use(h Handler) {
	p.handlers = append(p.handlers, h)
	p.middleware = p.build(p.handlers)
}

// build iterates over the handlers, it returns a
// list of middlewares with each item linked to
// the next one.
func (p *Pool) build(hs []Handler) middleware {
	if len(hs) == 0 {
		return p.last()
	}
	next := p.build(hs[1:])
	return middleware{hs[0], &next}
}

// last builds and returns the last middleware, which will
// execute the job without calling next middleware.
func (p *Pool) last() middleware {
	return middleware{
		HandlerFunc(func(sw StatusWriter, fact string, args *Args, next JobRunner) {
			err := p.execute(fact, args)
			sw.Set(err)
		}),
		&middleware{},
	}
}

// Run starts processing jobs from the queue.
func (p *Pool) Run(ctx context.Context) error {
	var wg sync.WaitGroup

	// Handle unix signals.
	sig := p.trap()

	ctx, cancel := context.WithCancel(ctx)

	// Fan-out channel.
	c := make(chan *Message)

	// Start workers.
	wg.Add(p.count + 1)
	for i := 0; i < p.count; i++ {
		go func() {
			defer wg.Done()
			p.worker(ctx, c)
		}()
	}

	// Start the master.
	go func() {
		defer wg.Done()
		p.master(ctx, c)
	}()

	var err error
	select {
	case <-ctx.Done():
		err = ctx.Err()
	case <-sig:
		cancel()
	}

	p.logger.Println("Stopping workers ...")
	close(c)
	wg.Wait()
	p.logger.Println("Shutdown completed!")
	return err
}

func (p *Pool) master(ctx context.Context, c chan<- *Message) {
	var r *response
	for {
		select {
		case <-ctx.Done():
			return
		case r = <-p.get():
		}

		if r.Err != nil {
			if wkerr, ok := r.Err.(*Error); ok && wkerr.Temporary() {
				continue
			}
			return
		}

		select {
		case <-ctx.Done():
			return
		case c <- r.Msg:
		}
	}
}

// worker executes jobs from the in channel in a separate goroutine.
func (p *Pool) worker(ctx context.Context, in <-chan *Message) {
	for msg := range in {
		status := NewStatusWriter()
		done := make(chan struct{}, 1)

		// Start the job in a separate goroutine.
		go func() {
			p.Exec(status, msg.Type(), msg.Args())
			done <- struct{}{}
		}()

		// Wait job completion.
		select {
		case <-ctx.Done():
			return
		case <-done:
			if status.OK() {
				if err := p.queue.Delete(msg); err != nil {
					p.logger.Println("delete:", msg, err)
				}
			} else {
				if err := p.queue.Reject(msg); err != nil {
					p.logger.Println("reject:", msg, err)
				}
			}
		}
	}
}

// Exec runs the job passing it through the middleware stack.
func (p *Pool) Exec(sw StatusWriter, fact string, args *Args) {
	p.middleware.Exec(sw, fact, args)
}

// execute runs the job without passing it through the
// middleware stack.
func (p *Pool) execute(fact string, args *Args) error {
	f, ok := p.mux[fact]
	if !ok {
		return NewErrorFmt("bad type: %v", fact)
	}

	j, err := f.Make(args)
	if err != nil {
		return NewErrorFmt("make: %v", err)
	}

	if err := j.Run(); err != nil {
		return NewErrorFmt("run: %v", err)
	}

	return nil
}

// trap traps OS signals to allow clean exit.
func (p *Pool) trap() <-chan struct{} {
	out := make(chan struct{}, 1)
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		defer close(out)
		for s := range signals {
			switch s {
			case syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM:
				p.logger.Println("Quit signal received ...")
				out <- struct{}{}
				return
			}
		}
	}()

	return out
}

// get service peeks a message from queue and
// returns it through a channel without blocking
// the caller.
func (p *Pool) get() <-chan *response {
	// Buffered channel to avoid goroutine leaking.
	out := make(chan *response, 1)

	// Start a gorouting to avoid blocking.
	go func() {
		defer close(out)

		msg, err := p.queue.Get()
		if err != nil {
			out <- &response{Err: err}
			return
		}

		out <- &response{Msg: msg}
	}()

	return out
}
<|endoftext|>


<commit_before>package procfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
)

// Proc provides information about a running process.
type Proc struct {
	// The process ID.
	PID int

	fs FS
}

// Procs represents a list of Proc structs.
type Procs []Proc

func (p Procs) Len() int           { return len(p) }
func (p Procs) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }

// Self returns a process for the current process.
func Self() (Proc, error) {
	return NewProc(os.Getpid())
}

// NewProc returns a process for the given pid under /proc.
func NewProc(pid int) (Proc, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return Proc{}, err
	}

	return fs.NewProc(pid)
}

// AllProcs returns a list of all currently avaible processes under /proc.
func AllProcs() (Procs, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return Procs{}, err
	}

	return fs.AllProcs()
}

// NewProc returns a process for the given pid.
func (fs FS) NewProc(pid int) (Proc, error) {
	if _, err := fs.stat(strconv.Itoa(pid)); err != nil {
		return Proc{}, err
	}

	return Proc{PID: pid, fs: fs}, nil
}

// AllProcs returns a list of all currently avaible processes.
func (fs FS) AllProcs() (Procs, error) {
	d, err := fs.open("")
	if err != nil {
		return Procs{}, err
	}
	defer d.Close()

	names, err := d.Readdirnames(-1)
	if err != nil {
		return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
	}

	p := Procs{}
	for _, n := range names {
		pid, err := strconv.ParseInt(n, 10, 64)
		if err != nil {
			continue
		}
		p = append(p, Proc{PID: int(pid), fs: fs})
	}

	return p, nil
}

// CmdLine returns the command line of a process.
func (p Proc) CmdLine() ([]string, error) {
	f, err := p.open("cmdline")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	if len(data) < 1 {
		return []string{}, nil
	}

	return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil
}

// Executable returns the absolute path of the executable command of a process.
func (p Proc) Executable() (string, error) {
	exe, err := p.readlink("exe")

	if os.IsNotExist(err) {
		return "", nil
	}

	return exe, err
}

// FileDescriptors returns the currently open file descriptors of a process.
func (p Proc) FileDescriptors() ([]uintptr, error) {
	names, err := p.fileDescriptors()
	if err != nil {
		return nil, err
	}

	fds := make([]uintptr, len(names))
	for i, n := range names {
		fd, err := strconv.ParseInt(n, 10, 32)
		if err != nil {
			return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
		}
		fds[i] = uintptr(fd)
	}

	return fds, nil
}

// FileDescriptorTargets returns the targets of all file descriptors of a process.
// If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string.
func (p Proc) FileDescriptorTargets() ([]string, error) {
	names, err := p.fileDescriptors()
	if err != nil {
		return nil, err
	}

	var targets = make([]string, len(names))

	for i, name := range names {
		var target, err = p.readlink("fd/" + name)
		if err != nil {
			targets[i] = ""
		} else {
			targets[i] = target
		}
	}

	return targets, nil
}

// FileDescriptorsLen returns the number of currently open file descriptors of
// a process.
func (p Proc) FileDescriptorsLen() (int, error) {
	fds, err := p.fileDescriptors()
	if err != nil {
		return 0, err
	}

	return len(fds), nil
}

func (p Proc) fileDescriptors() ([]string, error) {
	d, err := p.open("fd")
	if err != nil {
		return nil, err
	}
	defer d.Close()

	names, err := d.Readdirnames(-1)
	if err != nil {
		return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
	}

	return names, nil
}

func (p Proc) open(pa string) (*os.File, error) {
	return p.fs.open(path.Join(strconv.Itoa(p.PID), pa))
}

func (p Proc) readlink(pa string) (string, error) {
	return p.fs.readlink(path.Join(strconv.Itoa(p.PID), pa))
}
<commit_msg>Remove redundant error case and fix style<commit_after>package procfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
)

// Proc provides information about a running process.
type Proc struct {
	// The process ID.
	PID int

	fs FS
}

// Procs represents a list of Proc structs.
type Procs []Proc

func (p Procs) Len() int           { return len(p) }
func (p Procs) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Procs) Less(i, j int) bool { return p[i].PID < p[j].PID }

// Self returns a process for the current process.
func Self() (Proc, error) {
	return NewProc(os.Getpid())
}

// NewProc returns a process for the given pid under /proc.
func NewProc(pid int) (Proc, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return Proc{}, err
	}

	return fs.NewProc(pid)
}

// AllProcs returns a list of all currently avaible processes under /proc.
func AllProcs() (Procs, error) {
	fs, err := NewFS(DefaultMountPoint)
	if err != nil {
		return Procs{}, err
	}

	return fs.AllProcs()
}

// NewProc returns a process for the given pid.
func (fs FS) NewProc(pid int) (Proc, error) {
	if _, err := fs.stat(strconv.Itoa(pid)); err != nil {
		return Proc{}, err
	}

	return Proc{PID: pid, fs: fs}, nil
}

// AllProcs returns a list of all currently avaible processes.
func (fs FS) AllProcs() (Procs, error) {
	d, err := fs.open("")
	if err != nil {
		return Procs{}, err
	}
	defer d.Close()

	names, err := d.Readdirnames(-1)
	if err != nil {
		return Procs{}, fmt.Errorf("could not read %s: %s", d.Name(), err)
	}

	p := Procs{}
	for _, n := range names {
		pid, err := strconv.ParseInt(n, 10, 64)
		if err != nil {
			continue
		}
		p = append(p, Proc{PID: int(pid), fs: fs})
	}

	return p, nil
}

// CmdLine returns the command line of a process.
func (p Proc) CmdLine() ([]string, error) {
	f, err := p.open("cmdline")
	if err != nil {
		return nil, err
	}
	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	if len(data) < 1 {
		return []string{}, nil
	}

	return strings.Split(string(data[:len(data)-1]), string(byte(0))), nil
}

// Executable returns the absolute path of the executable command of a process.
func (p Proc) Executable() (string, error) {
	exe, err := p.readlink("exe")

	if os.IsNotExist(err) {
		return "", nil
	}

	return exe, err
}

// FileDescriptors returns the currently open file descriptors of a process.
func (p Proc) FileDescriptors() ([]uintptr, error) {
	names, err := p.fileDescriptors()
	if err != nil {
		return nil, err
	}

	fds := make([]uintptr, len(names))
	for i, n := range names {
		fd, err := strconv.ParseInt(n, 10, 32)
		if err != nil {
			return nil, fmt.Errorf("could not parse fd %s: %s", n, err)
		}
		fds[i] = uintptr(fd)
	}

	return fds, nil
}

// FileDescriptorTargets returns the targets of all file descriptors of a process.
// If a file descriptor is not a symlink to a file (like a socket), that value will be the empty string.
func (p Proc) FileDescriptorTargets() ([]string, error) {
	names, err := p.fileDescriptors()
	if err != nil {
		return nil, err
	}

	targets := make([]string, len(names))

	for i, name := range names {
		target, err := p.readlink("fd/" + name)
		if err == nil {
			targets[i] = target
		}
	}

	return targets, nil
}

// FileDescriptorsLen returns the number of currently open file descriptors of
// a process.
func (p Proc) FileDescriptorsLen() (int, error) {
	fds, err := p.fileDescriptors()
	if err != nil {
		return 0, err
	}

	return len(fds), nil
}

func (p Proc) fileDescriptors() ([]string, error) {
	d, err := p.open("fd")
	if err != nil {
		return nil, err
	}
	defer d.Close()

	names, err := d.Readdirnames(-1)
	if err != nil {
		return nil, fmt.Errorf("could not read %s: %s", d.Name(), err)
	}

	return names, nil
}

func (p Proc) open(pa string) (*os.File, error) {
	return p.fs.open(path.Join(strconv.Itoa(p.PID), pa))
}

func (p Proc) readlink(pa string) (string, error) {
	return p.fs.readlink(path.Join(strconv.Itoa(p.PID), pa))
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"
	"os"
	"io/ioutil"
	"time"
	"github.com/nsf/termbox-go"
)

// SETUP
const WAIT = 50
const ALLOW_BACK_OVER_LINE = false
const START_CHAR = 'S'
const FINISH_CHAR = 'F'

// Board
var board []rune
var tempBoard = make([]rune, len(board))

// Player
type Player struct {
	Symbol	rune
	X 		int
	Y		int
}
var p1 = Player{2015, 3, 3}

// Finish Line
type FinishLine struct {
	X 		int
	Y		int
}
var fL []FinishLine
var fR []FinishLine

// Counter
var circles int = 0
//var outFlg = true

func main() {
	// Termbox init
	termboxErr := termbox.Init()
	if termboxErr != nil {
        panic(termboxErr)
	}
	defer termbox.Close()
	termbox.HideCursor()
	// Track init
	var trackFileName string
	if  len(os.Args) > 1 {
		trackFileName = os.Args[1]
	} else {
		trackFileName = "t1.tr"
	}
	var boardByte, readfileErr = ioutil.ReadFile(trackFileName)
	if (readfileErr != nil) {
		panic ("Could not open file with track")
	}
	var boardString = string(boardByte)
	board = []rune(boardString)
	tempBoard = make([]rune, len(board))
	getFinishLines()
	// Draw finish line instead of L and R
	drawFinishLine()
	// Put player on start (R)
	var f = fR[0]
	p1.X = f.X; p1.Y = f.Y
	// Draw starting position
	draw(getBoard())
	termbox.Flush()
	// Key reader goroutine
	go checkKey()
	// Main Loop
	for !checkWin() {
		var move = getMove()
		if (isMoveOk(move)) {
			executeMove(move)
		}
		checkCircle()
		wait(WAIT)
		draw(getBoard())
		termbox.Flush()
	}
}

func drawFinishLine() {
	// gre cez cev board, zamena
	for key, val := range board {
		if val == START_CHAR {
			board[key] = ' '
		}
		if val == FINISH_CHAR {
			board[key] = '|'
		}
	}
}

func checkKey() {
	ev := termbox.PollEvent()
	go checkKey()
	switch ev.Type {
		case termbox.EventKey:
			if ev.Key == termbox.KeyCtrlC {
				termbox.Close()
				panic("Don't know how else to exit program:(")
			}
		case termbox.EventError:
			panic(ev.Err)
	}
}

func draw(text string) {
	var x=0; var y=0
	for _, value := range text {
		if value == '\n' {
			x=0
			y++
			continue
		}
		termbox.SetCell(x, y, value, 	termbox.ColorWhite, 										termbox.ColorBlack)
		x++
	}
}

func getFinishLines() {
	for key, value := range board {
		if value == START_CHAR {
			var x, y = getPosXY(key)
			fR = append(fR,FinishLine{x,y})
		}
		if value == FINISH_CHAR {
			var x, y = getPosXY(key)
			fL = append(fL,FinishLine{x,y})
		}
	}
}

//TODO per player
var flFlag = false
var frFlag = false
func checkCircle() {
	// na liniji
	if doesArrayContainPosition(fL, getPosIntPl(p1)) {
		if (frFlag == true) {
			circles--
			flFlag = true
			frFlag = false
		} else {
			flFlag = true
		}
	// desno od linije
    } else if doesArrayContainPosition(fR, getPosIntPl(p1)) {
    	if (flFlag == true) {
			circles++
			frFlag = true
			flFlag = false
		} else {
			frFlag = true
		}
	// drugje
    } else {
		flFlag = false
		frFlag = false
	}
}

func doesArrayContainPosition(fll []FinishLine, position int) bool {
	for _, fl := range fll {
		if position == getPosIntFl(fl) {
			return true
		}
	}
	return false
}

func toString(pl Player) string {
	return string(pl.Symbol) +" "+ string(pl.X) +" "+ string(pl.Y)
}

func getBoard() string {
	copy(tempBoard[:], board[0:len(board)])
	drawPlayerOnBoard(p1, tempBoard)
	return string(tempBoard)
}

func drawPlayerOnBoard(pl Player, board []rune) {
	var posInt = getPosInt(pl.X, pl.Y)
	board[posInt] = pl.Symbol
}

func getPosXY(pos int) (int, int) {
	var x = 0
	var y = 0
	for i := 0; i<=pos; i++ {
		x++
		if board[i] == '\n' {
			y++
			x = 0
		}
	}
	return x, y
}

func getPosInt(x int, y int) int {
	for i := 0; i<len(board); i++ {
		if board[i] == '\n' {
			y--
		}
		if y == 0 {
			x--
		}
		if y == 0 && x == 0 {
			return i
		}
	}
	panic("getPosInt: wrong coordinates")
}

func getPosIntPl(pl Player) int {
	return getPosInt(pl.X, pl.Y)
}

func getPosIntFl(fl FinishLine) int {
	return getPosInt(fl.X, fl.Y)
}

func isMoveOk(move int) bool {
	var newPos = getPos(p1.X, p1.Y, move)
	var sym = board[newPos]
	if contains([]rune{' ', '|'}, sym) {
		if !ALLOW_BACK_OVER_LINE {
			return !headingBackOverLine(getPosIntPl(p1), newPos)
		} else {
			return true
		}
	}
	return false
}

//TODO da ne gre niti na crto
func headingBackOverLine(oldPos int, newPos int) bool {
	// v naslednji potezi bi na ciljni crti
	// in zdaj je desno od ciljne crte
	if 	doesArrayContainPosition(fL, newPos) &&
		doesArrayContainPosition(fR, oldPos) {
		return true
	}
    return false
}

func contains(arr []rune, sim rune) bool {
	for _, val := range arr {
		if val == sim {
			return true
		}
	}
	return false
}

func executeMove(move int) {
	if move == 1 {
		p1.Y--
	}
	if move == 2 {
		p1.X++
	}
	if move == 3 {
		p1.Y++
	}
	if move == 4 {
		p1.X--
	}
}

func getPos(x int, y int, move int) int {
	if move == 1 {
		return getPosInt(x, y-1)
	}
	if move == 2 {
		return getPosInt(x+1, y)
	}
	if move == 3 {
		return getPosInt(x, y+1)
	}
	if move == 4 {
		return getPosInt(x-1, y)
	}
	panic("Invalid move value!")
}

//1:up 2:right 3:down 4: left
func getMove() int {
    var rt = rand.Perm(4)
	var rrt = rt[1]+1
	return rrt
}

func wait(sec int) {
	var ssec = time.Duration(sec*1000000)
	time.Sleep(ssec)
}

func checkWin() bool{
   return false
}

<commit_msg>new, more advanced framework in place. Two random players at the moment.<commit_after>package main

import (
	"math/rand"
	"os"
	"io/ioutil"
	"time"
	"github.com/nsf/termbox-go"
)

// SETUP
const WAIT = 50
const ALLOW_BACK_OVER_LINE = false
const START_CHAR = 'S'
const FINISH_CHAR = 'F'
const DEFAULT_TRACK = "t1.tr"
const FINISH_LINE = '|'

// Board
var board []rune
var tempBoard = make([]rune, len(board))

// Player
type Player struct {
	Symbol	rune
	X 		int
	Y		int
	laps 	int//= 0
	flFlag  bool//= false
	frFlag 	bool//= false
}
var pl1 =	Player{2015, 3, 3, 0, false, false}
var pl2 = Player{2016, 3, 3, 0, false, false}
var players = []Player{pl1, pl2}

// Channels
var channels []chan int
/*
var ch1 chan int
var ch2 chan int
*/
var globalChangeChanel chan int

// Controler
func NewControler(pl *Player, moveFromInputer chan int) {
	for {
		move := <-moveFromInputer
		pl.moveIfPossible(move)
	}
}

// Inputer
func NewRandomInputer(moveToControler chan int) {
	for {
		wait(WAIT)
		move := getRandomMove()
		moveToControler <- move
	}
}

// Finish Line
type FinishLine struct {
	X 		int
	Y		int
}
var fL []FinishLine
var fR []FinishLine

func main() {
	// Termbox init
	termboxErr := termbox.Init()
	if termboxErr != nil {
        panic(termboxErr)
	}
	defer termbox.Close()
	termbox.HideCursor()
	// Track init
	var trackFileName string
	if  len(os.Args) > 1 {
		trackFileName = os.Args[1]
	} else {
		trackFileName = DEFAULT_TRACK
	}
	var boardByte, readfileErr = ioutil.ReadFile(trackFileName)
	if (readfileErr != nil) {
		panic ("Could not open file with track")
	}
	var boardString = string(boardByte)
	board = []rune(boardString)
	tempBoard = make([]rune, len(board))
	getFinishLines()
	// Draw finish line instead of L and R
	drawFinishLine()
	// Put player on start (R)
	putPlayersOnStart()
	// Draw starting position
	draw(getBoard())
	termbox.Flush()
	// Key reader goroutine
	go checkKey()
	// Controlers and imputers
	globalChangeChanel = make(chan int)
	connectModules()
	// Main Loop
	for !checkWin() {
		<- globalChangeChanel
		brd := getBoard()
		draw(brd)
		termbox.Flush()
	}
}

func connectModules() {
	// create channels
	for i := 0; i < len(players); i++ {
		var chanel = make(chan int)
		channels = append(channels, chanel)
	}
	// create modules
	for i, ch := range channels {
		go NewControler(&players[i], ch)
		go NewRandomInputer(ch)
	}
}

func putPlayersOnStart() {
	i := 0
	for _, pl := range players {
		if len(fR) == i {
			i = 0
		}
		sL := fR[i]
		i++
		pl.X = sL.X
		pl.Y = sL.Y
	}
}

func (pl *Player) moveIfPossible(move int) {
	if (pl.isMoveOk(move)) {
		pl.executeMove(move)
	}
}

func drawFinishLine() {
	// gre cez cev board, zamena
	for key, val := range board {
		if val == START_CHAR {
			board[key] = ' '
		}
		if val == FINISH_CHAR {
			board[key] = FINISH_LINE
		}
	}
}

//TODO change to key listener module
func checkKey() {
	ev := termbox.PollEvent()
	go checkKey()
	switch ev.Type {
		case termbox.EventKey:
			if ev.Key == termbox.KeyCtrlC {
				termbox.Close()
				panic("Don't know how else to exit program:(")
			}
		case termbox.EventError:
			panic(ev.Err)
	}
}

func draw(text string) {
	var x=0; var y=0
	for _, value := range text {
		if value == '\n' {
			x=0
			y++
			continue
		}
		termbox.SetCell(x, y, value, 	termbox.ColorWhite, 										termbox.ColorBlack)
		x++
	}
}

func getFinishLines() {
	for key, value := range board {
		if value == START_CHAR {
			var x, y = getPosXY(key)
			fR = append(fR,FinishLine{x,y})
		}
		if value == FINISH_CHAR {
			var x, y = getPosXY(key)
			fL = append(fL,FinishLine{x,y})
		}
	}
}

func (pl *Player) checkCircle() {
	// na liniji
	if doesArrayContainPosition(fL, pl.getPosInt()) {
		if (pl.frFlag == true) {
			pl.laps--
			pl.flFlag = true
			pl.frFlag = false
		} else {
			pl.flFlag = true
		}
	// desno od linije
    } else if doesArrayContainPosition(fR, pl.getPosInt()) {
    	if (pl.flFlag == true) {
			pl.laps++
			pl.frFlag = true
			pl.flFlag = false
		} else {
			pl.frFlag = true
		}
	// drugje
    } else {
		pl.flFlag = false
		pl.frFlag = false
	}
}

func doesArrayContainPosition(fll []FinishLine, position int) bool {
	for _, fl := range fll {
		if position == fl.getPosInt() {
			return true
		}
	}
	return false
}

func toString(pl Player) string {
	return string(pl.Symbol) +" "+ string(pl.X) +" "+ string(pl.Y)
}

func getBoard() string {
	copy(tempBoard[:], board[0:len(board)])
	for _, pl := range players {
		pl.drawPlayerOnBoard(tempBoard)
	}
	return string(tempBoard)
}

func (pl *Player) drawPlayerOnBoard(boardLoc []rune) {
	var posInt = pl.getPosInt()
	boardLoc[posInt] = pl.Symbol
}

func getPosXY(pos int) (int, int) {
	var x = 0
	var y = 0
	for i := 0; i<=pos; i++ {
		x++
		if board[i] == '\n' {
			y++
			x = 0
		}
	}
	return x, y
}

func getPosInt(x int, y int) int {
	for i := 0; i<len(board); i++ {
		if board[i] == '\n' {
			y--
		}
		if y == 0 {
			x--
		}
		if y == 0 && x == 0 {
			return i
		}
	}
	panic("getPosInt: wrong coordinates")
}

func (pl *Player) getPosInt() int {
	return getPosInt(pl.X, pl.Y)
}

func (fl *FinishLine) getPosInt() int {
	return getPosInt(fl.X, fl.Y)
}

func (pl *Player) isMoveOk(move int) bool {
	var newPos = getPos(pl.X, pl.Y, move)
	var sym = board[newPos]
	if contains([]rune{' ', '|'}, sym) {
		if !ALLOW_BACK_OVER_LINE {
			return !headingBackOverLine(pl.getPosInt(), newPos)
		} else {
			return true
		}
	}
	return false
}

//TODO da ne gre niti na crto
func headingBackOverLine(oldPos int, newPos int) bool {
	// v naslednji potezi bi na ciljni crti
	// in zdaj je desno od ciljne crte
	if 	doesArrayContainPosition(fL, newPos) &&
		doesArrayContainPosition(fR, oldPos) {
		return true
	}
    return false
}

func contains(arr []rune, sim rune) bool {
	for _, val := range arr {
		if val == sim {
			return true
		}
	}
	return false
}

func (pl *Player) executeMove(move int) {
	if move == 1 {
		pl.Y--
	}
	if move == 2 {
		pl.X++
	}
	if move == 3 {
		pl.Y++
	}
	if move == 4 {
		pl.X--
	}
	pl.checkCircle()
	globalChangeChanel <- 1
}

func getPos(x int, y int, move int) int {
	if move == 1 {
		return getPosInt(x, y-1)
	}
	if move == 2 {
		return getPosInt(x+1, y)
	}
	if move == 3 {
		return getPosInt(x, y+1)
	}
	if move == 4 {
		return getPosInt(x-1, y)
	}
	panic("Invalid move value!")
}

//1:up 2:right 3:down 4: left
func getRandomMove() int {
    var rt = rand.Perm(4)
	var rrt = rt[1]+1
	return rrt
}

func wait(sec int) {
	var ssec = time.Duration(sec*1000000)
	time.Sleep(ssec)
}

func checkWin() bool{
   return false
}

<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package s3

import (
	"context"
	"io"
	"os"
	"path"

	"github.com/webx-top/echo"
	"github.com/webx-top/echo/defaults"
	"github.com/webx-top/echo/engine/mock"
	"github.com/webx-top/echo/param"

	"github.com/admpub/errors"
	"github.com/admpub/nging/v3/application/library/s3manager"
	"github.com/admpub/nging/v3/application/library/s3manager/s3client"
	"github.com/admpub/nging/v3/application/model"
	"github.com/admpub/nging/v3/application/model/file/storer"
	"github.com/admpub/nging/v3/application/registry/upload"
	"github.com/admpub/nging/v3/application/registry/upload/driver/local"
	"github.com/admpub/nging/v3/application/registry/upload/helper"
)

const (
	Name         = `s3`
	AccountIDKey = `storerID`
)

var _ upload.Storer = &Filesystem{}

func init() {
	upload.StorerRegister(Name, func(ctx context.Context, subdir string) (upload.Storer, error) {
		return NewFilesystem(ctx, subdir)
	})
}

func NewFilesystem(ctx context.Context, subdir string) (*Filesystem, error) {
	var cloudAccountID string
	eCtx, ok := ctx.(echo.Context)
	if !ok {
		eCtx = echo.NewContext(mock.NewRequest(), mock.NewResponse(), defaults.Default)
		eCtx.SetStdContext(ctx)
	} else {
		cloudAccountID = eCtx.Internal().String(AccountIDKey)
	}
	m := model.NewCloudStorage(eCtx)
	if len(cloudAccountID) == 0 {
		cloudAccountID = param.AsString(ctx.Value(AccountIDKey))
	}
	if len(cloudAccountID) == 0 || cloudAccountID == `0` {
		storerConfig, ok := storer.GetOk()
		if ok {
			cloudAccountID = storerConfig.ID
		}
	}
	if err := m.Get(nil, `id`, cloudAccountID); err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	mgr, err := s3client.New(m.NgingCloudStorage, 0)
	if err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	return &Filesystem{
		Filesystem: local.NewFilesystem(ctx, subdir, m.Baseurl),
		model:      m,
		mgr:        mgr,
	}, nil
}

// Filesystem 文件系统存储引擎
type Filesystem struct {
	*local.Filesystem
	model *model.CloudStorage
	mgr   *s3manager.S3Manager
}

// Name 引擎名
func (f *Filesystem) Name() string {
	return Name
}

func (f *Filesystem) ErrIsNotExist(err error) bool {
	return f.mgr.ErrIsNotExist(err)
}

// Exists 判断文件是否存在
func (f *Filesystem) Exists(file string) (bool, error) {
	return f.mgr.Exists(context.Background(), file)
}

// FileInfo 获取文件信息
func (f *Filesystem) FileInfo(file string) (os.FileInfo, error) {
	objectInfo, err := f.mgr.Stat(context.Background(), file)
	if err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	return s3manager.NewFileInfo(objectInfo), nil
}

// SendFile 下载文件
func (f *Filesystem) SendFile(ctx echo.Context, file string) error {
	fp, err := f.mgr.Get(ctx, file)
	if err != nil {
		return errors.WithMessage(err, Name)
	}
	defer fp.Close()
	fileName := path.Base(file)
	inline := true
	err = ctx.Attachment(fp, fileName, inline)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// FileDir 物理路径文件夹
func (f *Filesystem) FileDir(subpath string) string {
	return path.Join(helper.UploadURLPath, f.Subdir, subpath)
}

// Put 上传文件
func (f *Filesystem) Put(dstFile string, src io.Reader, size int64) (savePath string, viewURL string, err error) {
	savePath = f.FileDir(dstFile)
	//viewURL = `[storage:`+param.AsString(f.model.Id)+`]`+f.URLDir(dstFile)
	viewURL = f.PublicURL(dstFile)
	err = f.mgr.Put(context.Background(), src, savePath, size)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return
}

// Get 获取文件读取接口
func (f *Filesystem) Get(dstFile string) (io.ReadCloser, error) {
	object, err := f.mgr.Get(context.Background(), dstFile)
	if err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	exists, err := f.mgr.StatIsExists(object.Stat())
	if !exists {
		err = os.ErrNotExist
	}
	return object, err
}

// Delete 删除文件
func (f *Filesystem) Delete(dstFile string) error {
	err := f.mgr.Remove(context.Background(), dstFile)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// DeleteDir 删除文件夹及其内部文件
func (f *Filesystem) DeleteDir(dstDir string) error {
	err := f.mgr.RemoveDir(context.Background(), dstDir)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// Move 移动文件
func (f *Filesystem) Move(src, dst string) error {
	err := f.mgr.Rename(context.Background(), src, dst)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// Close 关闭连接
func (f *Filesystem) Close() error {
	return nil
}

// FixURL 改写文件网址
func (f *Filesystem) FixURL(content string, embedded ...bool) string {
	rowsByID := f.model.CachedList()
	return helper.ReplacePlaceholder(content, func(id string) string {
		r, y := rowsByID[id]
		if !y {
			return ``
		}
		return r.Baseurl
	})
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

package s3

import (
	"context"
	"io"
	"os"
	"path"

	"github.com/webx-top/echo"
	"github.com/webx-top/echo/defaults"
	"github.com/webx-top/echo/param"

	"github.com/admpub/errors"
	"github.com/admpub/nging/v3/application/library/s3manager"
	"github.com/admpub/nging/v3/application/library/s3manager/s3client"
	"github.com/admpub/nging/v3/application/model"
	"github.com/admpub/nging/v3/application/model/file/storer"
	"github.com/admpub/nging/v3/application/registry/upload"
	"github.com/admpub/nging/v3/application/registry/upload/driver/local"
	"github.com/admpub/nging/v3/application/registry/upload/helper"
)

const (
	Name         = `s3`
	AccountIDKey = `storerID`
)

var _ upload.Storer = &Filesystem{}

func init() {
	upload.StorerRegister(Name, func(ctx context.Context, subdir string) (upload.Storer, error) {
		return NewFilesystem(ctx, subdir)
	})
}

func NewFilesystem(ctx context.Context, subdir string) (*Filesystem, error) {
	var cloudAccountID string
	eCtx := defaults.MustGetContext(ctx)
	cloudAccountID = eCtx.Internal().String(AccountIDKey)
	m := model.NewCloudStorage(eCtx)
	if len(cloudAccountID) == 0 {
		cloudAccountID = param.AsString(ctx.Value(AccountIDKey))
	}
	if len(cloudAccountID) == 0 || cloudAccountID == `0` {
		storerConfig, ok := storer.GetOk()
		if ok {
			cloudAccountID = storerConfig.ID
		}
	}
	if err := m.Get(nil, `id`, cloudAccountID); err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	mgr, err := s3client.New(m.NgingCloudStorage, 0)
	if err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	return &Filesystem{
		Filesystem: local.NewFilesystem(ctx, subdir, m.Baseurl),
		model:      m,
		mgr:        mgr,
	}, nil
}

// Filesystem 文件系统存储引擎
type Filesystem struct {
	*local.Filesystem
	model *model.CloudStorage
	mgr   *s3manager.S3Manager
}

// Name 引擎名
func (f *Filesystem) Name() string {
	return Name
}

func (f *Filesystem) ErrIsNotExist(err error) bool {
	return f.mgr.ErrIsNotExist(err)
}

// Exists 判断文件是否存在
func (f *Filesystem) Exists(file string) (bool, error) {
	return f.mgr.Exists(context.Background(), file)
}

// FileInfo 获取文件信息
func (f *Filesystem) FileInfo(file string) (os.FileInfo, error) {
	objectInfo, err := f.mgr.Stat(context.Background(), file)
	if err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	return s3manager.NewFileInfo(objectInfo), nil
}

// SendFile 下载文件
func (f *Filesystem) SendFile(ctx echo.Context, file string) error {
	fp, err := f.mgr.Get(ctx, file)
	if err != nil {
		return errors.WithMessage(err, Name)
	}
	defer fp.Close()
	fileName := path.Base(file)
	inline := true
	err = ctx.Attachment(fp, fileName, inline)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// FileDir 物理路径文件夹
func (f *Filesystem) FileDir(subpath string) string {
	return path.Join(helper.UploadURLPath, f.Subdir, subpath)
}

// Put 上传文件
func (f *Filesystem) Put(dstFile string, src io.Reader, size int64) (savePath string, viewURL string, err error) {
	savePath = f.FileDir(dstFile)
	//viewURL = `[storage:`+param.AsString(f.model.Id)+`]`+f.URLDir(dstFile)
	viewURL = f.PublicURL(dstFile)
	err = f.mgr.Put(context.Background(), src, savePath, size)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return
}

// Get 获取文件读取接口
func (f *Filesystem) Get(dstFile string) (io.ReadCloser, error) {
	object, err := f.mgr.Get(context.Background(), dstFile)
	if err != nil {
		return nil, errors.WithMessage(err, Name)
	}
	exists, err := f.mgr.StatIsExists(object.Stat())
	if !exists {
		err = os.ErrNotExist
	}
	return object, err
}

// Delete 删除文件
func (f *Filesystem) Delete(dstFile string) error {
	err := f.mgr.Remove(context.Background(), dstFile)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// DeleteDir 删除文件夹及其内部文件
func (f *Filesystem) DeleteDir(dstDir string) error {
	err := f.mgr.RemoveDir(context.Background(), dstDir)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// Move 移动文件
func (f *Filesystem) Move(src, dst string) error {
	err := f.mgr.Rename(context.Background(), src, dst)
	if err != nil {
		err = errors.WithMessage(err, Name)
	}
	return err
}

// Close 关闭连接
func (f *Filesystem) Close() error {
	return nil
}

// FixURL 改写文件网址
func (f *Filesystem) FixURL(content string, embedded ...bool) string {
	rowsByID := f.model.CachedList()
	return helper.ReplacePlaceholder(content, func(id string) string {
		r, y := rowsByID[id]
		if !y {
			return ``
		}
		return r.Baseurl
	})
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/go-martini/martini"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/redigo/redis"
	"github.com/ninjasphere/sphere-go-homecloud/homecloud"
	"github.com/ninjasphere/sphere-go-homecloud/routes"
	"github.com/ninjasphere/sphere-go-homecloud/state"
)

// RestServer Holds stuff shared by all the rest services
type RestServer struct {
	redisPool *redis.Pool
	conn      *ninja.Connection

	roomModel    *homecloud.RoomModel
	thingModel   *homecloud.ThingModel
	deviceModel  *homecloud.DeviceModel
	stateManager state.StateManager
}

func NewRestServer(conn *ninja.Connection) *RestServer {

	conn, err := ninja.Connect("sphere-go-homecloud-rest")

	if err != nil {
		log.FatalError(err, "Failed to connect to mqtt")
	}

	return &RestServer{
		redisPool:    homecloud.RedisPool,
		conn:         conn,
		roomModel:    homecloud.NewRoomModel(homecloud.RedisPool, conn),
		thingModel:   homecloud.NewThingModel(homecloud.RedisPool, conn),
		deviceModel:  homecloud.NewDeviceModel(homecloud.RedisPool, conn),
		stateManager: state.NewStateManager(conn),
	}
}

func (r *RestServer) Listen() {

	m := martini.Classic()

	m.Map(r.roomModel)
	m.Map(r.thingModel)
	m.Map(r.deviceModel)
	m.Map(r.conn)
	m.Map(r.stateManager)

	location := routes.NewLocationRouter()
	thing := routes.NewThingRouter()
	room := routes.NewRoomRouter()

	m.Group("/rest/v1/locations", location.Register)
	m.Group("/rest/v1/things", thing.Register)
	m.Group("/rest/v1/rooms", room.Register)

	http.ListenAndServe(":8000", m)
}
<commit_msg>Add temporary apt upgrade REST call.<commit_after>package main

import (
	"net/http"

	"os/exec"
	"syscall"

	"github.com/go-martini/martini"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/redigo/redis"
	"github.com/ninjasphere/sphere-go-homecloud/homecloud"
	"github.com/ninjasphere/sphere-go-homecloud/routes"
	"github.com/ninjasphere/sphere-go-homecloud/state"
)

// RestServer Holds stuff shared by all the rest services
type RestServer struct {
	redisPool *redis.Pool
	conn      *ninja.Connection

	roomModel    *homecloud.RoomModel
	thingModel   *homecloud.ThingModel
	deviceModel  *homecloud.DeviceModel
	stateManager state.StateManager
}

func NewRestServer(conn *ninja.Connection) *RestServer {

	conn, err := ninja.Connect("sphere-go-homecloud-rest")

	if err != nil {
		log.FatalError(err, "Failed to connect to mqtt")
	}

	return &RestServer{
		redisPool:    homecloud.RedisPool,
		conn:         conn,
		roomModel:    homecloud.NewRoomModel(homecloud.RedisPool, conn),
		thingModel:   homecloud.NewThingModel(homecloud.RedisPool, conn),
		deviceModel:  homecloud.NewDeviceModel(homecloud.RedisPool, conn),
		stateManager: state.NewStateManager(conn),
	}
}

func (r *RestServer) Listen() {

	m := martini.Classic()

	m.Map(r.roomModel)
	m.Map(r.thingModel)
	m.Map(r.deviceModel)
	m.Map(r.conn)
	m.Map(r.stateManager)

	location := routes.NewLocationRouter()
	thing := routes.NewThingRouter()
	room := routes.NewRoomRouter()

	m.Group("/rest/v1/locations", location.Register)
	m.Group("/rest/v1/things", thing.Register)
	m.Group("/rest/v1/rooms", room.Register)

	// the following methods are temporary, and will go away at some stage once a real update process is in place
	m.Post("/rest/tmp/apt/update", func() string {
		cmd := exec.Command("/usr/bin/nohup", "/bin/sh", "-c", "apt-get update; apt-get dist-upgrade")
		cmd.SysProcAttr = &syscall.SysProcAttr{}
		cmd.SysProcAttr.Setpgid = true
		cmd.Start()
		return "OK"
	})

	http.ListenAndServe(":8000", m)
}
<|endoftext|>