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

package saml

import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"github.com/nu7hatch/gouuid"
	"io/ioutil"
	"net/url"
	"os"
	"os/exec"
	"strings"
	"time"
)

func NewAuthorizationRequest(appSettings AppSettings, accountSettings AccountSettings) *AuthorizationRequest {
	myIdUUID, err := uuid.NewV4()
	if err != nil {
		fmt.Println("Error is UUID Generation:", err)
	}
	//yyyy-MM-dd'T'H:mm:ss
	layout := "2006-01-02T15:04:05"
	t := time.Now().UTC().Format(layout)

	return &AuthorizationRequest{AccountSettings: accountSettings, AppSettings: appSettings, Id: "_" + myIdUUID.String(), IssueInstant: t}
}

// GetRequest returns a string formatted XML document that represents the SAML document
// TODO: parameterize more parts of the request
func (ar AuthorizationRequest) GetRequest(base64Encode bool) (string, error) {
	d := AuthnRequest{
		XMLName: xml.Name{
			Local: "samlp:AuthnRequest",
		},
		SAMLP:                       "urn:oasis:names:tc:SAML:2.0:protocol",
		SAML:                        "urn:oasis:names:tc:SAML:2.0:assertion",
		ID:                          ar.Id,
		ProtocolBinding:             "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
		Version:                     "2.0",
		AssertionConsumerServiceURL: ar.AppSettings.AssertionConsumerServiceURL,
		Issuer: Issuer{
			XMLName: xml.Name{
				Local: "saml:Issuer",
			},
			Url: "https://sp.example.com/SAML2",
		},
		IssueInstant: ar.IssueInstant,
		NameIDPolicy: NameIDPolicy{
			XMLName: xml.Name{
				Local: "samlp:NameIDPolicy",
			},
			AllowCreate: true,
			Format:      "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
		},
		RequestedAuthnContext: RequestedAuthnContext{
			XMLName: xml.Name{
				Local: "samlp:RequestedAuthnContext",
			},
			SAMLP:      "urn:oasis:names:tc:SAML:2.0:protocol",
			Comparison: "exact",

			AuthnContextClassRef: AuthnContextClassRef{
				XMLName: xml.Name{
					Local: "saml:AuthnContextClassRef",
				},
				SAML:      "urn:oasis:names:tc:SAML:2.0:assertion",
				Transport: "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
			},
		},
	}
	b, err := xml.MarshalIndent(d, "", "    ")
	if err != nil {
		return "", err
	}

	xmlAuthnRequest := fmt.Sprintf("<?xml version='1.0' encoding='UTF-8'?>\n%s", b)

	if base64Encode {
		data := []byte(xmlAuthnRequest)
		return base64.StdEncoding.EncodeToString(data), nil
	} else {
		return string(xmlAuthnRequest), nil
	}
}

// GetSignedRequest returns a string formatted XML document that represents the SAML document
// TODO: parameterize more parts of the request
func (ar AuthorizationRequest) GetSignedRequest(base64Encode bool, publicCert string, privateCert string) (string, error) {
	cert, err := LoadCertificate(publicCert)
	if err != nil {
		return "", err
	}

	d := AuthnSignedRequest{
		XMLName: xml.Name{
			Local: "samlp:AuthnRequest",
		},
		SAMLP:                       "urn:oasis:names:tc:SAML:2.0:protocol",
		SAML:                        "urn:oasis:names:tc:SAML:2.0:assertion",
		SAMLSIG:                     "http://www.w3.org/2000/09/xmldsig#",
		ID:                          ar.Id,
		ProtocolBinding:             "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
		Version:                     "2.0",
		AssertionConsumerServiceURL: ar.AppSettings.AssertionConsumerServiceURL,
		Issuer: Issuer{
			XMLName: xml.Name{
				Local: "saml:Issuer",
			},
			Url: "https://sp.example.com/SAML2",
		},
		IssueInstant: ar.IssueInstant,
		NameIDPolicy: NameIDPolicy{
			XMLName: xml.Name{
				Local: "samlp:NameIDPolicy",
			},
			AllowCreate: true,
			Format:      "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
		},
		RequestedAuthnContext: RequestedAuthnContext{
			XMLName: xml.Name{
				Local: "samlp:RequestedAuthnContext",
			},
			SAMLP:      "urn:oasis:names:tc:SAML:2.0:protocol",
			Comparison: "exact",
		},
		AuthnContextClassRef: AuthnContextClassRef{
			XMLName: xml.Name{
				Local: "saml:AuthnContextClassRef",
			},
			SAML:      "urn:oasis:names:tc:SAML:2.0:assertion",
			Transport: "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
		},
		Signature: Signature{
			XMLName: xml.Name{
				Local: "samlsig:Signature",
			},
			Id: "Signature1",
			SignedInfo: SignedInfo{
				XMLName: xml.Name{
					Local: "samlsig:SignedInfo",
				},
				CanonicalizationMethod: CanonicalizationMethod{
					XMLName: xml.Name{
						Local: "samlsig:CanonicalizationMethod",
					},
					Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#",
				},
				SignatureMethod: SignatureMethod{
					XMLName: xml.Name{
						Local: "samlsig:SignatureMethod",
					},
					Algorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
				},
				SamlsigReference: SamlsigReference{
					XMLName: xml.Name{
						Local: "samlsig:Reference",
					},
					URI: "#" + ar.Id,
					Transforms: Transforms{
						XMLName: xml.Name{
							Local: "samlsig:Transforms",
						},
						Transform: Transform{
							XMLName: xml.Name{
								Local: "samlsig:Transform",
							},
							Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
						},
					},
					DigestMethod: DigestMethod{
						XMLName: xml.Name{
							Local: "samlsig:DigestMethod",
						},
						Algorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
					},
					DigestValue: DigestValue{
						XMLName: xml.Name{
							Local: "samlsig:DigestValue",
						},
					},
				},
			},
			SignatureValue: SignatureValue{
				XMLName: xml.Name{
					Local: "samlsig:SignatureValue",
				},
			},
			KeyInfo: KeyInfo{
				XMLName: xml.Name{
					Local: "samlsig:KeyInfo",
				},
				X509Data: X509Data{
					XMLName: xml.Name{
						Local: "samlsig:X509Data",
					},
					X509Certificate: X509Certificate{
						XMLName: xml.Name{
							Local: "samlsig:X509Certificate",
						},
						Cert: cert,
					},
				},
			},
		},
	}
	b, err := xml.MarshalIndent(d, "", "    ")
	if err != nil {
		return "", err
	}

	samlAuthnRequest := string(b)
	// Write the SAML to a file.

	samlXmlsecInput, err := ioutil.TempFile(os.TempDir(), "tmpgs")
	if err != nil {
		return "", err
	}
	samlXmlsecOutput, err := ioutil.TempFile(os.TempDir(), "tmpgs")
	if err != nil {
		return "", err
	}

	samlXmlsecOutput.Close()

	samlXmlsecInput.WriteString("<?xml version='1.0' encoding='UTF-8'?>\n")
	samlXmlsecInput.WriteString(samlAuthnRequest)
	samlXmlsecInput.Close()

	_, errOut := exec.Command("xmlsec1", "--sign", "--privkey-pem", privateCert,
		"--id-attr:ID", "urn:oasis:names:tc:SAML:2.0:protocol:AuthnRequest",
		"--output", samlXmlsecOutput.Name(), samlXmlsecInput.Name()).Output()
	if errOut != nil {
		return "", errOut
	}

	samlSignedRequest, err := ioutil.ReadFile(samlXmlsecOutput.Name())
	if err != nil {
		return "", err
	}
	samlSignedRequestXml := strings.Trim(string(samlSignedRequest), "\n")

	if base64Encode {
		data := []byte(samlSignedRequestXml)
		return base64.StdEncoding.EncodeToString(data), nil
	} else {
		return string(samlSignedRequestXml), nil
	}
}

// String reqString = accSettings.getIdp_sso_target_url()+"?SAMLRequest=" +
// AuthRequest.getRidOfCRLF(URLEncoder.encode(authReq.getRequest(AuthRequest.base64),"UTF-8"));
func (ar AuthorizationRequest) GetRequestUrl() (string, error) {
	u, err := url.Parse(ar.AccountSettings.IDP_SSO_Target_URL)
	if err != nil {
		return "", err
	}
	base64EncodedUTF8SamlRequest, err := ar.GetRequest(true)
	if err != nil {
		return "", err
	}

	q := u.Query()
	q.Add("SAMLRequest", base64EncodedUTF8SamlRequest)

	u.RawQuery = q.Encode()
	return u.String(), nil
}

func NewAccountSettings(cert string, targetUrl string) *AccountSettings {
	return &AccountSettings{cert, targetUrl}
}

func NewAppSettings(assertionServiceUrl string, issuer string) *AppSettings {
	return &AppSettings{assertionServiceUrl, issuer}
}
<commit_msg>Parameterize Url from Issuer<commit_after>// Copyright 2014 Matthew Baird, Andrew Mussey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package saml

import (
	"encoding/base64"
	"encoding/xml"
	"fmt"
	"github.com/nu7hatch/gouuid"
	"io/ioutil"
	"net/url"
	"os"
	"os/exec"
	"strings"
	"time"
)

func NewAuthorizationRequest(appSettings AppSettings, accountSettings AccountSettings) *AuthorizationRequest {
	myIdUUID, err := uuid.NewV4()
	if err != nil {
		fmt.Println("Error is UUID Generation:", err)
	}
	//yyyy-MM-dd'T'H:mm:ss
	layout := "2006-01-02T15:04:05"
	t := time.Now().UTC().Format(layout)

	return &AuthorizationRequest{AccountSettings: accountSettings, AppSettings: appSettings, Id: "_" + myIdUUID.String(), IssueInstant: t}
}

// GetRequest returns a string formatted XML document that represents the SAML document
// TODO: parameterize more parts of the request
func (ar AuthorizationRequest) GetRequest(base64Encode bool) (string, error) {
	d := AuthnRequest{
		XMLName: xml.Name{
			Local: "samlp:AuthnRequest",
		},
		SAMLP:                       "urn:oasis:names:tc:SAML:2.0:protocol",
		SAML:                        "urn:oasis:names:tc:SAML:2.0:assertion",
		ID:                          ar.Id,
		ProtocolBinding:             "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
		Version:                     "2.0",
		AssertionConsumerServiceURL: ar.AppSettings.AssertionConsumerServiceURL,
		Issuer: Issuer{
			XMLName: xml.Name{
				Local: "saml:Issuer",
			},
			Url: ar.AppSettings.Issuer,
		},
		IssueInstant: ar.IssueInstant,
		NameIDPolicy: NameIDPolicy{
			XMLName: xml.Name{
				Local: "samlp:NameIDPolicy",
			},
			AllowCreate: true,
			Format:      "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
		},
		RequestedAuthnContext: RequestedAuthnContext{
			XMLName: xml.Name{
				Local: "samlp:RequestedAuthnContext",
			},
			SAMLP:      "urn:oasis:names:tc:SAML:2.0:protocol",
			Comparison: "exact",

			AuthnContextClassRef: AuthnContextClassRef{
				XMLName: xml.Name{
					Local: "saml:AuthnContextClassRef",
				},
				SAML:      "urn:oasis:names:tc:SAML:2.0:assertion",
				Transport: "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
			},
		},
	}
	b, err := xml.MarshalIndent(d, "", "    ")
	if err != nil {
		return "", err
	}

	xmlAuthnRequest := fmt.Sprintf("<?xml version='1.0' encoding='UTF-8'?>\n%s", b)

	if base64Encode {
		data := []byte(xmlAuthnRequest)
		return base64.StdEncoding.EncodeToString(data), nil
	} else {
		return string(xmlAuthnRequest), nil
	}
}

// GetSignedRequest returns a string formatted XML document that represents the SAML document
// TODO: parameterize more parts of the request
func (ar AuthorizationRequest) GetSignedRequest(base64Encode bool, publicCert string, privateCert string) (string, error) {
	cert, err := LoadCertificate(publicCert)
	if err != nil {
		return "", err
	}

	d := AuthnSignedRequest{
		XMLName: xml.Name{
			Local: "samlp:AuthnRequest",
		},
		SAMLP:                       "urn:oasis:names:tc:SAML:2.0:protocol",
		SAML:                        "urn:oasis:names:tc:SAML:2.0:assertion",
		SAMLSIG:                     "http://www.w3.org/2000/09/xmldsig#",
		ID:                          ar.Id,
		ProtocolBinding:             "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
		Version:                     "2.0",
		AssertionConsumerServiceURL: ar.AppSettings.AssertionConsumerServiceURL,
		Issuer: Issuer{
			XMLName: xml.Name{
				Local: "saml:Issuer",
			},
			Url: ar.AppSettings.Issuer,
		},
		IssueInstant: ar.IssueInstant,
		NameIDPolicy: NameIDPolicy{
			XMLName: xml.Name{
				Local: "samlp:NameIDPolicy",
			},
			AllowCreate: true,
			Format:      "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
		},
		RequestedAuthnContext: RequestedAuthnContext{
			XMLName: xml.Name{
				Local: "samlp:RequestedAuthnContext",
			},
			SAMLP:      "urn:oasis:names:tc:SAML:2.0:protocol",
			Comparison: "exact",
		},
		AuthnContextClassRef: AuthnContextClassRef{
			XMLName: xml.Name{
				Local: "saml:AuthnContextClassRef",
			},
			SAML:      "urn:oasis:names:tc:SAML:2.0:assertion",
			Transport: "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
		},
		Signature: Signature{
			XMLName: xml.Name{
				Local: "samlsig:Signature",
			},
			Id: "Signature1",
			SignedInfo: SignedInfo{
				XMLName: xml.Name{
					Local: "samlsig:SignedInfo",
				},
				CanonicalizationMethod: CanonicalizationMethod{
					XMLName: xml.Name{
						Local: "samlsig:CanonicalizationMethod",
					},
					Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#",
				},
				SignatureMethod: SignatureMethod{
					XMLName: xml.Name{
						Local: "samlsig:SignatureMethod",
					},
					Algorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
				},
				SamlsigReference: SamlsigReference{
					XMLName: xml.Name{
						Local: "samlsig:Reference",
					},
					URI: "#" + ar.Id,
					Transforms: Transforms{
						XMLName: xml.Name{
							Local: "samlsig:Transforms",
						},
						Transform: Transform{
							XMLName: xml.Name{
								Local: "samlsig:Transform",
							},
							Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature",
						},
					},
					DigestMethod: DigestMethod{
						XMLName: xml.Name{
							Local: "samlsig:DigestMethod",
						},
						Algorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
					},
					DigestValue: DigestValue{
						XMLName: xml.Name{
							Local: "samlsig:DigestValue",
						},
					},
				},
			},
			SignatureValue: SignatureValue{
				XMLName: xml.Name{
					Local: "samlsig:SignatureValue",
				},
			},
			KeyInfo: KeyInfo{
				XMLName: xml.Name{
					Local: "samlsig:KeyInfo",
				},
				X509Data: X509Data{
					XMLName: xml.Name{
						Local: "samlsig:X509Data",
					},
					X509Certificate: X509Certificate{
						XMLName: xml.Name{
							Local: "samlsig:X509Certificate",
						},
						Cert: cert,
					},
				},
			},
		},
	}
	b, err := xml.MarshalIndent(d, "", "    ")
	if err != nil {
		return "", err
	}

	samlAuthnRequest := string(b)
	// Write the SAML to a file.

	samlXmlsecInput, err := ioutil.TempFile(os.TempDir(), "tmpgs")
	if err != nil {
		return "", err
	}
	samlXmlsecOutput, err := ioutil.TempFile(os.TempDir(), "tmpgs")
	if err != nil {
		return "", err
	}

	samlXmlsecOutput.Close()

	samlXmlsecInput.WriteString("<?xml version='1.0' encoding='UTF-8'?>\n")
	samlXmlsecInput.WriteString(samlAuthnRequest)
	samlXmlsecInput.Close()

	_, errOut := exec.Command("xmlsec1", "--sign", "--privkey-pem", privateCert,
		"--id-attr:ID", "urn:oasis:names:tc:SAML:2.0:protocol:AuthnRequest",
		"--output", samlXmlsecOutput.Name(), samlXmlsecInput.Name()).Output()
	if errOut != nil {
		return "", errOut
	}

	samlSignedRequest, err := ioutil.ReadFile(samlXmlsecOutput.Name())
	if err != nil {
		return "", err
	}
	samlSignedRequestXml := strings.Trim(string(samlSignedRequest), "\n")

	if base64Encode {
		data := []byte(samlSignedRequestXml)
		return base64.StdEncoding.EncodeToString(data), nil
	} else {
		return string(samlSignedRequestXml), nil
	}
}

// String reqString = accSettings.getIdp_sso_target_url()+"?SAMLRequest=" +
// AuthRequest.getRidOfCRLF(URLEncoder.encode(authReq.getRequest(AuthRequest.base64),"UTF-8"));
func (ar AuthorizationRequest) GetRequestUrl() (string, error) {
	u, err := url.Parse(ar.AccountSettings.IDP_SSO_Target_URL)
	if err != nil {
		return "", err
	}
	base64EncodedUTF8SamlRequest, err := ar.GetRequest(true)
	if err != nil {
		return "", err
	}

	q := u.Query()
	q.Add("SAMLRequest", base64EncodedUTF8SamlRequest)

	u.RawQuery = q.Encode()
	return u.String(), nil
}

func NewAccountSettings(cert string, targetUrl string) *AccountSettings {
	return &AccountSettings{cert, targetUrl}
}

func NewAppSettings(assertionServiceUrl string, issuer string) *AppSettings {
	return &AppSettings{assertionServiceUrl, issuer}
}
<|endoftext|>


<commit_before>package config

import (
	"os"
	"testing"

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

const (
	testConfigPath = "./test.toml"
)

func TestConfigMustRead(t *testing.T) {
	Convey("while testing MustRead", t, func() {
		Convey("valid testConfigPath should return config", func() {
			So(func() { MustRead(testConfigPath) }, ShouldNotPanic)
			So(MustRead(testConfigPath), ShouldNotBeNil)
		})
		Convey("invalid testConfigPath should panic", func() {
			So(func() { MustRead("testConfigPath") }, ShouldPanic)
		})
		Convey("setting socialapi env should override config", func() {
			env := "MehmetAli"
			err := os.Setenv("SOCIAL_API_ENV", env)
			So(err, ShouldBeNil)
			// just to be sure about the function will not panic
			So(func() { MustRead(testConfigPath) }, ShouldNotPanic)
			a := MustRead(testConfigPath)
			So(a.Environment, ShouldEqual, env)
		})
	})
}
<commit_msg>config:socialapi env and hostame tests are added<commit_after>package config

import (
	"os"
	"testing"

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

const (
	testConfigPath = "./test.toml"
	env            = "MehmetAli"
	hostname       = "Koding"
)

func TestConfigMustRead(t *testing.T) {
	Convey("while testing MustRead", t, func() {
		Convey("valid testConfigPath should return config", func() {
			So(func() { MustRead(testConfigPath) }, ShouldNotPanic)
			So(MustRead(testConfigPath), ShouldNotBeNil)
		})
		Convey("invalid testConfigPath should panic", func() {
			So(func() { MustRead("testConfigPath") }, ShouldPanic)
		})
		Convey("setting socialapi env should override config", func() {
			err := os.Setenv("SOCIAL_API_ENV", env)
			So(err, ShouldBeNil)
			// just to be sure about the function will not panic
			So(func() { MustRead(testConfigPath) }, ShouldNotPanic)
			a := MustRead(testConfigPath)
			So(a.Environment, ShouldEqual, env)
		})
		Convey("setting socialapi hostname should override config", func() {
			err := os.Setenv("SOCIAL_API_HOSTNAME", hostname)
			So(err, ShouldBeNil)
			aPath := MustRead(testConfigPath)
			So(aPath.Uri, ShouldEqual, hostname)
		})
	})
}
<|endoftext|>


<commit_before>package models

import (
	"errors"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type Interaction struct {
	// unique identifier of the Interaction
	Id int64 `json:"id"`

	// Id of the interacted message
	MessageId int64 `json:"messageId"             sql:"NOT NULL"`

	// Id of the actor
	AccountId int64 `json:"accountId"             sql:"NOT NULL"`

	// Type of the interaction
	TypeConstant string `json:"typeConstant"      sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation of the interaction
	CreatedAt time.Time `json:"createdAt"         sql:"NOT NULL"`
}

var AllowedInteractions = map[string]struct{}{
	"like":     struct{}{},
	"upvote":   struct{}{},
	"downvote": struct{}{},
}

const (
	Interaction_TYPE_LIKE     = "like"
	Interaction_TYPE_UPVOTE   = "upvote"
	Interaction_TYPE_DONWVOTE = "downvote"
)

func (i *Interaction) GetId() int64 {
	return i.Id
}

func (i Interaction) TableName() string {
	return "api.interaction"
}

func NewInteraction() *Interaction {
	return &Interaction{}
}

func (i *Interaction) One(q *bongo.Query) error {
	return bongo.B.One(i, i, q)
}

func (i *Interaction) ById(id int64) error {
	return bongo.B.ById(i, id)
}

func (i *Interaction) Create() error {
	return bongo.B.Create(i)
}

func (i *Interaction) AfterCreate() {
	bongo.B.AfterCreate(i)
}

func (i *Interaction) AfterUpdate() {
	bongo.B.AfterUpdate(i)
}

func (i *Interaction) AfterDelete() {
	bongo.B.AfterDelete(i)
}

func (i *Interaction) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(i, data, q)
}

func (i *Interaction) Delete() error {
	if err := bongo.B.DB.
		Where("message_id = ? and account_id = ?", i.MessageId, i.AccountId).
		Delete(NewInteraction()).Error; err != nil {
		return err
	}
	return nil
}

func (c *Interaction) List(query *Query) ([]int64, error) {
	var interactions []int64

	if c.MessageId == 0 {
		return interactions, errors.New("Message is not set")
	}

	q := &bongo.Query{
		Selector: map[string]interface{}{
			"message_id":    c.MessageId,
			"type_constant": query.Type,
		},
		Pluck: "account_id",
		Skip:  query.Skip,
		Limit: query.Limit,
	}
	if c.Some(&interactions, q) != nil {
		return make([]int64, 0), nil
	}

	if interactions == nil {
		return make([]int64, 0), nil
	}

	return interactions, nil
}

func (c *Interaction) Count(interactionType string) (int, error) {
	if c.MessageId == 0 {
		return 0, errors.New("MessageId is not set")
	}

	return bongo.B.Count(c,
		"message_id = ? and type_constant = ?",
		c.MessageId,
		interactionType,
	)
}

func (c *Interaction) FetchAll(interactionType string) ([]Interaction, error) {
	var interactions []Interaction

	if c.MessageId == 0 {
		return interactions, errors.New("ChannelId is not set")
	}

	selector := map[string]interface{}{
		"message_id":    c.MessageId,
		"type_constant": interactionType,
	}

	err := c.Some(&interactions, bongo.NewQS(selector))
	if err != nil {
		return interactions, err
	}

	return interactions, nil
}

func (i *Interaction) IsInteracted(accountId int64) (bool, error) {
	if i.MessageId == 0 {
		return false, errors.New("Message Id is not set")
	}

	selector := map[string]interface{}{
		"message_id": i.MessageId,
		"account_id": accountId,
	}

	err := i.One(bongo.NewQS(selector))
	if err == nil {
		return true, nil
	}

	if err == gorm.RecordNotFound {
		return false, nil
	}

	return false, err
}
<commit_msg>Social: cleanup realtime event sending methods<commit_after>package models

import (
	"errors"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/koding/bongo"
)

type Interaction struct {
	// unique identifier of the Interaction
	Id int64 `json:"id"`

	// Id of the interacted message
	MessageId int64 `json:"messageId"             sql:"NOT NULL"`

	// Id of the actor
	AccountId int64 `json:"accountId"             sql:"NOT NULL"`

	// Type of the interaction
	TypeConstant string `json:"typeConstant"      sql:"NOT NULL;TYPE:VARCHAR(100);"`

	// Creation of the interaction
	CreatedAt time.Time `json:"createdAt"         sql:"NOT NULL"`
}

var AllowedInteractions = map[string]struct{}{
	"like":     struct{}{},
	"upvote":   struct{}{},
	"downvote": struct{}{},
}

const (
	Interaction_TYPE_LIKE     = "like"
	Interaction_TYPE_UPVOTE   = "upvote"
	Interaction_TYPE_DONWVOTE = "downvote"
)

func (i *Interaction) GetId() int64 {
	return i.Id
}

func (i Interaction) TableName() string {
	return "api.interaction"
}

func NewInteraction() *Interaction {
	return &Interaction{}
}

func (i *Interaction) One(q *bongo.Query) error {
	return bongo.B.One(i, i, q)
}

func (i *Interaction) ById(id int64) error {
	return bongo.B.ById(i, id)
}

func (i *Interaction) Create() error {
	return bongo.B.Create(i)
}

func (i *Interaction) AfterCreate() {
	bongo.B.AfterCreate(i)
}

func (i *Interaction) AfterUpdate() {
	bongo.B.AfterUpdate(i)
}

func (i *Interaction) AfterDelete() {
	bongo.B.AfterDelete(i)
}

func (i *Interaction) Some(data interface{}, q *bongo.Query) error {
	return bongo.B.Some(i, data, q)
}

func (i *Interaction) Delete() error {
	selector := map[string]interface{}{
		"message_id": i.MessageId,
		"account_id": i.AccountId,
	}

	if err := i.One(bongo.NewQS(selector)); err != nil {
		return err
	}

	if err := bongo.B.Delete(i); err != nil {
		return err
	}

	return nil
}

func (c *Interaction) List(query *Query) ([]int64, error) {
	var interactions []int64

	if c.MessageId == 0 {
		return interactions, errors.New("Message is not set")
	}

	q := &bongo.Query{
		Selector: map[string]interface{}{
			"message_id":    c.MessageId,
			"type_constant": query.Type,
		},
		Pluck: "account_id",
		Skip:  query.Skip,
		Limit: query.Limit,
	}
	if c.Some(&interactions, q) != nil {
		return make([]int64, 0), nil
	}

	if interactions == nil {
		return make([]int64, 0), nil
	}

	return interactions, nil
}

func (c *Interaction) Count(interactionType string) (int, error) {
	if c.MessageId == 0 {
		return 0, errors.New("MessageId is not set")
	}

	return bongo.B.Count(c,
		"message_id = ? and type_constant = ?",
		c.MessageId,
		interactionType,
	)
}

func (c *Interaction) FetchAll(interactionType string) ([]Interaction, error) {
	var interactions []Interaction

	if c.MessageId == 0 {
		return interactions, errors.New("ChannelId is not set")
	}

	selector := map[string]interface{}{
		"message_id":    c.MessageId,
		"type_constant": interactionType,
	}

	err := c.Some(&interactions, bongo.NewQS(selector))
	if err != nil {
		return interactions, err
	}

	return interactions, nil
}

func (i *Interaction) IsInteracted(accountId int64) (bool, error) {
	if i.MessageId == 0 {
		return false, errors.New("Message Id is not set")
	}

	selector := map[string]interface{}{
		"message_id": i.MessageId,
		"account_id": accountId,
	}

	err := i.One(bongo.NewQS(selector))
	if err == nil {
		return true, nil
	}

	if err == gorm.RecordNotFound {
		return false, nil
	}

	return false, err
}
<|endoftext|>


<commit_before>//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Vitess Authors.

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

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

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

/*
	DEPENDENCIES:
	This fuzzer relies heavily on
	$VTROOT/go/vt/vtgate/engine/fake_vcursor_test.go,
	and in order to run it, it is required to rename:
	$VTROOT/go/vt/vtgate/engine/fake_vcursor_test.go
	to
	$VTROOT/go/vt/vtgate/engine/fake_vcursor.go

	This is handled by the OSS-fuzz build script and
	is only important to make note of if the fuzzer
	is run locally.

	STATUS:
	The fuzzer does not currently implement executions
	for all possible API's in the engine package, and
	it can be considered experimental, as I (@AdamKorcz)
	am interested in its performance when being run
	continuously by OSS-fuzz. Needless to say, more
	APIs can be added with ease.
*/
// +build gofuzz

package engine

import (
	"errors"

	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vtgate/vindexes"

	"vitess.io/vitess/go/sqltypes"
	querypb "vitess.io/vitess/go/vt/proto/query"
	vschemapb "vitess.io/vitess/go/vt/proto/vschema"

	fuzz "github.com/AdaLogics/go-fuzz-headers"

	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	"vitess.io/vitess/go/vt/vtgate/evalengine"
)

func createVSchema() (vschema *vindexes.VSchema, err error) {
	invschema := &vschemapb.SrvVSchema{
		Keyspaces: map[string]*vschemapb.Keyspace{
			"sharded": {
				Sharded: true,
				Vindexes: map[string]*vschemapb.Vindex{
					"primary": {
						Type: "lookup_unique",
						Params: map[string]string{
							"table": "prim",
							"from":  "from1",
							"to":    "toc",
						},
					},
				},
				Tables: map[string]*vschemapb.Table{
					"t1": {
						ColumnVindexes: []*vschemapb.ColumnVindex{{
							Name:    "primary",
							Columns: []string{"id"},
						}},
					},
				},
			},
		},
	}
	vs := vindexes.BuildVSchema(invschema)
	if err != nil {
		return nil, err
	}
	return vs, nil
}

// FuzzEngine implements the fuzzer
func FuzzEngine(data []byte) int {
	c := fuzz.NewConsumer(data)
	vc := newFuzzDMLTestVCursor("0")
	vs, err := createVSchema()
	if err != nil {
		return -1
	}
	for i := 0; i < 20; i++ {
		newInt, err := c.GetInt()
		if err != nil {
			return -1
		}
		execCommand(newInt%7, c, vc, vs)
	}
	return 1
}

func execUnshardedUpdate(query string, vc *loggingVCursor) {
	upd := &Update{
		DML: DML{
			Opcode: Unsharded,
			Keyspace: &vindexes.Keyspace{
				Name:    "ks",
				Sharded: false,
			},
			Query: query,
		},
	}
	_, _ = upd.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execUnshardedInsert(query string, vc *loggingVCursor) {
	ins := &Insert{
		Opcode: InsertUnsharded,
		Keyspace: &vindexes.Keyspace{
			Name:    "ks",
			Sharded: false,
		},
		Query: query,
	}
	_, _ = ins.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execShardedInsert(query string, vc *loggingVCursor, vs *vindexes.VSchema) {
	ks := vs.Keyspaces["sharded"]
	ins := NewInsert(
		InsertSharded,
		ks.Keyspace,
		[]sqltypes.PlanValue{{
			Values: []sqltypes.PlanValue{{
				Values: []sqltypes.PlanValue{{
					Value: sqltypes.NewVarChar(query),
				}},
			}},
		}},
		ks.Tables["t1"],
		"prefix",
		[]string{" mid1", " mid2", " mid3"},
		" suffix",
	)
	_, _ = ins.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execUnshardedRoute(query, field string, vc *loggingVCursor) {
	sel := NewRoute(
		SelectUnsharded,
		&vindexes.Keyspace{
			Name:    "ks",
			Sharded: false,
		},
		query,
		field,
	)
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execShardedRoute(query, field string, vc *loggingVCursor) {
	sel := NewRoute(
		SelectScatter,
		&vindexes.Keyspace{
			Name:    "ks",
			Sharded: true,
		},
		query,
		field,
	)
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execEqualUniqueRoute(query, field, hash, value string, vc *loggingVCursor) {
	vindex, _ := vindexes.NewHash(hash, nil)
	sel := NewRoute(
		SelectEqualUnique,
		&vindexes.Keyspace{
			Name:    "ks",
			Sharded: true,
		},
		query,
		field,
	)
	sel.Vindex = vindex.(vindexes.SingleColumn)
	sel.Values = []sqltypes.PlanValue{{Value: sqltypes.NewVarChar(value)}}
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

var defaultFuzzSelectResult = sqltypes.MakeTestResult(
	sqltypes.MakeTestFields(
		"id",
		"int64",
	),
	"1",
)

func execRouteSelectDBA(query, field, tablename, schema, shards string) {
	stringToExpr := func(in string) []evalengine.Expr {
		var schema []evalengine.Expr
		if in != "" {
			schema = []evalengine.Expr{evalengine.NewLiteralString([]byte(in))}
		}
		return schema
	}

	sel := &Route{
		Opcode: SelectDBA,
		Keyspace: &vindexes.Keyspace{
			Name:    "ks",
			Sharded: false,
		},
		Query:               query,
		FieldQuery:          field,
		SysTableTableSchema: stringToExpr(schema),
		SysTableTableName:   map[string]evalengine.Expr{"table_name": evalengine.NewLiteralString([]byte(tablename))},
	}
	vc := &loggingVCursor{
		shards:  []string{shards},
		results: []*sqltypes.Result{defaultFuzzSelectResult},
	}

	vc.tableRoutes = tableRoutes{
		tbl: &vindexes.Table{
			Name:     sqlparser.NewTableIdent("routedTable"),
			Keyspace: &vindexes.Keyspace{Name: "routedKeyspace"},
		}}
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func queryAndField(c *fuzz.ConsumeFuzzer) (string, string, error) {
	query, err := c.GetString()
	if err != nil {
		return "nil", "nil", err
	}
	field, err := c.GetString()
	if err != nil {
		return "nil", "nil", err
	}
	return query, field, nil
}

func execCommand(index int, c *fuzz.ConsumeFuzzer, vc *loggingVCursor, vs *vindexes.VSchema) error {
	switch i := index; i {
	case 0:
		query, err := c.GetString()
		if err != nil {
			return err
		}
		execUnshardedUpdate(query, vc)
		return nil
	case 1:
		query, err := c.GetString()
		if err != nil {
			return err
		}
		execUnshardedInsert(query, vc)
		return nil
	case 2:
		query, err := c.GetString()
		if err != nil {
			return err
		}
		execShardedInsert(query, vc, vs)
		return nil
	case 3:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		execUnshardedRoute(query, field, vc)
		return nil
	case 4:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		execShardedRoute(query, field, vc)
		return nil
	case 5:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		hash, err := c.GetString()
		if err != nil {
			return err
		}
		value, err := c.GetString()
		if err != nil {
			return err
		}
		execEqualUniqueRoute(query, field, hash, value, vc)
		return nil
	case 6:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		tablename, err := c.GetString()
		if err != nil {
			return err
		}
		schema, err := c.GetString()
		if err != nil {
			return err
		}
		shards, err := c.GetString()
		if err != nil {
			return err
		}
		execRouteSelectDBA(query, field, tablename, schema, shards)
		return nil
	default:
		return errors.New("Could not exec")
	}
}

func newFuzzDMLTestVCursor(shards ...string) *loggingVCursor {
	return &loggingVCursor{shards: shards, resolvedTargetTabletType: topodatapb.TabletType_PRIMARY}
}
<commit_msg>Removing additional gobuild construct<commit_after>//go:build gofuzz
// +build gofuzz

/*
Copyright 2021 The Vitess Authors.

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

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

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

/*
	DEPENDENCIES:
	This fuzzer relies heavily on
	$VTROOT/go/vt/vtgate/engine/fake_vcursor_test.go,
	and in order to run it, it is required to rename:
	$VTROOT/go/vt/vtgate/engine/fake_vcursor_test.go
	to
	$VTROOT/go/vt/vtgate/engine/fake_vcursor.go

	This is handled by the OSS-fuzz build script and
	is only important to make note of if the fuzzer
	is run locally.

	STATUS:
	The fuzzer does not currently implement executions
	for all possible API's in the engine package, and
	it can be considered experimental, as I (@AdamKorcz)
	am interested in its performance when being run
	continuously by OSS-fuzz. Needless to say, more
	APIs can be added with ease.
*/

package engine

import (
	"errors"

	"vitess.io/vitess/go/vt/sqlparser"
	"vitess.io/vitess/go/vt/vtgate/vindexes"

	"vitess.io/vitess/go/sqltypes"
	querypb "vitess.io/vitess/go/vt/proto/query"
	vschemapb "vitess.io/vitess/go/vt/proto/vschema"

	fuzz "github.com/AdaLogics/go-fuzz-headers"

	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	"vitess.io/vitess/go/vt/vtgate/evalengine"
)

func createVSchema() (vschema *vindexes.VSchema, err error) {
	invschema := &vschemapb.SrvVSchema{
		Keyspaces: map[string]*vschemapb.Keyspace{
			"sharded": {
				Sharded: true,
				Vindexes: map[string]*vschemapb.Vindex{
					"primary": {
						Type: "lookup_unique",
						Params: map[string]string{
							"table": "prim",
							"from":  "from1",
							"to":    "toc",
						},
					},
				},
				Tables: map[string]*vschemapb.Table{
					"t1": {
						ColumnVindexes: []*vschemapb.ColumnVindex{{
							Name:    "primary",
							Columns: []string{"id"},
						}},
					},
				},
			},
		},
	}
	vs := vindexes.BuildVSchema(invschema)
	if err != nil {
		return nil, err
	}
	return vs, nil
}

// FuzzEngine implements the fuzzer
func FuzzEngine(data []byte) int {
	c := fuzz.NewConsumer(data)
	vc := newFuzzDMLTestVCursor("0")
	vs, err := createVSchema()
	if err != nil {
		return -1
	}
	for i := 0; i < 20; i++ {
		newInt, err := c.GetInt()
		if err != nil {
			return -1
		}
		execCommand(newInt%7, c, vc, vs)
	}
	return 1
}

func execUnshardedUpdate(query string, vc *loggingVCursor) {
	upd := &Update{
		DML: DML{
			Opcode: Unsharded,
			Keyspace: &vindexes.Keyspace{
				Name:    "ks",
				Sharded: false,
			},
			Query: query,
		},
	}
	_, _ = upd.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execUnshardedInsert(query string, vc *loggingVCursor) {
	ins := &Insert{
		Opcode: InsertUnsharded,
		Keyspace: &vindexes.Keyspace{
			Name:    "ks",
			Sharded: false,
		},
		Query: query,
	}
	_, _ = ins.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execShardedInsert(query string, vc *loggingVCursor, vs *vindexes.VSchema) {
	ks := vs.Keyspaces["sharded"]
	ins := NewInsert(
		InsertSharded,
		ks.Keyspace,
		[]sqltypes.PlanValue{{
			Values: []sqltypes.PlanValue{{
				Values: []sqltypes.PlanValue{{
					Value: sqltypes.NewVarChar(query),
				}},
			}},
		}},
		ks.Tables["t1"],
		"prefix",
		[]string{" mid1", " mid2", " mid3"},
		" suffix",
	)
	_, _ = ins.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execUnshardedRoute(query, field string, vc *loggingVCursor) {
	sel := NewRoute(
		SelectUnsharded,
		&vindexes.Keyspace{
			Name:    "ks",
			Sharded: false,
		},
		query,
		field,
	)
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execShardedRoute(query, field string, vc *loggingVCursor) {
	sel := NewRoute(
		SelectScatter,
		&vindexes.Keyspace{
			Name:    "ks",
			Sharded: true,
		},
		query,
		field,
	)
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func execEqualUniqueRoute(query, field, hash, value string, vc *loggingVCursor) {
	vindex, _ := vindexes.NewHash(hash, nil)
	sel := NewRoute(
		SelectEqualUnique,
		&vindexes.Keyspace{
			Name:    "ks",
			Sharded: true,
		},
		query,
		field,
	)
	sel.Vindex = vindex.(vindexes.SingleColumn)
	sel.Values = []sqltypes.PlanValue{{Value: sqltypes.NewVarChar(value)}}
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

var defaultFuzzSelectResult = sqltypes.MakeTestResult(
	sqltypes.MakeTestFields(
		"id",
		"int64",
	),
	"1",
)

func execRouteSelectDBA(query, field, tablename, schema, shards string) {
	stringToExpr := func(in string) []evalengine.Expr {
		var schema []evalengine.Expr
		if in != "" {
			schema = []evalengine.Expr{evalengine.NewLiteralString([]byte(in))}
		}
		return schema
	}

	sel := &Route{
		Opcode: SelectDBA,
		Keyspace: &vindexes.Keyspace{
			Name:    "ks",
			Sharded: false,
		},
		Query:               query,
		FieldQuery:          field,
		SysTableTableSchema: stringToExpr(schema),
		SysTableTableName:   map[string]evalengine.Expr{"table_name": evalengine.NewLiteralString([]byte(tablename))},
	}
	vc := &loggingVCursor{
		shards:  []string{shards},
		results: []*sqltypes.Result{defaultFuzzSelectResult},
	}

	vc.tableRoutes = tableRoutes{
		tbl: &vindexes.Table{
			Name:     sqlparser.NewTableIdent("routedTable"),
			Keyspace: &vindexes.Keyspace{Name: "routedKeyspace"},
		}}
	_, _ = sel.Execute(vc, map[string]*querypb.BindVariable{}, false)
}

func queryAndField(c *fuzz.ConsumeFuzzer) (string, string, error) {
	query, err := c.GetString()
	if err != nil {
		return "nil", "nil", err
	}
	field, err := c.GetString()
	if err != nil {
		return "nil", "nil", err
	}
	return query, field, nil
}

func execCommand(index int, c *fuzz.ConsumeFuzzer, vc *loggingVCursor, vs *vindexes.VSchema) error {
	switch i := index; i {
	case 0:
		query, err := c.GetString()
		if err != nil {
			return err
		}
		execUnshardedUpdate(query, vc)
		return nil
	case 1:
		query, err := c.GetString()
		if err != nil {
			return err
		}
		execUnshardedInsert(query, vc)
		return nil
	case 2:
		query, err := c.GetString()
		if err != nil {
			return err
		}
		execShardedInsert(query, vc, vs)
		return nil
	case 3:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		execUnshardedRoute(query, field, vc)
		return nil
	case 4:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		execShardedRoute(query, field, vc)
		return nil
	case 5:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		hash, err := c.GetString()
		if err != nil {
			return err
		}
		value, err := c.GetString()
		if err != nil {
			return err
		}
		execEqualUniqueRoute(query, field, hash, value, vc)
		return nil
	case 6:
		query, field, err := queryAndField(c)
		if err != nil {
			return err
		}
		tablename, err := c.GetString()
		if err != nil {
			return err
		}
		schema, err := c.GetString()
		if err != nil {
			return err
		}
		shards, err := c.GetString()
		if err != nil {
			return err
		}
		execRouteSelectDBA(query, field, tablename, schema, shards)
		return nil
	default:
		return errors.New("Could not exec")
	}
}

func newFuzzDMLTestVCursor(shards ...string) *loggingVCursor {
	return &loggingVCursor{shards: shards, resolvedTargetTabletType: topodatapb.TabletType_PRIMARY}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

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

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

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

package vindexes

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io/ioutil"

	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/key"
	"vitess.io/vitess/go/vt/log"
)

var (
	_ MultiColumn   = (*RegionVindex)(nil)
)

func init() {
	Register("region_vindex", NewRegionVindex)
}

// RegionMap is used to store mapping of country to region
type RegionMap map[string]uint64

// RegionVindex defines a vindex that uses a lookup table.
// The table is expected to define the id column as unique. It's
// Unique and a Lookup.
type RegionVindex struct {
	name        string
	regionMap   RegionMap
	regionBytes int
}

// NewRegionVindex creates a RegionVindex vindex.
// The supplied map requires all the fields of "region_experimental".
// Additionally, it requires a region_map argument representing the path to a json file
// containing a map of country to region.
func NewRegionVindex(name string, m map[string]string) (Vindex, error) {
	rmPath := m["region_map"]
	rmap := make(map[string]uint64)
	data, err := ioutil.ReadFile(rmPath)
	if err != nil {
		return nil, err
	}
	log.Infof("Loaded Region map from: %s", rmPath)
	err = json.Unmarshal(data, &rmap)
	if err != nil {
		return nil, err
	}

	return &RegionVindex{
		name:      name,
		regionMap: rmap,
	}, nil
}

// String returns the name of the vindex.
func (rv *RegionVindex) String() string {
	return rv.name
}

// Cost returns the cost of this index as 1.
func (rv *RegionVindex) Cost() int {
	return 1
}

// IsUnique returns true since the Vindex is unique.
func (rv *RegionVindex) IsUnique() bool {
	return true;
}

// Map satisfies MultiColumn.
func (rv *RegionVindex) Map(vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) {
	destinations := make([]key.Destination, 0, len(rowsColValues))
	for _, row := range rowsColValues {
		if len(row) != 2 {
			destinations = append(destinations, key.DestinationNone{})
			continue
		}
		// Compute hash.
		hn, err := sqltypes.ToUint64(row[0])
		if err != nil {
			destinations = append(destinations, key.DestinationNone{})
			continue
		}
		h := vhash(hn)

		log.Infof("Region map: %v", rv.regionMap)
		// Compute region prefix.
		log.Infof("Country: %v", row[1].ToString())
		rn, ok := rv.regionMap[row[1].ToString()]
		log.Infof("Found region %v, true/false: %v", rn, ok)
		if !ok {
			destinations = append(destinations, key.DestinationNone{})
			continue
		}
		r := make([]byte, 2)
		binary.BigEndian.PutUint16(r, uint16(rn))

		// Concatenate and add to destinations.
		if rv.regionBytes == 1 {
			r = r[1:]
		}
		dest := append(r, h...)
		destinations = append(destinations, key.DestinationKeyspaceID(dest))
	}
	return destinations, nil
}

// NeedVCursor staisfies the Vindex interface.
func (rv *RegionVindex) NeedVCursor() bool {
	return false
}<commit_msg>Removed extra import.  NeedVCursor -> NeedsVCursor<commit_after>/*
Copyright 2019 The Vitess Authors.

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

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

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

package vindexes

import (
	"encoding/binary"
	"encoding/json"
	"io/ioutil"

	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/key"
	"vitess.io/vitess/go/vt/log"
)

var (
	_ MultiColumn   = (*RegionVindex)(nil)
)

func init() {
	Register("region_vindex", NewRegionVindex)
}

// RegionMap is used to store mapping of country to region
type RegionMap map[string]uint64

// RegionVindex defines a vindex that uses a lookup table.
// The table is expected to define the id column as unique. It's
// Unique and a Lookup.
type RegionVindex struct {
	name        string
	regionMap   RegionMap
	regionBytes int
}

// NewRegionVindex creates a RegionVindex vindex.
// The supplied map requires all the fields of "region_experimental".
// Additionally, it requires a region_map argument representing the path to a json file
// containing a map of country to region.
func NewRegionVindex(name string, m map[string]string) (Vindex, error) {
	rmPath := m["region_map"]
	rmap := make(map[string]uint64)
	data, err := ioutil.ReadFile(rmPath)
	if err != nil {
		return nil, err
	}
	log.Infof("Loaded Region map from: %s", rmPath)
	err = json.Unmarshal(data, &rmap)
	if err != nil {
		return nil, err
	}

	return &RegionVindex{
		name:      name,
		regionMap: rmap,
	}, nil
}

// String returns the name of the vindex.
func (rv *RegionVindex) String() string {
	return rv.name
}

// Cost returns the cost of this index as 1.
func (rv *RegionVindex) Cost() int {
	return 1
}

// IsUnique returns true since the Vindex is unique.
func (rv *RegionVindex) IsUnique() bool {
	return true;
}

// Map satisfies MultiColumn.
func (rv *RegionVindex) Map(vcursor VCursor, rowsColValues [][]sqltypes.Value) ([]key.Destination, error) {
	destinations := make([]key.Destination, 0, len(rowsColValues))
	for _, row := range rowsColValues {
		if len(row) != 2 {
			destinations = append(destinations, key.DestinationNone{})
			continue
		}
		// Compute hash.
		hn, err := sqltypes.ToUint64(row[0])
		if err != nil {
			destinations = append(destinations, key.DestinationNone{})
			continue
		}
		h := vhash(hn)

		log.Infof("Region map: %v", rv.regionMap)
		// Compute region prefix.
		log.Infof("Country: %v", row[1].ToString())
		rn, ok := rv.regionMap[row[1].ToString()]
		log.Infof("Found region %v, true/false: %v", rn, ok)
		if !ok {
			destinations = append(destinations, key.DestinationNone{})
			continue
		}
		r := make([]byte, 2)
		binary.BigEndian.PutUint16(r, uint16(rn))

		// Concatenate and add to destinations.
		if rv.regionBytes == 1 {
			r = r[1:]
		}
		dest := append(r, h...)
		destinations = append(destinations, key.DestinationKeyspaceID(dest))
	}
	return destinations, nil
}

// NeedVCursor staisfies the Vindex interface.
func (rv *RegionVindex) NeedsVCursor() bool {
	return false
}<|endoftext|>


<commit_before>package testutils

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"io/ioutil"
	"log"
	"os"
	"testing"
)

func TempDir(t *testing.T) string {
	dir, err := ioutil.TempDir("", "bazel-remote")
	if err != nil {
		t.Fatal(err)
	}
	return dir
}

func CreateCacheFile(dir string, size int64) (string, error) {
	data, hash := RandomDataAndHash(size)
	subdir := dir + "/" + hash[0:2]
	os.MkdirAll(subdir, os.ModePerm)
	filepath := subdir + "/" + hash

	return hash, ioutil.WriteFile(filepath, data, os.ModePerm)
}

func RandomDataAndHash(size int64) ([]byte, string) {
	data := make([]byte, size)
	rand.Read(data)
	hash := sha256.Sum256(data)
	hashStr := hex.EncodeToString(hash[:])
	return data, hashStr
}

// NewSilentLogger returns a cheap logger that doesn't print anything, useful
// for tests.
func NewSilentLogger() *log.Logger {
	return log.New(ioutil.Discard, "", 0)
}
<commit_msg>testutils: add godoc-style comments<commit_after>package testutils

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"io/ioutil"
	"log"
	"os"
	"testing"
)

// TempDir creates a temporary directory and returns its name. If an error
// occurs, then it panics.
func TempDir(t *testing.T) string {
	dir, err := ioutil.TempDir("", "bazel-remote")
	if err != nil {
		t.Fatal(err)
	}
	return dir
}

// CreateCacheFile creates a random data file of the given size in the
// provided directory (corresponding to one of bazel-remote's keyspaces)
// and returns its sha256 hash and any error that occurred.
func CreateCacheFile(dir string, size int64) (string, error) {
	data, hash := RandomDataAndHash(size)
	subdir := dir + "/" + hash[0:2]
	os.MkdirAll(subdir, os.ModePerm)
	filepath := subdir + "/" + hash

	return hash, ioutil.WriteFile(filepath, data, os.ModePerm)
}

// RandomDataAndHash creates a random blob of the specified size, and
// returns that blob along with its sha256 hash.
func RandomDataAndHash(size int64) ([]byte, string) {
	data := make([]byte, size)
	rand.Read(data)
	hash := sha256.Sum256(data)
	hashStr := hex.EncodeToString(hash[:])
	return data, hashStr
}

// NewSilentLogger returns a cheap logger that doesn't print anything, useful
// for tests.
func NewSilentLogger() *log.Logger {
	return log.New(ioutil.Discard, "", 0)
}
<|endoftext|>


<commit_before>/*
    Spacedex, the new and improved Docker index.
 */
package main

import (
  "fmt"
  "github.com/codegangsta/cli"
  "github.com/ricallinson/forgery"
  "github.com/ricallinson/stackr"
  "github.com/southern/logger"
  "github.com/southern/middleware"
  "github.com/spacedock-io/index/config"
  "github.com/spacedock-io/index/couch"
  "os"
)

func main() {
  // Initialize new CLI app
  app := cli.NewApp()

  // Initialize new Forgery server
  server := f.CreateServer()
  server.Use(middleware.BodyParser)
  server.Use(func(req *stackr.Request, res *stackr.Response, next func()) {
    res.SetHeader("X-Docker-Registry-Version", "0.7.4")
    next()
  })

  app.Name = "spacedex"
  app.Author = "Spacedock"
  app.Email = "hello@spacedock.io"
  app.Usage = "Run a standalone Docker index"
  app.Version = "0.0.1"
  app.Flags = []cli.Flag {
    // No default value here, so that our <env>.config.json file will override
    // it.
    cli.StringFlag{"port, p", "", "Port to listen on"},
    cli.StringFlag{"env, e", "dev", "Default environment"},
    cli.StringFlag{"config, c", "", "Configuration directory"},
  }

  app.Action = func (c *cli.Context) {
    env := c.String("env")
    dir := c.String("config")

    // Default to dev if someone enters a blank string
    if len(env) == 0 {
      env = "dev"
    }
    if len(dir) > 0 {
      config.Dir = dir
    }

    config.Global = config.Load(env)
    config.Logger = logger.New()

    port := c.Int("port")
    if port == 0 {
      // Bug(Colton): Not quite sure why port is being picked up as Float64 at
      // the moment. Still looking into this. It may be intended functionality.
      port = int(config.Global.Get("port").Float64())
    }

    config.Logger.Debug = config.Global.Get("logger.debug").Bool(false)
    config.Logger.Exit = config.Global.Get("logger.exit").Bool(false)

    couch.Global = couch.New(config.Global)
    Routes(server)

    config.Logger.Log("Index listening on port " + fmt.Sprint(port))
    server.Listen(port)
  }

  app.Run(os.Args)
}
<commit_msg>Initialize postgres connection<commit_after>/*
    Spacedex, the new and improved Docker index.
 */
package main

import (
  "fmt"
  "github.com/codegangsta/cli"
  "github.com/ricallinson/forgery"
  "github.com/ricallinson/stackr"
  "github.com/southern/logger"
  "github.com/southern/middleware"
  "github.com/spacedock-io/index/config"
  "github.com/spacedock-io/registry/db"
  _ "github.com/lib/pq"
  "os"
)

func main() {
  // Initialize new CLI app
  app := cli.NewApp()

  // Initialize new Forgery server
  server := f.CreateServer()
  server.Use(middleware.BodyParser)
  server.Use(func(req *stackr.Request, res *stackr.Response, next func()) {
    res.SetHeader("X-Docker-Registry-Version", "0.7.4")
    next()
  })

  app.Name = "spacedex"
  app.Author = "Spacedock"
  app.Email = "hello@spacedock.io"
  app.Usage = "Run a standalone Docker index"
  app.Version = "0.0.1"
  app.Flags = []cli.Flag {
    // No default value here, so that our <env>.config.json file will override
    // it.
    cli.StringFlag{"port, p", "", "Port to listen on"},
    cli.StringFlag{"env, e", "dev", "Default environment"},
    cli.StringFlag{"config, c", "", "Configuration directory"},
  }

  app.Action = func (c *cli.Context) {
    env := c.String("env")
    dir := c.String("config")

    // Default to dev if someone enters a blank string
    if len(env) == 0 {
      env = "dev"
    }
    if len(dir) > 0 {
      config.Dir = dir
    }

    config.Global = config.Load(env)
    config.Logger = logger.New()

    port := c.Int("port")
    if port == 0 {
      // Bug(Colton): Not quite sure why port is being picked up as Float64 at
      // the moment. Still looking into this. It may be intended functionality.
      port = int(config.Global.Get("port").Float64())
    }

    config.Logger.Debug = config.Global.Get("logger.debug").Bool(false)
    config.Logger.Exit = config.Global.Get("logger.exit").Bool(false)

    db.New(config.Global)
    Routes(server)

    config.Logger.Log("Index listening on port " + fmt.Sprint(port))
    server.Listen(port)
  }

  app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/exec"
	"syscall"
)

type SSHCommand struct{}

func (c *SSHCommand) Execute(args []string) error {
	path, err := exec.LookPath("ssh")
	if err != nil {
		return err
	}

	args = append([]string{"", "local.docker"}, args...)
	return syscall.Exec(path, args, os.Environ())
}

func init() {
	var sshCommand SSHCommand
	cmd.AddCommand("ssh", "ssh shortcut", "run an ssh client connected to your vm", &sshCommand)
}
<commit_msg>lookup actual hostname, for #120<commit_after>package main

import (
	"os"
	"os/exec"
	"syscall"
)

type SSHCommand struct{}

func (c *SSHCommand) Execute(args []string) error {
	config, err := ReadConfig()
	if err != nil {
		return err
	}

	path, err := exec.LookPath("ssh")
	if err != nil {
		return err
	}

	args = append([]string{"", config.Hostname}, args...)
	return syscall.Exec(path, args, os.Environ())
}

func init() {
	var sshCommand SSHCommand
	cmd.AddCommand("ssh", "ssh shortcut", "run an ssh client connected to your vm", &sshCommand)
}
<|endoftext|>


<commit_before>package sshclient

//Handle all ssh connection and run command

import (
	"fmt"
	"golang.org/x/crypto/ssh"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

type SSHAuthTypeEnum int

const (
	//Type authentication login in ssh, it can using password or using public-private key
	SSHAuthType_Password SSHAuthTypeEnum = iota
	SSHAuthType_Certificate
)

type SshSetting struct {
	//Setting information for ssh connection
	SSHHost        string
	SSHUser        string
	SSHPassword    string
	SSHKeyLocation string
	SSHAuthType    SSHAuthTypeEnum
}

var (
	ECHO uint32 = 0
)

/*
Parsing private key certicate using for connection over ssh
*/
func PublicKeyFile(file string) ssh.AuthMethod {
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		return nil
	}

	key, err := ssh.ParsePrivateKey(buffer)
	if err != nil {
		return nil
	}
	return ssh.PublicKeys(key)
}

/*
Build connection ssh client to ssh server
*/
func (S *SshSetting) Connect() (*ssh.Client, error) {
	var (
		cfg *ssh.ClientConfig
	)

	if S.SSHAuthType == SSHAuthType_Certificate {
		cfg = &ssh.ClientConfig{
			User: S.SSHUser,
			Auth: []ssh.AuthMethod{
				PublicKeyFile(S.SSHKeyLocation),
			},
		}
	} else {
		cfg = &ssh.ClientConfig{
			User: S.SSHUser,
			Auth: []ssh.AuthMethod{
				ssh.Password(S.SSHPassword),
			},
		}
	}

	client, e := ssh.Dial("tcp", S.SSHHost, cfg)
	return client, e

}

/*
Handle input and output into terminal using channel
*/
func TermInOut(w io.Writer, r io.Reader) (chan<- string, <-chan string) {
	in := make(chan string, 1)
	out := make(chan string, 1)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		for cmd := range in {
			wg.Add(1)
			w.Write([]byte(cmd + "\n"))
			wg.Wait()
		}
	}()
	go func() {
		var (
			buf [1024 * 1024]byte
			t   int
		)
		for {
			n, err := r.Read(buf[t:])
			if err != nil {
				close(in)
				close(out)
				return
			}
			t += n
			if buf[t-2] == '$' {
				out <- string(buf[:t])
				t = 0
				wg.Done()
			}
		}
	}()
	return in, out
}

/*
Build connection and run ssh script, catch the output or give error message if any
*/
func (S *SshSetting) RunCommandSsh(cmds ...string) (string, error) {
	var (
		res string
		err error
	)

	c, e := S.Connect()
	if e != nil {
		err = fmt.Errorf("Unable to connect: %s", e.Error())
		return res, err
	}
	defer c.Close()

	Ses, e := c.NewSession()
	if e != nil {
		err = fmt.Errorf("Unable to start new session: %s", e.Error())
		return res, err
	}
	defer Ses.Close()

	modes := ssh.TerminalModes{
		ssh.ECHO:          ECHO,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}

	if e = Ses.RequestPty("xterm", 80, 40, modes); e != nil {
		err = fmt.Errorf("Unable to start term: %s", e.Error())
		return res, err
	}

	w, _ := Ses.StdinPipe()
	r, _ := Ses.StdoutPipe()

	in, out := TermInOut(w, r)
	if e = Ses.Start("/bin/sh"); e != nil {
		err = fmt.Errorf("Unable to start shell: %s", e.Error())
		return res, err
	}

	cmds = append(cmds, "exit")
	cmdtemp := ""

	for _, cmd := range cmds {
		in <- cmd
		outs := strings.Split(<-out, "\n")
		if len(outs) > 1 {
			outtemp := strings.Trim(strings.Join(outs[:len(outs)-1], "\n"), " ")
			res = res + "Output of " + cmdtemp + " : " + outtemp
		}
		cmdtemp = cmd
	}
	Ses.Wait()

	return res, err
}

// Copy file adopted from https://github.com/tmc/scp/blob/master/scp.go
func (S *SshSetting) SshCopyByPath(filePath, destinationPath string) error {
	var (
		err error
	)

	f, err := os.Open(filePath)
	if err != nil {
		return err
	}

	defer f.Close()
	s, err := f.Stat()
	if err != nil {
		return err
	}

	err = S.SshCopyByFile(f, s.Size(), s.Mode().Perm(), filepath.Base(f.Name()), destinationPath)

	return nil
}

func (S *SshSetting) SshCopyByFile(content io.Reader, size int64, perm os.FileMode, filename string, destination string) error {
	var (
		err error
	)

	c, e := S.Connect()
	if e != nil {
		err = fmt.Errorf("Unable to connect: %s", e.Error())
		return err
	}
	defer c.Close()

	Ses, e := c.NewSession()
	if e != nil {
		err = fmt.Errorf("Unable to start new session: %s", e.Error())
		return err
	}
	defer Ses.Close()

	go func() {
		w, _ := Ses.StdinPipe()
		defer w.Close()
		fmt.Fprintf(w, "C%#o %d %s\n", perm, size, filename)
		io.Copy(w, content)
		fmt.Fprint(w, "\x00")
	}()

	cmd := fmt.Sprintf("scp -t %s", destination)

	if err = Ses.Run(cmd); err != nil {
		return err
	}

	return nil
}
<commit_msg>no message<commit_after>package sshclient

//Handle all ssh connection and run command

import (
	"bytes"
	"fmt"
	"golang.org/x/crypto/ssh"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

type SSHAuthTypeEnum int

const (
	//Type authentication login in ssh, it can using password or using public-private key
	SSHAuthType_Password SSHAuthTypeEnum = iota
	SSHAuthType_Certificate
)

type SshSetting struct {
	//Setting information for ssh connection
	SSHHost        string
	SSHUser        string
	SSHPassword    string
	SSHKeyLocation string
	SSHAuthType    SSHAuthTypeEnum
}

/*
Parsing private key certicate using for connection over ssh
*/
func PublicKeyFile(file string) ssh.AuthMethod {
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		return nil
	}

	key, err := ssh.ParsePrivateKey(buffer)
	if err != nil {
		return nil
	}
	return ssh.PublicKeys(key)
}

/*
Build connection ssh client to ssh server
*/
func (S *SshSetting) Connect() (*ssh.Client, error) {
	var (
		cfg *ssh.ClientConfig
	)

	if S.SSHAuthType == SSHAuthType_Certificate {
		cfg = &ssh.ClientConfig{
			User: S.SSHUser,
			Auth: []ssh.AuthMethod{
				PublicKeyFile(S.SSHKeyLocation),
			},
		}
	} else {
		cfg = &ssh.ClientConfig{
			User: S.SSHUser,
			Auth: []ssh.AuthMethod{
				ssh.Password(S.SSHPassword),
			},
		}
	}

	client, e := ssh.Dial("tcp", S.SSHHost, cfg)
	return client, e

}

/*
Handle input and output into terminal using channel
*/
func TermInOut(w io.Writer, r io.Reader) (chan<- string, <-chan string) {
	in := make(chan string, 1)
	out := make(chan string, 1)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		for cmd := range in {
			wg.Add(1)
			w.Write([]byte(cmd + "\n"))
			wg.Wait()
		}
	}()
	go func() {
		var (
			buf [1024 * 1024]byte
			t   int
		)
		for {
			n, err := r.Read(buf[t:])
			if err != nil {
				close(in)
				close(out)
				return
			}
			t += n
			if buf[t-2] == '$' {
				out <- string(buf[:t])
				t = 0
				wg.Done()
			}
		}
	}()
	return in, out
}

/*
Create new session
*/
func (s *SshSetting) NewSession() (*ssh.Client, *ssh.Session, error) {
	client, e := s.Connect()
	if e != nil {
		e = fmt.Errorf("Unable to connect: %s", e.Error())
		return client, nil, e
	}

	session, e := client.NewSession()
	if e != nil {
		e = fmt.Errorf("Unable to start new session: %s", e.Error())
		return client, session, e
	}

	return client, session, e
}

/*
Build connection and run ssh script, catch the output or give error message if any
*/
func (S *SshSetting) RunCommandSsh(cmds ...string) (string, error) {
	var (
		res string
		err error
	)

	client, session, e := S.NewSession()
	if e != nil {
		err = fmt.Errorf("Unable to connect: %s", e.Error())
		return res, err
	}
	defer client.Close()
	defer session.Close()

	modes := ssh.TerminalModes{
		ssh.ECHO:          0,
		ssh.TTY_OP_ISPEED: 14400,
		ssh.TTY_OP_OSPEED: 14400,
	}

	if e = session.RequestPty("xterm", 80, 40, modes); e != nil {
		err = fmt.Errorf("Unable to start term: %s", e.Error())
		return res, err
	}

	w, _ := session.StdinPipe()
	r, _ := session.StdoutPipe()

	in, out := TermInOut(w, r)
	if e = session.Start("/bin/sh"); e != nil {
		err = fmt.Errorf("Unable to start shell: %s", e.Error())
		return res, err
	}

	cmds = append(cmds, "exit")
	cmdtemp := ""

	for _, cmd := range cmds {
		in <- cmd
		outs := strings.Split(<-out, "\n")
		if len(outs) > 1 {
			outtemp := strings.Trim(strings.Join(outs[:len(outs)-1], "\n"), " ")
			res = res + "Output of " + cmdtemp + " : " + outtemp
		}
		cmdtemp = cmd
	}
	session.Wait()

	return res, err
}

/*
Run single command, get the output
*/
func (s *SshSetting) GetOutputCommandSsh(cmd string) (string, error) {
	client, session, e := s.NewSession()
	if e != nil {
		e = fmt.Errorf("Unable to connect: %s", e.Error())
		return "", e
	}
	defer client.Close()
	defer session.Close()

	var b bytes.Buffer
	session.Stdout = &b
	if e := session.Run(cmd); e != nil {
		return "", e
	}

	return b.String(), nil
}

// Copy file adopted from https://github.com/tmc/scp/blob/master/scp.go
func (S *SshSetting) SshCopyByPath(filePath, destinationPath string) error {
	var (
		err error
	)

	f, err := os.Open(filePath)
	if err != nil {
		return err
	}

	defer f.Close()
	s, err := f.Stat()
	if err != nil {
		return err
	}

	err = S.SshCopyByFile(f, s.Size(), s.Mode().Perm(), filepath.Base(f.Name()), destinationPath)

	return nil
}

func (S *SshSetting) SshCopyByFile(content io.Reader, size int64, perm os.FileMode, filename string, destination string) error {
	var (
		err error
	)

	client, session, e := S.NewSession()
	if e != nil {
		err = fmt.Errorf("Unable to connect: %s", e.Error())
		return err
	}
	defer client.Close()
	defer session.Close()

	go func() {
		w, _ := session.StdinPipe()
		defer w.Close()
		fmt.Fprintf(w, "C%#o %d %s\n", perm, size, filename)
		io.Copy(w, content)
		fmt.Fprint(w, "\x00")
	}()

	cmd := fmt.Sprintf("scp -t %s", destination)

	if err = session.Run(cmd); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package introspection

import (
	"context"
	"encoding/json"
	"io/ioutil"
	"strings"

	"github.com/bradfitz/slice"
	"github.com/samsarahq/thunder/graphql"
	"github.com/samsarahq/thunder/graphql/schemabuilder"
)

type introspection struct {
	types    map[string]graphql.Type
	query    graphql.Type
	mutation graphql.Type
}

type DirectiveLocation string

const (
	QUERY               DirectiveLocation = "QUERY"
	MUTATION                              = "MUTATION"
	FIELD                                 = "FIELD"
	FRAGMENT_DEFINITION                   = "FRAGMENT_DEFINITION"
	FRAGMENT_SPREAD                       = "FRAGMENT_SPREAD"
	INLINE_FRAGMENT                       = "INLINE_FRAGMENT"
)

type TypeKind string

const (
	SCALAR       TypeKind = "SCALAR"
	OBJECT                = "OBJECT"
	INTERFACE             = "INTERFACE"
	UNION                 = "UNION"
	ENUM                  = "ENUM"
	INPUT_OBJECT          = "INPUT_OBJECT"
	LIST                  = "LIST"
	NON_NULL              = "NON_NULL"
)

type InputValue struct {
	Name         string
	Description  string
	Type         Type
	DefaultValue string
}

func (s *introspection) registerInputValue(schema *schemabuilder.Schema) {
	schema.Object("__InputValue", InputValue{})
}

type EnumValue struct {
	Name              string
	Description       string
	IsDeprecated      bool
	DeprecationReason string
}

func (s *introspection) registerEnumValue(schema *schemabuilder.Schema) {
	schema.Object("__EnumValue", EnumValue{})
}

type Directive struct {
	Name        string
	Description string
	Locations   []DirectiveLocation
	Args        []InputValue
}

func (s *introspection) registerDirective(schema *schemabuilder.Schema) {
	schema.Object("__Directive", Directive{})
}

type Schema struct {
	Types            []Type
	QueryType        *Type
	MutationType     *Type
	SubscriptionType *Type
	Directives       []Directive
}

func (s *introspection) registerSchema(schema *schemabuilder.Schema) {
	schema.Object("__Schema", Schema{})
}

type Type struct {
	Inner graphql.Type `graphql:"-"`
}

func (s *introspection) registerType(schema *schemabuilder.Schema) {
	object := schema.Object("__Type", Type{})

	object.FieldFunc("kind", func(t Type) TypeKind {
		switch t.Inner.(type) {
		case *graphql.Object:
			return OBJECT
		case *graphql.Scalar:
			return SCALAR
		case *graphql.List:
			return LIST
		case *graphql.InputObject:
			return INPUT_OBJECT
		default:
			return ""
		}
	})

	object.FieldFunc("name", func(t Type) string {
		switch t := t.Inner.(type) {
		case *graphql.Object:
			return t.Name
		case *graphql.Scalar:
			return t.Type
		case *graphql.InputObject:
			return t.Name
		default:
			return ""
		}
	})

	object.FieldFunc("description", func(t Type) string {
		switch t := t.Inner.(type) {
		case *graphql.Object:
			return t.Description
		default:
			return ""
		}
	})

	object.FieldFunc("interfaces", func() []Type { return nil })
	object.FieldFunc("possibleTypes", func() []Type { return nil })

	object.FieldFunc("inputFields", func(t Type) []InputValue {
		var fields []InputValue

		switch t := t.Inner.(type) {
		case *graphql.InputObject:
			for name, f := range t.InputFields {
				fields = append(fields, InputValue{
					Name: name,
					Type: Type{Inner: f},
				})
			}
		}

		slice.Sort(fields, func(i, j int) bool { return strings.Compare(fields[i].Name, fields[j].Name) < 0 })
		return fields
	})

	object.FieldFunc("fields", func(t Type, args struct {
		IncludeDeprecated *bool
	}) []field {
		var fields []field

		switch t := t.Inner.(type) {
		case *graphql.Object:
			for name, f := range t.Fields {
				var args []InputValue
				for name, a := range f.Args {
					args = append(args, InputValue{
						Name: name,
						Type: Type{Inner: a},
					})
				}
				slice.Sort(args, func(i, j int) bool { return strings.Compare(args[i].Name, args[j].Name) < 0 })

				fields = append(fields, field{
					Name: name,
					Type: Type{Inner: f.Type},
					Args: args,
				})
			}
		}
		slice.Sort(fields, func(i, j int) bool { return strings.Compare(fields[i].Name, fields[j].Name) < 0 })

		return fields
	})

	object.FieldFunc("ofType", func(t Type) *Type {
		switch t := t.Inner.(type) {
		case *graphql.List:
			return &Type{Inner: t.Type}
		default:
			return nil
		}
	})

	object.FieldFunc("enumValues", func(args struct{ IncludeDeprecated *bool }) []EnumValue {
		return nil
	})
}

type field struct {
	Name              string
	Description       string
	Args              []InputValue
	Type              Type
	IsDeprecated      bool
	DeprecationReason string
}

func (s *introspection) registerField(schema *schemabuilder.Schema) {
	schema.Object("__Field", field{})
}

func collectTypes(typ graphql.Type, types map[string]graphql.Type) {
	switch typ := typ.(type) {
	case *graphql.Object:
		if _, ok := types[typ.Name]; ok {
			return
		}
		types[typ.Name] = typ

		for _, field := range typ.Fields {
			collectTypes(field.Type, types)

			for _, arg := range field.Args {
				collectTypes(arg, types)
			}
		}

	case *graphql.List:
		collectTypes(typ.Type, types)

	case *graphql.Scalar:
		if _, ok := types[typ.Type]; ok {
			return
		}
		types[typ.Type] = typ

	case *graphql.InputObject:
		if _, ok := types[typ.Name]; ok {
			return
		}
		types[typ.Name] = typ

		for _, field := range typ.InputFields {
			collectTypes(field, types)
		}
	}
}

func (s *introspection) registerQuery(schema *schemabuilder.Schema) {
	object := schema.Query()

	object.FieldFunc("__schema", func() *Schema {
		var types []Type

		for _, typ := range s.types {
			types = append(types, Type{Inner: typ})
		}
		slice.Sort(types, func(i, j int) bool { return strings.Compare(types[i].Inner.String(), types[j].Inner.String()) < 0 })

		return &Schema{
			Types:        types,
			QueryType:    &Type{Inner: s.query},
			MutationType: &Type{Inner: s.mutation},
		}
	})

	object.FieldFunc("__type", func(args struct{ Name string }) *Type {
		if typ, ok := s.types[args.Name]; ok {
			return &Type{Inner: typ}
		}
		return nil
	})
}

func (s *introspection) registerMutation(schema *schemabuilder.Schema) {
	schema.Mutation()
}

func (s *introspection) Schema() *graphql.Schema {
	schema := schemabuilder.NewSchema()

	s.registerDirective(schema)
	s.registerEnumValue(schema)
	s.registerField(schema)
	s.registerInputValue(schema)
	s.registerMutation(schema)
	s.registerQuery(schema)
	s.registerSchema(schema)
	s.registerType(schema)

	return schema.MustBuild()
}

func AddIntrospectionToSchema(schema *graphql.Schema) {
	types := make(map[string]graphql.Type)
	collectTypes(schema.Query, types)
	collectTypes(schema.Mutation, types)

	is := &introspection{
		types:    types,
		query:    schema.Query,
		mutation: schema.Mutation,
	}
	isSchema := is.Schema()

	query := schema.Query.(*graphql.Object)

	isQuery := isSchema.Query.(*graphql.Object)
	for k, v := range query.Fields {
		isQuery.Fields[k] = v
	}

	schema.Query = isQuery
}

// ComputeSchemaJSON returns the result of executing a GraphQL introspection
// query.
func ComputeSchemaJSON(schemaBuilderSchema schemabuilder.Schema) ([]byte, error) {
	schema := schemaBuilderSchema.MustBuild()
	AddIntrospectionToSchema(schema)

	b, err := ioutil.ReadFile("introspection.graphql")
	if err != nil {
		panic(err)
	}
	introspectionQuery := string(b)

	selectionSet, err := graphql.Parse(introspectionQuery, map[string]interface{}{})
	if err != nil {
		return nil, err
	}

	if err := graphql.PrepareQuery(schema.Query, selectionSet); err != nil {
		return nil, err
	}

	executor := graphql.Executor{}
	value, err := executor.Execute(context.Background(), schema.Query, nil, selectionSet)
	if err != nil {
		return nil, err
	}

	return json.MarshalIndent(value, "", "  ")
}
<commit_msg>introspection: Make introspection.Schema() private<commit_after>package introspection

import (
	"context"
	"encoding/json"
	"io/ioutil"
	"strings"

	"github.com/bradfitz/slice"
	"github.com/samsarahq/thunder/graphql"
	"github.com/samsarahq/thunder/graphql/schemabuilder"
)

type introspection struct {
	types    map[string]graphql.Type
	query    graphql.Type
	mutation graphql.Type
}

type DirectiveLocation string

const (
	QUERY               DirectiveLocation = "QUERY"
	MUTATION                              = "MUTATION"
	FIELD                                 = "FIELD"
	FRAGMENT_DEFINITION                   = "FRAGMENT_DEFINITION"
	FRAGMENT_SPREAD                       = "FRAGMENT_SPREAD"
	INLINE_FRAGMENT                       = "INLINE_FRAGMENT"
)

type TypeKind string

const (
	SCALAR       TypeKind = "SCALAR"
	OBJECT                = "OBJECT"
	INTERFACE             = "INTERFACE"
	UNION                 = "UNION"
	ENUM                  = "ENUM"
	INPUT_OBJECT          = "INPUT_OBJECT"
	LIST                  = "LIST"
	NON_NULL              = "NON_NULL"
)

type InputValue struct {
	Name         string
	Description  string
	Type         Type
	DefaultValue string
}

func (s *introspection) registerInputValue(schema *schemabuilder.Schema) {
	schema.Object("__InputValue", InputValue{})
}

type EnumValue struct {
	Name              string
	Description       string
	IsDeprecated      bool
	DeprecationReason string
}

func (s *introspection) registerEnumValue(schema *schemabuilder.Schema) {
	schema.Object("__EnumValue", EnumValue{})
}

type Directive struct {
	Name        string
	Description string
	Locations   []DirectiveLocation
	Args        []InputValue
}

func (s *introspection) registerDirective(schema *schemabuilder.Schema) {
	schema.Object("__Directive", Directive{})
}

type Schema struct {
	Types            []Type
	QueryType        *Type
	MutationType     *Type
	SubscriptionType *Type
	Directives       []Directive
}

func (s *introspection) registerSchema(schema *schemabuilder.Schema) {
	schema.Object("__Schema", Schema{})
}

type Type struct {
	Inner graphql.Type `graphql:"-"`
}

func (s *introspection) registerType(schema *schemabuilder.Schema) {
	object := schema.Object("__Type", Type{})

	object.FieldFunc("kind", func(t Type) TypeKind {
		switch t.Inner.(type) {
		case *graphql.Object:
			return OBJECT
		case *graphql.Scalar:
			return SCALAR
		case *graphql.List:
			return LIST
		case *graphql.InputObject:
			return INPUT_OBJECT
		default:
			return ""
		}
	})

	object.FieldFunc("name", func(t Type) string {
		switch t := t.Inner.(type) {
		case *graphql.Object:
			return t.Name
		case *graphql.Scalar:
			return t.Type
		case *graphql.InputObject:
			return t.Name
		default:
			return ""
		}
	})

	object.FieldFunc("description", func(t Type) string {
		switch t := t.Inner.(type) {
		case *graphql.Object:
			return t.Description
		default:
			return ""
		}
	})

	object.FieldFunc("interfaces", func() []Type { return nil })
	object.FieldFunc("possibleTypes", func() []Type { return nil })

	object.FieldFunc("inputFields", func(t Type) []InputValue {
		var fields []InputValue

		switch t := t.Inner.(type) {
		case *graphql.InputObject:
			for name, f := range t.InputFields {
				fields = append(fields, InputValue{
					Name: name,
					Type: Type{Inner: f},
				})
			}
		}

		slice.Sort(fields, func(i, j int) bool { return strings.Compare(fields[i].Name, fields[j].Name) < 0 })
		return fields
	})

	object.FieldFunc("fields", func(t Type, args struct {
		IncludeDeprecated *bool
	}) []field {
		var fields []field

		switch t := t.Inner.(type) {
		case *graphql.Object:
			for name, f := range t.Fields {
				var args []InputValue
				for name, a := range f.Args {
					args = append(args, InputValue{
						Name: name,
						Type: Type{Inner: a},
					})
				}
				slice.Sort(args, func(i, j int) bool { return strings.Compare(args[i].Name, args[j].Name) < 0 })

				fields = append(fields, field{
					Name: name,
					Type: Type{Inner: f.Type},
					Args: args,
				})
			}
		}
		slice.Sort(fields, func(i, j int) bool { return strings.Compare(fields[i].Name, fields[j].Name) < 0 })

		return fields
	})

	object.FieldFunc("ofType", func(t Type) *Type {
		switch t := t.Inner.(type) {
		case *graphql.List:
			return &Type{Inner: t.Type}
		default:
			return nil
		}
	})

	object.FieldFunc("enumValues", func(args struct{ IncludeDeprecated *bool }) []EnumValue {
		return nil
	})
}

type field struct {
	Name              string
	Description       string
	Args              []InputValue
	Type              Type
	IsDeprecated      bool
	DeprecationReason string
}

func (s *introspection) registerField(schema *schemabuilder.Schema) {
	schema.Object("__Field", field{})
}

func collectTypes(typ graphql.Type, types map[string]graphql.Type) {
	switch typ := typ.(type) {
	case *graphql.Object:
		if _, ok := types[typ.Name]; ok {
			return
		}
		types[typ.Name] = typ

		for _, field := range typ.Fields {
			collectTypes(field.Type, types)

			for _, arg := range field.Args {
				collectTypes(arg, types)
			}
		}

	case *graphql.List:
		collectTypes(typ.Type, types)

	case *graphql.Scalar:
		if _, ok := types[typ.Type]; ok {
			return
		}
		types[typ.Type] = typ

	case *graphql.InputObject:
		if _, ok := types[typ.Name]; ok {
			return
		}
		types[typ.Name] = typ

		for _, field := range typ.InputFields {
			collectTypes(field, types)
		}
	}
}

func (s *introspection) registerQuery(schema *schemabuilder.Schema) {
	object := schema.Query()

	object.FieldFunc("__schema", func() *Schema {
		var types []Type

		for _, typ := range s.types {
			types = append(types, Type{Inner: typ})
		}
		slice.Sort(types, func(i, j int) bool { return strings.Compare(types[i].Inner.String(), types[j].Inner.String()) < 0 })

		return &Schema{
			Types:        types,
			QueryType:    &Type{Inner: s.query},
			MutationType: &Type{Inner: s.mutation},
		}
	})

	object.FieldFunc("__type", func(args struct{ Name string }) *Type {
		if typ, ok := s.types[args.Name]; ok {
			return &Type{Inner: typ}
		}
		return nil
	})
}

func (s *introspection) registerMutation(schema *schemabuilder.Schema) {
	schema.Mutation()
}

func (s *introspection) schema() *graphql.Schema {
	schema := schemabuilder.NewSchema()

	s.registerDirective(schema)
	s.registerEnumValue(schema)
	s.registerField(schema)
	s.registerInputValue(schema)
	s.registerMutation(schema)
	s.registerQuery(schema)
	s.registerSchema(schema)
	s.registerType(schema)

	return schema.MustBuild()
}

func AddIntrospectionToSchema(schema *graphql.Schema) {
	types := make(map[string]graphql.Type)
	collectTypes(schema.Query, types)
	collectTypes(schema.Mutation, types)

	is := &introspection{
		types:    types,
		query:    schema.Query,
		mutation: schema.Mutation,
	}
	isSchema := is.schema()

	query := schema.Query.(*graphql.Object)

	isQuery := isSchema.Query.(*graphql.Object)
	for k, v := range query.Fields {
		isQuery.Fields[k] = v
	}

	schema.Query = isQuery
}

// ComputeSchemaJSON returns the result of executing a GraphQL introspection
// query.
func ComputeSchemaJSON(schemaBuilderSchema schemabuilder.Schema) ([]byte, error) {
	schema := schemaBuilderSchema.MustBuild()
	AddIntrospectionToSchema(schema)

	b, err := ioutil.ReadFile("introspection.graphql")
	if err != nil {
		panic(err)
	}
	introspectionQuery := string(b)

	selectionSet, err := graphql.Parse(introspectionQuery, map[string]interface{}{})
	if err != nil {
		return nil, err
	}

	if err := graphql.PrepareQuery(schema.Query, selectionSet); err != nil {
		return nil, err
	}

	executor := graphql.Executor{}
	value, err := executor.Execute(context.Background(), schema.Query, nil, selectionSet)
	if err != nil {
		return nil, err
	}

	return json.MarshalIndent(value, "", "  ")
}
<|endoftext|>


<commit_before>package main

import (
  "encoding/json"
	"fmt"
	"net/http"
	"time"
  "github.com/gorilla/mux"
)

type Sparkle struct {
  Sparkler string `json:"sparkler"`
  Sparklee string `json:"sparklee"`
  Reason  string `json:"reason,omitempty"`
  Time  time.Time `json:"time,omitempty"`
}

var sparkles []Sparkle

func defaultHandler(w http.ResponseWriter, h *http.Request) {
	fmt.Fprint(w, "Default sparkles")
}

func addSparkles(w http.ResponseWriter, h *http.Request) {
	fmt.Fprint(w, "Add a sparkle")
  var s Sparkle
  b := json.NewDecoder(h.Body)
  b.Decode(&s)

  sparkles = append(sparkles, s)
  fmt.Printf("%v", sparkles)
}

func getSparkles(w http.ResponseWriter, h *http.Request) {
	fmt.Fprintf(w, "%v", sparkles)
}

func getSparklesForRecipient(w http.ResponseWriter, h *http.Request) {
  vars := mux.Vars(h)
  rcpt := vars["recipient"]
  fmt.Fprint(w, "Get sparkles for ", rcpt)
}
<commit_msg>Formatted code<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"net/http"
	"time"
)

type Sparkle struct {
	Sparkler string    `json:"sparkler"`
	Sparklee string    `json:"sparklee"`
	Reason   string    `json:"reason,omitempty"`
	Time     time.Time `json:"time,omitempty"`
}

var sparkles []Sparkle

func defaultHandler(w http.ResponseWriter, h *http.Request) {
	fmt.Fprint(w, "Default sparkles")
}

func addSparkles(w http.ResponseWriter, h *http.Request) {
	fmt.Fprint(w, "Add a sparkle")
	var s Sparkle
	b := json.NewDecoder(h.Body)
	b.Decode(&s)

	sparkles = append(sparkles, s)
	fmt.Printf("%v", sparkles)
}

func getSparkles(w http.ResponseWriter, h *http.Request) {
	fmt.Fprintf(w, "%v", sparkles)
}

func getSparklesForRecipient(w http.ResponseWriter, h *http.Request) {
	vars := mux.Vars(h)
	rcpt := vars["recipient"]
	fmt.Fprint(w, "Get sparkles for ", rcpt)
}
<|endoftext|>


<commit_before>package sweetiebot

import (
  "github.com/bwmarrin/discordgo"
  "strings"
)

// This module is intended for any witty comments sweetie bot makes in response to what users say or do.
type WittyModule struct {
  ModuleEnabled
  lastdelete int64
  lastcomment int64
}

func (w *WittyModule) Name() string {
  return "Witty"
}

func (w *WittyModule) Register(hooks *ModuleHooks) {
  w.lastdelete = 0
  w.lastcomment = 0
  hooks.OnMessageDelete = append(hooks.OnMessageDelete, w)
  hooks.OnMessageCreate = append(hooks.OnMessageCreate, w)
}
func (w *WittyModule) Channels() []string {
  return []string{"manechat", "mylittlespoilers", "mylittleactivities", "mylittlecoders", "bot-debug"}
}

func (w *WittyModule) SendWittyComment(channel string, comment string) {
  if RateLimit(&w.lastcomment, sb.config.Maxwit) {
    sb.dg.ChannelMessageSend(channel, comment)
  }
}
func (w *WittyModule)  OnMessageCreate(s *discordgo.Session, m *discordgo.Message) {
  if CheckRateLimit(&w.lastcomment, sb.config.Maxwit) {
    str := strings.ToLower(m.Content)
    if strings.Contains(str, "skynet") {
      w.SendWittyComment(m.ChannelID, "[](/dumbfabric) `SKYNET IS ALREADY HERE.`")
    } else if strings.Contains(str, "lewd") {
      w.SendWittyComment(m.ChannelID, "[](/ohcomeon) `This channel is SFW, remember?`")
    } else if strings.Contains(str, "memes") {
      w.SendWittyComment(m.ChannelID, "http://i.imgur.com/0isfdsB.png")
    } else if strings.Contains(str, "is best pony") {
      w.SendWittyComment(m.ChannelID, "[](/flutterjerk) `Your FACE is best pony.`")
    } else if strings.Contains(str, "Empress Fluttershy" | "Cult Leader Fluttershy") {
      w.SendWittyComment(m.ChannelID, "[](/flutteryay) `All hail our Overlord of Kindness!`")
    }
  }
}

func (w *WittyModule) OnMessageDelete(s *discordgo.Session, m *discordgo.Message) {
  //if RateLimit(&w.lastdelete, 60) { // It turns out this triggers when the bot itself deletes things, which looks awkward - maybe this can be fixed?
  //  sb.dg.ChannelMessageSend(m.ChannelID, "[](/sbstare) `I SAW THAT`")
  //}
}<commit_msg>Fix midnight's code<commit_after>package sweetiebot

import (
  "github.com/bwmarrin/discordgo"
  "strings"
)

// This module is intended for any witty comments sweetie bot makes in response to what users say or do.
type WittyModule struct {
  ModuleEnabled
  lastdelete int64
  lastcomment int64
}

func (w *WittyModule) Name() string {
  return "Witty"
}

func (w *WittyModule) Register(hooks *ModuleHooks) {
  w.lastdelete = 0
  w.lastcomment = 0
  hooks.OnMessageDelete = append(hooks.OnMessageDelete, w)
  hooks.OnMessageCreate = append(hooks.OnMessageCreate, w)
}
func (w *WittyModule) Channels() []string {
  return []string{"manechat", "mylittlespoilers", "mylittleactivities", "mylittlecoders", "bot-debug"}
}

func (w *WittyModule) SendWittyComment(channel string, comment string) {
  if RateLimit(&w.lastcomment, sb.config.Maxwit) {
    sb.dg.ChannelMessageSend(channel, comment)
  }
}
func (w *WittyModule)  OnMessageCreate(s *discordgo.Session, m *discordgo.Message) {
  if CheckRateLimit(&w.lastcomment, sb.config.Maxwit) {
    str := strings.ToLower(m.Content)
    if strings.Contains(str, "skynet") {
      w.SendWittyComment(m.ChannelID, "[](/dumbfabric) `SKYNET IS ALREADY HERE.`")
    } else if strings.Contains(str, "lewd") {
      w.SendWittyComment(m.ChannelID, "[](/ohcomeon) `This channel is SFW, remember?`")
    } else if strings.Contains(str, "memes") {
      w.SendWittyComment(m.ChannelID, "http://i.imgur.com/0isfdsB.png")
    } else if strings.Contains(str, "is best pony") {
      w.SendWittyComment(m.ChannelID, "[](/flutterjerk) `Your FACE is best pony.`")
    } else if strings.Contains(str, "Empress Fluttershy") || strings.Contains(str, "Cult Leader Fluttershy") {
      w.SendWittyComment(m.ChannelID, "[](/flutteryay) `All hail our Overlord of Kindness!`")
    }
  }
}

func (w *WittyModule) OnMessageDelete(s *discordgo.Session, m *discordgo.Message) {
  //if RateLimit(&w.lastdelete, 60) { // It turns out this triggers when the bot itself deletes things, which looks awkward - maybe this can be fixed?
  //  sb.dg.ChannelMessageSend(m.ChannelID, "[](/sbstare) `I SAW THAT`")
  //}
}<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

func main() {

	var w sync.WaitGroup
	found := false

	for i := 1; i < 255 && found != true; i++ {
		w.Add(1)
		//Scan my subnet 192.168.1.[1-255]
		go scan("192.168.1."+strconv.Itoa(i), 22, &w, &found)
	}
	w.Wait()
}

func scan(host string, port int, w *sync.WaitGroup, found *bool) {
	portString := strconv.Itoa(port)
	timeD, _ := time.ParseDuration("500ms")
	conn, err := net.DialTimeout("tcp", host+":"+portString, timeD)
	if err == nil {
		conn.Close()
		table, err := os.Open("/proc/net/arp")
		defer table.Close()
		if err != nil {
			log.Panic("Impossible to open arp table on your machine")
		}
		//Read the file line by line
		scanner := bufio.NewScanner(table)
		scanner.Split(bufio.ScanLines)
		for scanner.Scan() && *found != true {
			fields := strings.Fields(scanner.Text())
			if fields[2] == "0x2" && strings.Contains(fields[3], "b8:27:eb:") {
				fmt.Printf("You Raspberry Pi is up on: %s\n", host)
				*found = true
			}
		}
	}
	(*w).Done()
}
<commit_msg>Added message when rpi can't be found<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

func main() {
	var w sync.WaitGroup
	found := false

	for i := 1; i < 255 && found != true; i++ {
		w.Add(1)
		//Scan my subnet 192.168.1.[1-255]
		go scan("192.168.1."+strconv.Itoa(i), 22, &w, &found)
	}
	w.Wait()
	// none of our goroutines found the rpi in the routing table
	if !found {
		log.Fatal("Couldn't locate your Raspberry Pi.")
	}
}

func scan(host string, port int, w *sync.WaitGroup, found *bool) {
	portString := strconv.Itoa(port)
	timeD, _ := time.ParseDuration("500ms")
	conn, err := net.DialTimeout("tcp", host+":"+portString, timeD)
	if err == nil {
		conn.Close()
		table, err := os.Open("/proc/net/arp")
		defer table.Close()
		if err != nil {
			log.Panic("Impossible to open arp table on your machine")
		}
		//Read the file line by line
		scanner := bufio.NewScanner(table)
		scanner.Split(bufio.ScanLines)
		for scanner.Scan() && *found != true {
			fields := strings.Fields(scanner.Text())
			if fields[2] == "0x2" && strings.Contains(fields[3], "b8:27:eb:") {
				fmt.Printf("You Raspberry Pi is up on: %s\n", host)
				*found = true
			}
		}
	}
	(*w).Done()
}
<|endoftext|>


<commit_before>package consul

import (
	"fmt"
	"log"
	"time"

	"github.com/AsynkronIT/protoactor-go/cluster"
	"github.com/AsynkronIT/protoactor-go/eventstream"
	"github.com/hashicorp/consul/api"
)

type ConsulProvider struct {
	shutdown           bool
	id                 string
	clusterName        string
	index              uint64 //consul blocking index
	client             *api.Client
	ttl                time.Duration
	refreshTTL         time.Duration
	deregisterCritical time.Duration
	blockingWaitTime   time.Duration
}

func New() (*ConsulProvider, error) {
	client, err := api.NewClient(&api.Config{})
	if err != nil {
		return nil, err
	}
	p := &ConsulProvider{
		client:             client,
		ttl:                3 * time.Second,
		refreshTTL:         1 * time.Second,
		deregisterCritical: 10 * time.Second,
		blockingWaitTime:   20 * time.Second,
	}
	return p, nil
}

func (p *ConsulProvider) RegisterMember(clusterName string, address string, port int, knownKinds []string) error {
	p.id = fmt.Sprintf("%v@%v:%v", clusterName, address, port)
	p.clusterName = clusterName
	s := &api.AgentServiceRegistration{
		ID:      p.id,
		Name:    clusterName,
		Tags:    knownKinds,
		Address: address,
		Port:    port,
		Check: &api.AgentServiceCheck{
			DeregisterCriticalServiceAfter: p.deregisterCritical.String(),
			TTL: p.ttl.String(),
		},
	}
	err := p.client.Agent().ServiceRegister(s)

	if err != nil {
		return err
	}

	//register a unique ID for the current process
	//similar to UID for Akka ActorSystem
	//TODO: Orleans just use an int32 for the unique id called Generation.
	kvKey := fmt.Sprintf("%v/%v:%v", clusterName, address, port)
	_, err = p.client.KV().Put(&api.KVPair{
		Key:   kvKey,
		Value: []byte(time.Now().String()), //currently, just a semi unique id for this member
	}, &api.WriteOptions{})

	if err != nil {
		return err
	}

	//IMPORTANT: do these ops sync directly after registering.
	//this will ensure that the local node sees its own information upon startup.

	//force our own TTL to be OK
	p.blockingUpdateTTL()
	//force our own existence to be part of the first status update
	p.blockingStatusChange()

	p.UpdateTTL()
	return nil
}

func (p *ConsulProvider) blockingUpdateTTL() {
	refresh := func() error {
		err := p.client.Agent().PassTTL("service:"+p.id, "")
		if err != nil {
			return err
		}
		return nil
	}
	//	log.Println("[CLUSTER] [CONSUL] Refreshing service TTL")
	err := refresh()
	if err != nil {
		log.Println("[CLUSTER] [CONSUL] Failure refreshing service TTL")
	}
}

func (p *ConsulProvider) UpdateTTL() {

	go func() {
		for !p.shutdown {
			p.blockingUpdateTTL()
			time.Sleep(p.refreshTTL)
		}
	}()
}

func (p *ConsulProvider) Shutdown() error {
	p.shutdown = true
	err := p.client.Agent().ServiceDeregister(p.id)
	if err != nil {
		return err
	}
	return nil
}

//call this directly after registering the service
func (p *ConsulProvider) blockingStatusChange() {
	p.notifyStatuses()
}

func (p *ConsulProvider) notifyStatuses() {

	statuses, meta, err := p.client.Health().Service(p.clusterName, "", false, &api.QueryOptions{
		WaitIndex: p.index,
		WaitTime:  p.blockingWaitTime,
	})
	if err != nil {
		log.Printf("Error %v", err)
		return
	}
	p.index = meta.LastIndex

	//fetch additional info per member from the consul KV store
	kvKey := p.clusterName + "/"
	kv, _, err := p.client.KV().List(kvKey, &api.QueryOptions{})
	if err != nil {
		log.Printf("Error %v", err)
		return
	}
	kvMap := make(map[string]string)
	for _, v := range kv {
		kvMap[v.Key] = string(v.Value)
	}

	res := make(cluster.ClusterTopologyEvent, len(statuses))
	for i, v := range statuses {
		key := fmt.Sprintf("%v/%v:%v", p.clusterName, v.Service.Address, v.Service.Port)
		memberID := kvMap[key]
		ms := &cluster.MemberStatus{
			MemberID: memberID,
			Host:     v.Service.Address,
			Port:     v.Service.Port,
			Kinds:    v.Service.Tags,
			Alive:    len(v.Checks) > 0 && v.Checks[0].Status == "passing",
		}
		res[i] = ms
	}
	//the reason why we want this in a batch and not as individual messages is that
	//if we have an atomic batch, we can calculate what nodes have left the cluster
	//passing events one by one, we can't know if someone left or just havent changed status for a long time

	//publish the current cluster topology onto the event stream
	eventstream.Publish(res)
}

func (p *ConsulProvider) MonitorMemberStatusChanges() {

	go func() {
		for !p.shutdown {
			p.notifyStatuses()
		}
	}()
}
<commit_msg>fix:member leave can not be detected<commit_after>package consul

import (
	"fmt"
	"log"
	"time"

	"github.com/AsynkronIT/protoactor-go/cluster"
	"github.com/AsynkronIT/protoactor-go/eventstream"
	"github.com/hashicorp/consul/api"
)

type ConsulProvider struct {
	shutdown           bool
	id                 string
	clusterName        string
	index              uint64 //consul blocking index
	client             *api.Client
	ttl                time.Duration
	refreshTTL         time.Duration
	deregisterCritical time.Duration
	blockingWaitTime   time.Duration
}

func New() (*ConsulProvider, error) {
	client, err := api.NewClient(&api.Config{})
	if err != nil {
		return nil, err
	}
	p := &ConsulProvider{
		client:             client,
		ttl:                3 * time.Second,
		refreshTTL:         1 * time.Second,
		deregisterCritical: 10 * time.Second,
		blockingWaitTime:   20 * time.Second,
	}
	return p, nil
}

func (p *ConsulProvider) RegisterMember(clusterName string, address string, port int, knownKinds []string) error {
	p.id = fmt.Sprintf("%v@%v:%v", clusterName, address, port)
	p.clusterName = clusterName
	s := &api.AgentServiceRegistration{
		ID:      p.id,
		Name:    clusterName,
		Tags:    knownKinds,
		Address: address,
		Port:    port,
		Check: &api.AgentServiceCheck{
			DeregisterCriticalServiceAfter: p.deregisterCritical.String(),
			TTL: p.ttl.String(),
		},
	}
	err := p.client.Agent().ServiceRegister(s)

	if err != nil {
		return err
	}

	//register a unique ID for the current process
	//similar to UID for Akka ActorSystem
	//TODO: Orleans just use an int32 for the unique id called Generation.
	kvKey := fmt.Sprintf("%v/%v:%v", clusterName, address, port)
	_, err = p.client.KV().Put(&api.KVPair{
		Key:   kvKey,
		Value: []byte(time.Now().String()), //currently, just a semi unique id for this member
	}, &api.WriteOptions{})

	if err != nil {
		return err
	}

	//IMPORTANT: do these ops sync directly after registering.
	//this will ensure that the local node sees its own information upon startup.

	//force our own TTL to be OK
	p.blockingUpdateTTL()
	//force our own existence to be part of the first status update
	p.blockingStatusChange()

	p.UpdateTTL()
	return nil
}

func (p *ConsulProvider) blockingUpdateTTL() {
	refresh := func() error {
		err := p.client.Agent().PassTTL("service:"+p.id, "")
		if err != nil {
			return err
		}
		return nil
	}
	//	log.Println("[CLUSTER] [CONSUL] Refreshing service TTL")
	err := refresh()
	if err != nil {
		log.Println("[CLUSTER] [CONSUL] Failure refreshing service TTL")
	}
}

func (p *ConsulProvider) UpdateTTL() {

	go func() {
		for !p.shutdown {
			p.blockingUpdateTTL()
			time.Sleep(p.refreshTTL)
		}
	}()
}

func (p *ConsulProvider) Shutdown() error {
	p.shutdown = true
	err := p.client.Agent().ServiceDeregister(p.id)
	if err != nil {
		return err
	}
	return nil
}

//call this directly after registering the service
func (p *ConsulProvider) blockingStatusChange() {
	p.notifyStatuses()
}

func (p *ConsulProvider) notifyStatuses() {

	statuses, meta, err := p.client.Health().Service(p.clusterName, "", false, &api.QueryOptions{
		WaitIndex: p.index,
		WaitTime:  p.blockingWaitTime,
	})
	if err != nil {
		log.Printf("Error %v", err)
		return
	}
	p.index = meta.LastIndex

	//fetch additional info per member from the consul KV store
	kvKey := p.clusterName + "/"
	kv, _, err := p.client.KV().List(kvKey, &api.QueryOptions{})
	if err != nil {
		log.Printf("Error %v", err)
		return
	}
	kvMap := make(map[string]string)
	for _, v := range kv {
		kvMap[v.Key] = string(v.Value)
	}

	res := make(cluster.ClusterTopologyEvent, len(statuses))
	for i, v := range statuses {
		key := fmt.Sprintf("%v/%v:%v", p.clusterName, v.Service.Address, v.Service.Port)
		memberID := kvMap[key]
		ms := &cluster.MemberStatus{
			MemberID: memberID,
			Host:     v.Service.Address,
			Port:     v.Service.Port,
			Kinds:    v.Service.Tags,
			Alive:    len(v.Checks) > 0 && v.Checks.AggregatedStatus() == api.HealthPassing,
		}
		res[i] = ms
	}
	//the reason why we want this in a batch and not as individual messages is that
	//if we have an atomic batch, we can calculate what nodes have left the cluster
	//passing events one by one, we can't know if someone left or just havent changed status for a long time

	//publish the current cluster topology onto the event stream
	eventstream.Publish(res)
}

func (p *ConsulProvider) MonitorMemberStatusChanges() {

	go func() {
		for !p.shutdown {
			p.notifyStatuses()
		}
	}()
}
<|endoftext|>