<commit_before>package main

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/bitly/go-simplejson"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"
)

const signInPath = "/oauth2/sign_in"
const oauthStartPath = "/oauth2/start"
const oauthCallbackPath = "/oauth2/callback"

type OauthProxy struct {
	CookieSeed string
	CookieKey  string
	Validator  func(string) bool

	redirectUrl        *url.URL // the url to receive requests at
	oauthRedemptionUrl *url.URL // endpoint to redeem the code
	oauthLoginUrl      *url.URL // to redirect the user to
	oauthUserInfoUrl   *url.URL
	oauthScope         string
	clientID           string
	clientSecret       string
	SignInMessage      string
	HtpasswdFile       *HtpasswdFile
	serveMux           *http.ServeMux
}

func NewOauthProxy(proxyUrls []*url.URL, clientID string, clientSecret string, validator func(string) bool) *OauthProxy {
	login, _ := url.Parse("https://accounts.google.com/o/oauth2/auth")
	redeem, _ := url.Parse("https://accounts.google.com/o/oauth2/token")
	info, _ := url.Parse("https://www.googleapis.com/oauth2/v2/userinfo")
	serveMux := http.NewServeMux()
	for _, u := range proxyUrls {
		path := u.Path
		u.Path = ""
		log.Printf("mapping %s => %s", path, u)
		serveMux.Handle(path, httputil.NewSingleHostReverseProxy(u))
	}
	return &OauthProxy{
		CookieKey:  "_oauthproxy",
		CookieSeed: *cookieSecret,
		Validator:  validator,

		clientID:           clientID,
		clientSecret:       clientSecret,
		oauthScope:         "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
		oauthRedemptionUrl: redeem,
		oauthLoginUrl:      login,
		oauthUserInfoUrl:   info,
		serveMux:           serveMux,
	}
}

func (p *OauthProxy) SetRedirectUrl(redirectUrl *url.URL) {
	redirectUrl.Path = oauthCallbackPath
	p.redirectUrl = redirectUrl
}

func (p *OauthProxy) GetLoginURL(redirectUrl string) string {
	params := url.Values{}
	params.Add("redirect_uri", p.redirectUrl.String())
	params.Add("approval_prompt", "force")
	params.Add("scope", p.oauthScope)
	params.Add("client_id", p.clientID)
	params.Add("response_type", "code")
	if strings.HasPrefix(redirectUrl, "/") {
		params.Add("state", redirectUrl)
	}
	return fmt.Sprintf("%s?%s", p.oauthLoginUrl, params.Encode())
}

func apiRequest(req *http.Request) (*simplejson.Json, error) {
	httpclient := &http.Client{}
	resp, err := httpclient.Do(req)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		log.Printf("got response code %d - %s", resp.StatusCode, body)
		return nil, errors.New("api request returned 200 status code")
	}
	data, err := simplejson.NewJson(body)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func (p *OauthProxy) redeemCode(code string) (string, error) {
	if code == "" {
		return "", errors.New("missing code")
	}
	params := url.Values{}
	params.Add("redirect_uri", p.redirectUrl.String())
	params.Add("client_id", p.clientID)
	params.Add("client_secret", p.clientSecret)
	params.Add("code", code)
	params.Add("grant_type", "authorization_code")
	log.Printf("body is %s", params.Encode())
	req, err := http.NewRequest("POST", p.oauthRedemptionUrl.String(), bytes.NewBufferString(params.Encode()))
	if err != nil {
		log.Printf("failed building request %s", err.Error())
		return "", err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	json, err := apiRequest(req)
	if err != nil {
		log.Printf("failed making request %s", err.Error())
		return "", err
	}
	access_token, err := json.Get("access_token").String()
	if err != nil {
		return "", err
	}
	return access_token, nil
}

func (p *OauthProxy) getUserInfo(token string) (string, error) {
	params := url.Values{}
	params.Add("access_token", token)
	endpoint := fmt.Sprintf("%s?%s", p.oauthUserInfoUrl.String(), params.Encode())
	log.Printf("calling %s", endpoint)
	req, err := http.NewRequest("GET", endpoint, nil)
	if err != nil {
		log.Printf("failed building request %s", err.Error())
		return "", err
	}
	json, err := apiRequest(req)
	if err != nil {
		log.Printf("failed making request %s", err.Error())
		return "", err
	}
	email, err := json.Get("email").String()
	if err != nil {
		log.Printf("failed getting email from response %s", err.Error())
		return "", err
	}
	return email, nil
}

func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) {
	domain := strings.Split(req.Host, ":")[0]
	if *cookieDomain != "" && strings.HasSuffix(domain, *cookieDomain) {
		domain = *cookieDomain
	}
	cookie := &http.Cookie{
		Name:     p.CookieKey,
		Value:    "",
		Path:     "/",
		Domain:   domain,
		Expires:  time.Now().Add(time.Duration(1) * time.Hour * -1),
		HttpOnly: true,
	}
	http.SetCookie(rw, cookie)
}

func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val string) {

	domain := strings.Split(req.Host, ":")[0] // strip the port (if any)
	if *cookieDomain != "" && strings.HasSuffix(domain, *cookieDomain) {
		domain = *cookieDomain
	}
	cookie := &http.Cookie{
		Name:     p.CookieKey,
		Value:    signedCookieValue(p.CookieSeed, p.CookieKey, val),
		Path:     "/",
		Domain:   domain,
		Expires:  time.Now().Add(time.Duration(168) * time.Hour), // 7 days
		HttpOnly: true,
		// Secure: req. ... ? set if X-Scheme: https ?
	}
	http.SetCookie(rw, cookie)
}

func (p *OauthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, message string) {
	log.Printf("ErrorPage %d %s %s", code, title, message)
	rw.WriteHeader(code)
	templates := getTemplates()
	t := struct {
		Title   string
		Message string
	}{
		Title:   fmt.Sprintf("%d %s", code, title),
		Message: message,
	}
	templates.ExecuteTemplate(rw, "error.html", t)
}

func (p *OauthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) {
	p.ClearCookie(rw, req)
	rw.WriteHeader(code)
	templates := getTemplates()

	t := struct {
		SignInMessage string
		Htpasswd      bool
		Redirect      string
	}{
		SignInMessage: p.SignInMessage,
		Htpasswd:      p.HtpasswdFile != nil,
		Redirect:      req.URL.RequestURI(),
	}
	templates.ExecuteTemplate(rw, "sign_in.html", t)
}

func (p *OauthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool) {
	if req.Method != "POST" || p.HtpasswdFile == nil {
		return "", false
	}
	user := req.FormValue("username")
	passwd := req.FormValue("password")
	if user == "" {
		return "", false
	}
	// check auth
	if p.HtpasswdFile.Validate(user, passwd) {
		log.Printf("authenticated %s via manual sign in", user)
		return user, true
	}
	return "", false
}

func (p *OauthProxy) GetRedirect(req *http.Request) (string, error) {
	err := req.ParseForm()

	if err != nil {
		return "", err
	}

	redirect := req.FormValue("rd")

	if redirect == "" {
		redirect = "/"
	}

	return redirect, err
}

func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// check if this is a redirect back at the end of oauth
	remoteIP := req.Header.Get("X-Real-IP")
	if remoteIP == "" {
		remoteIP = req.RemoteAddr
	}
	log.Printf("%s %s %s", remoteIP, req.Method, req.URL.Path)

	var ok bool
	var user string

	if req.URL.Path == signInPath {
		redirect, err := p.GetRedirect(req)
		if err != nil {
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}

		user, ok = p.ManualSignIn(rw, req)
		if ok {
			p.SetCookie(rw, req, user)
			http.Redirect(rw, req, redirect, 302)
		} else {
			p.SignInPage(rw, req, 200)
		}
		return
	}
	if req.URL.Path == oauthStartPath {
		redirect, err := p.GetRedirect(req)
		if err != nil {
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}
		http.Redirect(rw, req, p.GetLoginURL(redirect), 302)
		return
	}
	if req.URL.Path == oauthCallbackPath {
		// finish the oauth cycle
		err := req.ParseForm()
		if err != nil {
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}
		errorString := req.Form.Get("error")
		if errorString != "" {
			p.ErrorPage(rw, 403, "Permission Denied", errorString)
			return
		}

		token, err := p.redeemCode(req.Form.Get("code"))
		if err != nil {
			log.Printf("error redeeming code %s", err.Error())
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}
		// validate user
		email, err := p.getUserInfo(token)
		if err != nil {
			log.Printf("error redeeming code %s", err.Error())
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}

		redirect := req.Form.Get("state")
		if redirect == "" {
			redirect = "/"
		}

		// set cookie, or deny
		if p.Validator(email) {
			log.Printf("authenticating %s completed", email)
			p.SetCookie(rw, req, email)
			http.Redirect(rw, req, redirect, 302)
			return
		} else {
			p.ErrorPage(rw, 403, "Permission Denied", "Invalid Account")
			return
		}
	}

	if !ok {
		cookie, err := req.Cookie(p.CookieKey)
		if err == nil {
			var email string
			email, ok = validateCookie(cookie, p.CookieSeed)
			user = strings.Split(email, "@")[0]
		}
	}

	if !ok {
		user, ok = p.CheckBasicAuth(req)
		// if we want to promote basic auth requests to cookie'd requests, we could do that here
		// not sure that would be ideal in all circumstances though
		// if ok {
		// 	p.SetCookie(rw, req, user)
		// }
	}

	if !ok {
		log.Printf("invalid cookie")
		p.SignInPage(rw, req, 403)
		return
	}

	// At this point, the user is authenticated. proxy normally
	if *passBasicAuth {
		req.SetBasicAuth(user, "")
		req.Header["X-Forwarded-User"] = []string{user}
	}

	p.serveMux.ServeHTTP(rw, req)
}

func (p *OauthProxy) CheckBasicAuth(req *http.Request) (string, bool) {
	if p.HtpasswdFile == nil {
		return "", false
	}
	s := strings.SplitN(req.Header.Get("Authorization"), " ", 2)
	if len(s) != 2 || s[0] != "Basic" {
		return "", false
	}
	b, err := base64.StdEncoding.DecodeString(s[1])
	if err != nil {
		return "", false
	}
	pair := strings.SplitN(string(b), ":", 2)
	if len(pair) != 2 {
		return "", false
	}
	if p.HtpasswdFile.Validate(pair[0], pair[1]) {
		log.Printf("authenticated %s via basic auth", pair[0])
		return pair[0], true
	}
	return "", false
}
<commit_msg>Fixed wrong error message<commit_after>package main

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/bitly/go-simplejson"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"
)

const signInPath = "/oauth2/sign_in"
const oauthStartPath = "/oauth2/start"
const oauthCallbackPath = "/oauth2/callback"

type OauthProxy struct {
	CookieSeed string
	CookieKey  string
	Validator  func(string) bool

	redirectUrl        *url.URL // the url to receive requests at
	oauthRedemptionUrl *url.URL // endpoint to redeem the code
	oauthLoginUrl      *url.URL // to redirect the user to
	oauthUserInfoUrl   *url.URL
	oauthScope         string
	clientID           string
	clientSecret       string
	SignInMessage      string
	HtpasswdFile       *HtpasswdFile
	serveMux           *http.ServeMux
}

func NewOauthProxy(proxyUrls []*url.URL, clientID string, clientSecret string, validator func(string) bool) *OauthProxy {
	login, _ := url.Parse("https://accounts.google.com/o/oauth2/auth")
	redeem, _ := url.Parse("https://accounts.google.com/o/oauth2/token")
	info, _ := url.Parse("https://www.googleapis.com/oauth2/v2/userinfo")
	serveMux := http.NewServeMux()
	for _, u := range proxyUrls {
		path := u.Path
		u.Path = ""
		log.Printf("mapping %s => %s", path, u)
		serveMux.Handle(path, httputil.NewSingleHostReverseProxy(u))
	}
	return &OauthProxy{
		CookieKey:  "_oauthproxy",
		CookieSeed: *cookieSecret,
		Validator:  validator,

		clientID:           clientID,
		clientSecret:       clientSecret,
		oauthScope:         "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
		oauthRedemptionUrl: redeem,
		oauthLoginUrl:      login,
		oauthUserInfoUrl:   info,
		serveMux:           serveMux,
	}
}

func (p *OauthProxy) SetRedirectUrl(redirectUrl *url.URL) {
	redirectUrl.Path = oauthCallbackPath
	p.redirectUrl = redirectUrl
}

func (p *OauthProxy) GetLoginURL(redirectUrl string) string {
	params := url.Values{}
	params.Add("redirect_uri", p.redirectUrl.String())
	params.Add("approval_prompt", "force")
	params.Add("scope", p.oauthScope)
	params.Add("client_id", p.clientID)
	params.Add("response_type", "code")
	if strings.HasPrefix(redirectUrl, "/") {
		params.Add("state", redirectUrl)
	}
	return fmt.Sprintf("%s?%s", p.oauthLoginUrl, params.Encode())
}

func apiRequest(req *http.Request) (*simplejson.Json, error) {
	httpclient := &http.Client{}
	resp, err := httpclient.Do(req)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		log.Printf("got response code %d - %s", resp.StatusCode, body)
		return nil, errors.New("api request returned non 200 status code")
	}
	data, err := simplejson.NewJson(body)
	if err != nil {
		return nil, err
	}
	return data, nil
}

func (p *OauthProxy) redeemCode(code string) (string, error) {
	if code == "" {
		return "", errors.New("missing code")
	}
	params := url.Values{}
	params.Add("redirect_uri", p.redirectUrl.String())
	params.Add("client_id", p.clientID)
	params.Add("client_secret", p.clientSecret)
	params.Add("code", code)
	params.Add("grant_type", "authorization_code")
	log.Printf("body is %s", params.Encode())
	req, err := http.NewRequest("POST", p.oauthRedemptionUrl.String(), bytes.NewBufferString(params.Encode()))
	if err != nil {
		log.Printf("failed building request %s", err.Error())
		return "", err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	json, err := apiRequest(req)
	if err != nil {
		log.Printf("failed making request %s", err.Error())
		return "", err
	}
	access_token, err := json.Get("access_token").String()
	if err != nil {
		return "", err
	}
	return access_token, nil
}

func (p *OauthProxy) getUserInfo(token string) (string, error) {
	params := url.Values{}
	params.Add("access_token", token)
	endpoint := fmt.Sprintf("%s?%s", p.oauthUserInfoUrl.String(), params.Encode())
	log.Printf("calling %s", endpoint)
	req, err := http.NewRequest("GET", endpoint, nil)
	if err != nil {
		log.Printf("failed building request %s", err.Error())
		return "", err
	}
	json, err := apiRequest(req)
	if err != nil {
		log.Printf("failed making request %s", err.Error())
		return "", err
	}
	email, err := json.Get("email").String()
	if err != nil {
		log.Printf("failed getting email from response %s", err.Error())
		return "", err
	}
	return email, nil
}

func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) {
	domain := strings.Split(req.Host, ":")[0]
	if *cookieDomain != "" && strings.HasSuffix(domain, *cookieDomain) {
		domain = *cookieDomain
	}
	cookie := &http.Cookie{
		Name:     p.CookieKey,
		Value:    "",
		Path:     "/",
		Domain:   domain,
		Expires:  time.Now().Add(time.Duration(1) * time.Hour * -1),
		HttpOnly: true,
	}
	http.SetCookie(rw, cookie)
}

func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val string) {

	domain := strings.Split(req.Host, ":")[0] // strip the port (if any)
	if *cookieDomain != "" && strings.HasSuffix(domain, *cookieDomain) {
		domain = *cookieDomain
	}
	cookie := &http.Cookie{
		Name:     p.CookieKey,
		Value:    signedCookieValue(p.CookieSeed, p.CookieKey, val),
		Path:     "/",
		Domain:   domain,
		Expires:  time.Now().Add(time.Duration(168) * time.Hour), // 7 days
		HttpOnly: true,
		// Secure: req. ... ? set if X-Scheme: https ?
	}
	http.SetCookie(rw, cookie)
}

func (p *OauthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, message string) {
	log.Printf("ErrorPage %d %s %s", code, title, message)
	rw.WriteHeader(code)
	templates := getTemplates()
	t := struct {
		Title   string
		Message string
	}{
		Title:   fmt.Sprintf("%d %s", code, title),
		Message: message,
	}
	templates.ExecuteTemplate(rw, "error.html", t)
}

func (p *OauthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) {
	p.ClearCookie(rw, req)
	rw.WriteHeader(code)
	templates := getTemplates()

	t := struct {
		SignInMessage string
		Htpasswd      bool
		Redirect      string
	}{
		SignInMessage: p.SignInMessage,
		Htpasswd:      p.HtpasswdFile != nil,
		Redirect:      req.URL.RequestURI(),
	}
	templates.ExecuteTemplate(rw, "sign_in.html", t)
}

func (p *OauthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool) {
	if req.Method != "POST" || p.HtpasswdFile == nil {
		return "", false
	}
	user := req.FormValue("username")
	passwd := req.FormValue("password")
	if user == "" {
		return "", false
	}
	// check auth
	if p.HtpasswdFile.Validate(user, passwd) {
		log.Printf("authenticated %s via manual sign in", user)
		return user, true
	}
	return "", false
}

func (p *OauthProxy) GetRedirect(req *http.Request) (string, error) {
	err := req.ParseForm()

	if err != nil {
		return "", err
	}

	redirect := req.FormValue("rd")

	if redirect == "" {
		redirect = "/"
	}

	return redirect, err
}

func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// check if this is a redirect back at the end of oauth
	remoteIP := req.Header.Get("X-Real-IP")
	if remoteIP == "" {
		remoteIP = req.RemoteAddr
	}
	log.Printf("%s %s %s", remoteIP, req.Method, req.URL.Path)

	var ok bool
	var user string

	if req.URL.Path == signInPath {
		redirect, err := p.GetRedirect(req)
		if err != nil {
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}

		user, ok = p.ManualSignIn(rw, req)
		if ok {
			p.SetCookie(rw, req, user)
			http.Redirect(rw, req, redirect, 302)
		} else {
			p.SignInPage(rw, req, 200)
		}
		return
	}
	if req.URL.Path == oauthStartPath {
		redirect, err := p.GetRedirect(req)
		if err != nil {
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}
		http.Redirect(rw, req, p.GetLoginURL(redirect), 302)
		return
	}
	if req.URL.Path == oauthCallbackPath {
		// finish the oauth cycle
		err := req.ParseForm()
		if err != nil {
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}
		errorString := req.Form.Get("error")
		if errorString != "" {
			p.ErrorPage(rw, 403, "Permission Denied", errorString)
			return
		}

		token, err := p.redeemCode(req.Form.Get("code"))
		if err != nil {
			log.Printf("error redeeming code %s", err.Error())
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}
		// validate user
		email, err := p.getUserInfo(token)
		if err != nil {
			log.Printf("error redeeming code %s", err.Error())
			p.ErrorPage(rw, 500, "Internal Error", err.Error())
			return
		}

		redirect := req.Form.Get("state")
		if redirect == "" {
			redirect = "/"
		}

		// set cookie, or deny
		if p.Validator(email) {
			log.Printf("authenticating %s completed", email)
			p.SetCookie(rw, req, email)
			http.Redirect(rw, req, redirect, 302)
			return
		} else {
			p.ErrorPage(rw, 403, "Permission Denied", "Invalid Account")
			return
		}
	}

	if !ok {
		cookie, err := req.Cookie(p.CookieKey)
		if err == nil {
			var email string
			email, ok = validateCookie(cookie, p.CookieSeed)
			user = strings.Split(email, "@")[0]
		}
	}

	if !ok {
		user, ok = p.CheckBasicAuth(req)
		// if we want to promote basic auth requests to cookie'd requests, we could do that here
		// not sure that would be ideal in all circumstances though
		// if ok {
		// 	p.SetCookie(rw, req, user)
		// }
	}

	if !ok {
		log.Printf("invalid cookie")
		p.SignInPage(rw, req, 403)
		return
	}

	// At this point, the user is authenticated. proxy normally
	if *passBasicAuth {
		req.SetBasicAuth(user, "")
		req.Header["X-Forwarded-User"] = []string{user}
	}

	p.serveMux.ServeHTTP(rw, req)
}

func (p *OauthProxy) CheckBasicAuth(req *http.Request) (string, bool) {
	if p.HtpasswdFile == nil {
		return "", false
	}
	s := strings.SplitN(req.Header.Get("Authorization"), " ", 2)
	if len(s) != 2 || s[0] != "Basic" {
		return "", false
	}
	b, err := base64.StdEncoding.DecodeString(s[1])
	if err != nil {
		return "", false
	}
	pair := strings.SplitN(string(b), ":", 2)
	if len(pair) != 2 {
		return "", false
	}
	if p.HtpasswdFile.Validate(pair[0], pair[1]) {
		log.Printf("authenticated %s via basic auth", pair[0])
		return pair[0], true
	}
	return "", false
}
<|endoftext|>


<commit_before>// Copyright 2015 LinkedIn Corp. 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.Copyright [201X] LinkedIn Corp. 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.

package goavro

import (
	"bufio"
	"bytes"
	"code.google.com/p/snappy-go/snappy"
	"compress/flate"
	"fmt"
	"io"
	"log"
	"math/rand"
)

// DefaultWriterBlockSize specifies the default number of datum items
// in a block when writing.
const DefaultWriterBlockSize = 10

// ErrWriterInit is returned when an error is created during Writer
// initialization.
type ErrWriterInit struct {
	Message string
	Err     error
}

// Error converts the error instance to a string.
func (e *ErrWriterInit) Error() string {
	if e.Err == nil {
		return "cannot create Writer: " + e.Message
	} else if e.Message == "" {
		return "cannot create Writer: " + e.Err.Error()
	} else {
		return "cannot create Writer: " + e.Message + "; " + e.Err.Error()
	}
}

// WriterSetter functions are those those which are used to
// instantiate a new Writer.
type WriterSetter func(*Writer) error

// ToWriter specifies which io.Writer is the target of the Writer
// stream.
func ToWriter(w io.Writer) WriterSetter {
	return func(fw *Writer) error {
		fw.w = w
		return nil
	}
}

// UseCodec specifies that a Writer should reuse an existing Codec
// rather than creating a new one, and recompling the same schema over
// and over.
func UseCodec(codec Codec) WriterSetter {
	return func(fw *Writer) error {
		if codec != nil {
			fw.dataCodec = codec
			return nil
		}
		return fmt.Errorf("invalid Codec")
	}
}

// BufferToWriter specifies which io.Writer is the target of the
// Writer stream, and creates a bufio.Writer around that
// io.Writer.
func BufferToWriter(w io.Writer) WriterSetter {
	return func(fw *Writer) error {
		fw.w = bufio.NewWriter(w)
		fw.buffered = true
		return nil
	}
}

// BlockSize specifies the default number of data items to be
// grouped in a block, compressed, and written to the stream.
func BlockSize(blockSize int64) WriterSetter {
	return func(fw *Writer) error {
		if blockSize <= 0 {
			return fmt.Errorf("blockSize must be larger than 0: %d", blockSize)
		}
		fw.blockSize = blockSize
		return nil
	}
}

// Compression is used to set the compression codec of
// a new Writer instance.
func Compression(someCompressionCodec string) WriterSetter {
	return func(fw *Writer) error {
		fw.CompressionCodec = someCompressionCodec
		return nil
	}
}

// Sync is used to set the sync marker bytes of a new
// instance. It checks to ensure the byte slice is 16 bytes long, but
// does not check that it has been set to something other than the
// zero value. Usually you can elide the `Sync` call and allow it
// to create a random byte sequence.
func Sync(someSync []byte) WriterSetter {
	return func(fw *Writer) error {
		if syncLength != len(someSync) {
			return fmt.Errorf("sync marker ought to be %d bytes long: %d", syncLength, len(someSync))
		}
		fw.Sync = make([]byte, syncLength)
		copy(fw.Sync, someSync)
		return nil
	}
}

// WriterSchema is used to set the Avro schema of a new instance.
func WriterSchema(someSchema string) WriterSetter {
	return func(fw *Writer) (err error) {
		if fw.dataCodec, err = NewCodec(someSchema); err != nil {
			return
		}
		return
	}
}

// Writer structure contains data necessary to write Avro files.
type Writer struct {
	CompressionCodec string
	Sync             []byte
	blockSize        int64
	buffered         bool
	dataCodec        Codec
	err              error
	toBlock          chan interface{}
	w                io.Writer
	writerDone       chan struct{}
}

// NewWriter returns a object to write data to an io.Writer using the
// Avro Object Container Files format.
//
//     func serveClient(conn net.Conn) {
//         fw, err := goavro.NewWriter(
//             goavro.BlockSize(100),
//             goavro.Compression(goavro.CompressionSnappy),
//             goavro.WriterSchema(recordSchema),
//             goavro.ToWriter(conn))
//         if err != nil {
//             log.Fatal("cannot create Writer: ", err)
//         }
//         defer fw.Close()
//
//         // create a record that matches the schema we want to encode
//         someRecord, err := goavro.NewRecord(goavro.RecordSchema(recordSchema))
//         if err != nil {
//             log.Fatal(err)
//         }
//         // identify field name to set datum for
//         someRecord.Set("username", "Aquaman")
//         someRecord.Set("comment", "The Atlantic is oddly cold this morning!")
//         // you can fully qualify the field name
//         someRecord.Set("com.example.timestamp", int64(1082196484))
//         fw.Write(someRecord)
//
//         // create another record
//         someRecord, err = goavro.NewRecord(goavro.RecordSchema(recordSchema))
//         if err != nil {
//             log.Fatal(err)
//         }
//         someRecord.Set("username", "Batman")
//         someRecord.Set("comment", "Who are all of these crazies?")
//         someRecord.Set("com.example.timestamp", int64(1427383430))
//         fw.Write(someRecord)
//     }
func NewWriter(setters ...WriterSetter) (*Writer, error) {
	var err error
	fw := &Writer{CompressionCodec: CompressionNull, blockSize: DefaultWriterBlockSize}
	for _, setter := range setters {
		err = setter(fw)
		if err != nil {
			return nil, &ErrWriterInit{Err: err}
		}
	}
	if fw.w == nil {
		return nil, &ErrWriterInit{Message: "must specify io.Writer"}
	}
	// writer: stuff should already be initialized
	if !IsCompressionCodecSupported(fw.CompressionCodec) {
		return nil, &ErrWriterInit{Message: fmt.Sprintf("unsupported codec: %s", fw.CompressionCodec)}
	}
	if fw.dataCodec == nil {
		return nil, &ErrWriterInit{Message: "missing schema"}
	}
	if fw.Sync == nil {
		// create random sequence of bytes for file sync marker
		fw.Sync = make([]byte, syncLength)
		for i := range fw.Sync {
			fw.Sync[i] = byte(rand.Intn(256))
		}
	}
	if err = fw.writeHeader(); err != nil {
		return nil, &ErrWriterInit{Err: err}
	}
	// setup writing pipeline
	fw.toBlock = make(chan interface{})
	toEncode := make(chan *writerBlock)
	toCompress := make(chan *writerBlock)
	toWrite := make(chan *writerBlock)
	fw.writerDone = make(chan struct{})
	go blocker(fw, fw.toBlock, toEncode)
	go encoder(fw, toEncode, toCompress)
	go compressor(fw, toCompress, toWrite)
	go writer(fw, toWrite)
	return fw, nil
}

// Close is called when the open file is no longer needed. It flushes
// the bytes to the `io.Writer` if the file is being writtern.
func (fw *Writer) Close() error {
	close(fw.toBlock)
	<-fw.writerDone
	if fw.buffered {
		return fw.w.(*bufio.Writer).Flush()
	}
	return nil
}

// Write places a datum into the pipeline to be written to the Writer.
func (fw *Writer) Write(datum interface{}) {
	fw.toBlock <- datum
}

func (fw *Writer) writeHeader() (err error) {
	if _, err = fw.w.Write([]byte(magicBytes)); err != nil {
		return
	}
	// header metadata
	hm := make(map[string]interface{})
	hm["avro.schema"] = []byte(fw.dataCodec.Schema())
	hm["avro.codec"] = []byte(fw.CompressionCodec)
	if err = metadataCodec.Encode(fw.w, hm); err != nil {
		return
	}
	_, err = fw.w.Write(fw.Sync)
	return
}

type writerBlock struct {
	items      []interface{}
	encoded    *bytes.Buffer
	compressed []byte
	err        error
}

func blocker(fw *Writer, toBlock <-chan interface{}, toEncode chan<- *writerBlock) {
	items := make([]interface{}, 0, fw.blockSize)
	for item := range toBlock {
		items = append(items, item)
		if int64(len(items)) == fw.blockSize {
			toEncode <- &writerBlock{items: items}
			items = make([]interface{}, 0, fw.BlockSize)
		}
	}
	if len(items) > 0 {
		toEncode <- &writerBlock{items: items}
	}
	close(toEncode)
}

func encoder(fw *Writer, toEncode <-chan *writerBlock, toCompress chan<- *writerBlock) {
	for block := range toEncode {
		if block.err == nil {
			block.encoded = new(bytes.Buffer)
			for _, item := range block.items {
				block.err = fw.dataCodec.Encode(block.encoded, item)
				if block.err != nil {
					break
				}
			}
		}
		toCompress <- block
	}
	close(toCompress)
}

func compressor(fw *Writer, toCompress <-chan *writerBlock, toWrite chan<- *writerBlock) {
	switch fw.CompressionCodec {
	case CompressionDeflate:
		bb := new(bytes.Buffer)
		comp, _ := flate.NewWriter(bb, flate.DefaultCompression)
		for block := range toCompress {
			_, block.err = comp.Write(block.encoded.Bytes())
			block.err = comp.Close()
			if block.err == nil {
				block.compressed = bb.Bytes()
				toWrite <- block
			}
			bb = new(bytes.Buffer)
			comp.Reset(bb)
		}
	case CompressionNull:
		for block := range toCompress {
			block.compressed = block.encoded.Bytes()
			toWrite <- block
		}
	case CompressionSnappy:
		for block := range toCompress {
			block.compressed, block.err = snappy.Encode(block.compressed, block.encoded.Bytes())
			if block.err != nil {
				block.err = fmt.Errorf("cannot compress: %v", block.err)
			}
			toWrite <- block
		}
	}
	close(toWrite)
}

func writer(fw *Writer, toWrite <-chan *writerBlock) {
	for block := range toWrite {
		if block.err == nil {
			block.err = longCodec.Encode(fw.w, int64(len(block.items)))
		}
		if block.err == nil {
			block.err = longCodec.Encode(fw.w, int64(len(block.compressed)))
		}
		if block.err == nil {
			_, block.err = fw.w.Write(block.compressed)
		}
		if block.err == nil {
			_, block.err = fw.w.Write(fw.Sync)
		}
		if block.err != nil {
			log.Printf("[WARNING] cannot write block: %v", block.err)
			fw.err = block.err // ???
			break
			// } else {
			// 	log.Printf("[DEBUG] block written: %d, %d, %v", len(block.items), len(block.compressed), block.compressed)
		}
	}
	if fw.err = longCodec.Encode(fw.w, int64(0)); fw.err == nil {
		fw.err = longCodec.Encode(fw.w, int64(0))
	}
	fw.writerDone <- struct{}{}
}
<commit_msg>Writer aggregates data items into blocks<commit_after>// Copyright 2015 LinkedIn Corp. 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.Copyright [201X] LinkedIn Corp. 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.

package goavro

import (
	"bufio"
	"bytes"
	"code.google.com/p/snappy-go/snappy"
	"compress/flate"
	"fmt"
	"io"
	"log"
	"math/rand"
)

// DefaultWriterBlockSize specifies the default number of datum items
// in a block when writing.
const DefaultWriterBlockSize = 10

// ErrWriterInit is returned when an error is created during Writer
// initialization.
type ErrWriterInit struct {
	Message string
	Err     error
}

// Error converts the error instance to a string.
func (e *ErrWriterInit) Error() string {
	if e.Err == nil {
		return "cannot create Writer: " + e.Message
	} else if e.Message == "" {
		return "cannot create Writer: " + e.Err.Error()
	} else {
		return "cannot create Writer: " + e.Message + "; " + e.Err.Error()
	}
}

// WriterSetter functions are those those which are used to
// instantiate a new Writer.
type WriterSetter func(*Writer) error

// ToWriter specifies which io.Writer is the target of the Writer
// stream.
func ToWriter(w io.Writer) WriterSetter {
	return func(fw *Writer) error {
		fw.w = w
		return nil
	}
}

// UseCodec specifies that a Writer should reuse an existing Codec
// rather than creating a new one, and recompling the same schema over
// and over.
func UseCodec(codec Codec) WriterSetter {
	return func(fw *Writer) error {
		if codec != nil {
			fw.dataCodec = codec
			return nil
		}
		return fmt.Errorf("invalid Codec")
	}
}

// BufferToWriter specifies which io.Writer is the target of the
// Writer stream, and creates a bufio.Writer around that
// io.Writer.
func BufferToWriter(w io.Writer) WriterSetter {
	return func(fw *Writer) error {
		fw.w = bufio.NewWriter(w)
		fw.buffered = true
		return nil
	}
}

// BlockSize specifies the default number of data items to be
// grouped in a block, compressed, and written to the stream.
func BlockSize(blockSize int64) WriterSetter {
	return func(fw *Writer) error {
		if blockSize <= 0 {
			return fmt.Errorf("blockSize must be larger than 0: %d", blockSize)
		}
		fw.blockSize = blockSize
		return nil
	}
}

// Compression is used to set the compression codec of
// a new Writer instance.
func Compression(someCompressionCodec string) WriterSetter {
	return func(fw *Writer) error {
		fw.CompressionCodec = someCompressionCodec
		return nil
	}
}

// Sync is used to set the sync marker bytes of a new
// instance. It checks to ensure the byte slice is 16 bytes long, but
// does not check that it has been set to something other than the
// zero value. Usually you can elide the `Sync` call and allow it
// to create a random byte sequence.
func Sync(someSync []byte) WriterSetter {
	return func(fw *Writer) error {
		if syncLength != len(someSync) {
			return fmt.Errorf("sync marker ought to be %d bytes long: %d", syncLength, len(someSync))
		}
		fw.Sync = make([]byte, syncLength)
		copy(fw.Sync, someSync)
		return nil
	}
}

// WriterSchema is used to set the Avro schema of a new instance.
func WriterSchema(someSchema string) WriterSetter {
	return func(fw *Writer) (err error) {
		if fw.dataCodec, err = NewCodec(someSchema); err != nil {
			return
		}
		return
	}
}

// Writer structure contains data necessary to write Avro files.
type Writer struct {
	CompressionCodec string
	Sync             []byte
	blockSize        int64
	buffered         bool
	dataCodec        Codec
	err              error
	toBlock          chan interface{}
	w                io.Writer
	writerDone       chan struct{}
}

// NewWriter returns a object to write data to an io.Writer using the
// Avro Object Container Files format.
//
//     func serveClient(conn net.Conn) {
//         fw, err := goavro.NewWriter(
//             goavro.BlockSize(100),
//             goavro.Compression(goavro.CompressionSnappy),
//             goavro.WriterSchema(recordSchema),
//             goavro.ToWriter(conn))
//         if err != nil {
//             log.Fatal("cannot create Writer: ", err)
//         }
//         defer fw.Close()
//
//         // create a record that matches the schema we want to encode
//         someRecord, err := goavro.NewRecord(goavro.RecordSchema(recordSchema))
//         if err != nil {
//             log.Fatal(err)
//         }
//         // identify field name to set datum for
//         someRecord.Set("username", "Aquaman")
//         someRecord.Set("comment", "The Atlantic is oddly cold this morning!")
//         // you can fully qualify the field name
//         someRecord.Set("com.example.timestamp", int64(1082196484))
//         fw.Write(someRecord)
//
//         // create another record
//         someRecord, err = goavro.NewRecord(goavro.RecordSchema(recordSchema))
//         if err != nil {
//             log.Fatal(err)
//         }
//         someRecord.Set("username", "Batman")
//         someRecord.Set("comment", "Who are all of these crazies?")
//         someRecord.Set("com.example.timestamp", int64(1427383430))
//         fw.Write(someRecord)
//     }
func NewWriter(setters ...WriterSetter) (*Writer, error) {
	var err error
	fw := &Writer{CompressionCodec: CompressionNull, blockSize: DefaultWriterBlockSize}
	for _, setter := range setters {
		err = setter(fw)
		if err != nil {
			return nil, &ErrWriterInit{Err: err}
		}
	}
	if fw.w == nil {
		return nil, &ErrWriterInit{Message: "must specify io.Writer"}
	}
	// writer: stuff should already be initialized
	if !IsCompressionCodecSupported(fw.CompressionCodec) {
		return nil, &ErrWriterInit{Message: fmt.Sprintf("unsupported codec: %s", fw.CompressionCodec)}
	}
	if fw.dataCodec == nil {
		return nil, &ErrWriterInit{Message: "missing schema"}
	}
	if fw.Sync == nil {
		// create random sequence of bytes for file sync marker
		fw.Sync = make([]byte, syncLength)
		for i := range fw.Sync {
			fw.Sync[i] = byte(rand.Intn(256))
		}
	}
	if err = fw.writeHeader(); err != nil {
		return nil, &ErrWriterInit{Err: err}
	}
	// setup writing pipeline
	fw.toBlock = make(chan interface{})
	toEncode := make(chan *writerBlock)
	toCompress := make(chan *writerBlock)
	toWrite := make(chan *writerBlock)
	fw.writerDone = make(chan struct{})
	go blocker(fw, fw.toBlock, toEncode)
	go encoder(fw, toEncode, toCompress)
	go compressor(fw, toCompress, toWrite)
	go writer(fw, toWrite)
	return fw, nil
}

// Close is called when the open file is no longer needed. It flushes
// the bytes to the `io.Writer` if the file is being writtern.
func (fw *Writer) Close() error {
	close(fw.toBlock)
	<-fw.writerDone
	if fw.buffered {
		return fw.w.(*bufio.Writer).Flush()
	}
	return nil
}

// Write places a datum into the pipeline to be written to the Writer.
func (fw *Writer) Write(datum interface{}) {
	fw.toBlock <- datum
}

func (fw *Writer) writeHeader() (err error) {
	if _, err = fw.w.Write([]byte(magicBytes)); err != nil {
		return
	}
	// header metadata
	hm := make(map[string]interface{})
	hm["avro.schema"] = []byte(fw.dataCodec.Schema())
	hm["avro.codec"] = []byte(fw.CompressionCodec)
	if err = metadataCodec.Encode(fw.w, hm); err != nil {
		return
	}
	_, err = fw.w.Write(fw.Sync)
	return
}

type writerBlock struct {
	items      []interface{}
	encoded    *bytes.Buffer
	compressed []byte
	err        error
}

func blocker(fw *Writer, toBlock <-chan interface{}, toEncode chan<- *writerBlock) {
	items := make([]interface{}, 0, fw.blockSize)
	for item := range toBlock {
		items = append(items, item)
		if int64(len(items)) == fw.blockSize {
			toEncode <- &writerBlock{items: items}
			items = make([]interface{}, 0, fw.blockSize)
		}
	}
	if len(items) > 0 {
		toEncode <- &writerBlock{items: items}
	}
	close(toEncode)
}

func encoder(fw *Writer, toEncode <-chan *writerBlock, toCompress chan<- *writerBlock) {
	for block := range toEncode {
		if block.err == nil {
			block.encoded = new(bytes.Buffer)
			for _, item := range block.items {
				block.err = fw.dataCodec.Encode(block.encoded, item)
				if block.err != nil {
					break
				}
			}
		}
		toCompress <- block
	}
	close(toCompress)
}

func compressor(fw *Writer, toCompress <-chan *writerBlock, toWrite chan<- *writerBlock) {
	switch fw.CompressionCodec {
	case CompressionDeflate:
		bb := new(bytes.Buffer)
		comp, _ := flate.NewWriter(bb, flate.DefaultCompression)
		for block := range toCompress {
			_, block.err = comp.Write(block.encoded.Bytes())
			block.err = comp.Close()
			if block.err == nil {
				block.compressed = bb.Bytes()
				toWrite <- block
			}
			bb = new(bytes.Buffer)
			comp.Reset(bb)
		}
	case CompressionNull:
		for block := range toCompress {
			block.compressed = block.encoded.Bytes()
			toWrite <- block
		}
	case CompressionSnappy:
		for block := range toCompress {
			block.compressed, block.err = snappy.Encode(block.compressed, block.encoded.Bytes())
			if block.err != nil {
				block.err = fmt.Errorf("cannot compress: %v", block.err)
			}
			toWrite <- block
		}
	}
	close(toWrite)
}

func writer(fw *Writer, toWrite <-chan *writerBlock) {
	for block := range toWrite {
		if block.err == nil {
			block.err = longCodec.Encode(fw.w, int64(len(block.items)))
		}
		if block.err == nil {
			block.err = longCodec.Encode(fw.w, int64(len(block.compressed)))
		}
		if block.err == nil {
			_, block.err = fw.w.Write(block.compressed)
		}
		if block.err == nil {
			_, block.err = fw.w.Write(fw.Sync)
		}
		if block.err != nil {
			log.Printf("[WARNING] cannot write block: %v", block.err)
			fw.err = block.err // ???
			break
			// } else {
			// 	log.Printf("[DEBUG] block written: %d, %d, %v", len(block.items), len(block.compressed), block.compressed)
		}
	}
	if fw.err = longCodec.Encode(fw.w, int64(0)); fw.err == nil {
		fw.err = longCodec.Encode(fw.w, int64(0))
	}
	fw.writerDone <- struct{}{}
}
<|endoftext|>


<commit_before>// Copyright 2015 CloudAwan LLC
//
// 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 configuration

import (
	"errors"
	analysisLogger "github.com/cloudawan/cloudone_analysis/utility/logger"
	"github.com/cloudawan/cloudone_utility/configuration"
	"github.com/cloudawan/cloudone_utility/logger"
	"github.com/cloudawan/cloudone_utility/restclient"
	"strconv"
	"strings"
)

var log = analysisLogger.GetLogManager().GetLogger("utility")

var configurationContent = `
{
	"certificate": "/etc/cloudone_analysis/development_cert.pem",
	"key": "/etc/cloudone_analysis/development_key.pem",
	"elasticsearchHost": ["127.0.0.1"],
	"elasticsearchPort": 9200,
	"kubeapiHostAndPort": ["127.0.0.1:8080"]
}
`

var LocalConfiguration *configuration.Configuration

func init() {
	var err error
	LocalConfiguration, err = configuration.CreateConfiguration("cloudone_analysis", configurationContent)
	if err != nil {
		log.Critical(err)
		panic(err)
	}
}

func GetAvailableKubeapiHostAndPort() (returnedHost string, returnedPort int, returnedError error) {
	defer func() {
		if err := recover(); err != nil {
			returnedHost = ""
			returnedPort = 0
			returnedError = err.(error)
			log.Error("GetAvailableKubeapiHostAndPort Error: %s", err)
			log.Error(logger.GetStackTrace(4096, false))
		}
	}()

	kubeapiHostAndPortSlice, ok := LocalConfiguration.GetStringSlice("kubeapiHostAndPort")
	if ok == false {
		log.Error("Fail to get configuration kubeapiHostAndPort")
		return "", 0, errors.New("Fail to get configuration kubeapiHostAndPort")
	}
	for _, kubeapiHostAndPort := range kubeapiHostAndPortSlice {
		_, err := restclient.RequestGet("http://"+kubeapiHostAndPort, false)
		if err == nil {
			splitSlice := strings.Split(kubeapiHostAndPort, ":")
			host := splitSlice[0]
			port, err := strconv.Atoi(splitSlice[1])
			if err != nil {
				log.Error(err)
				return "", 0, err
			}
			return host, port, nil
		}
	}

	log.Error("No available host and port")
	return "", 0, errors.New("No available host and port")
}
<commit_msg>Change to health check with timeout<commit_after>// Copyright 2015 CloudAwan LLC
//
// 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 configuration

import (
	"errors"
	analysisLogger "github.com/cloudawan/cloudone_analysis/utility/logger"
	"github.com/cloudawan/cloudone_utility/configuration"
	"github.com/cloudawan/cloudone_utility/logger"
	"github.com/cloudawan/cloudone_utility/restclient"
	"strconv"
	"strings"
	"time"
)

var log = analysisLogger.GetLogManager().GetLogger("utility")

var configurationContent = `
{
	"certificate": "/etc/cloudone_analysis/development_cert.pem",
	"key": "/etc/cloudone_analysis/development_key.pem",
	"elasticsearchHost": ["127.0.0.1"],
	"elasticsearchPort": 9200,
	"kubeapiHostAndPort": ["127.0.0.1:8080"]
}
`

var LocalConfiguration *configuration.Configuration

func init() {
	var err error
	LocalConfiguration, err = configuration.CreateConfiguration("cloudone_analysis", configurationContent)
	if err != nil {
		log.Critical(err)
		panic(err)
	}
}

func GetAvailableKubeapiHostAndPort() (returnedHost string, returnedPort int, returnedError error) {
	defer func() {
		if err := recover(); err != nil {
			returnedHost = ""
			returnedPort = 0
			returnedError = err.(error)
			log.Error("GetAvailableKubeapiHostAndPort Error: %s", err)
			log.Error(logger.GetStackTrace(4096, false))
		}
	}()

	kubeapiHostAndPortSlice, ok := LocalConfiguration.GetStringSlice("kubeapiHostAndPort")
	if ok == false {
		log.Error("Fail to get configuration kubeapiHostAndPort")
		return "", 0, errors.New("Fail to get configuration kubeapiHostAndPort")
	}
	for _, kubeapiHostAndPort := range kubeapiHostAndPortSlice {
		result, err := restclient.HealthCheck("http://"+kubeapiHostAndPort, time.Second)

		if result {
			splitSlice := strings.Split(kubeapiHostAndPort, ":")
			host := splitSlice[0]
			port, err := strconv.Atoi(splitSlice[1])
			if err != nil {
				log.Error(err)
				return "", 0, err
			}
			return host, port, nil
		} else {
			if err != nil {
				log.Error(err)
			}
		}
	}

	log.Error("No available host and port")
	return "", 0, errors.New("No available host and port")
}
<|endoftext|>


<commit_before>package okta

import (
	"fmt"
	"time"
)

type UsersService service

type User struct {
	Activated   string `json:"activated"`
	Created     string `json:"created"`
	Credentials struct {
		Password struct{} `json:"password"`
		Provider struct {
			Name string `json:"name"`
			Type string `json:"type"`
		} `json:"provider"`
		RecoveryQuestion struct {
			Question string `json:"question"`
		} `json:"recovery_question"`
	} `json:"credentials"`
	ID              string  `json:"id"`
	LastLogin       string  `json:"lastLogin"`
	LastUpdated     string  `json:"lastUpdated"`
	PasswordChanged string  `json:"passwordChanged"`
	Profile         profile `json:"profile"`
	Status          string  `json:"status"`
	StatusChanged   string  `json:"statusChanged"`
	Links           struct {
		ChangePassword struct {
			Href string `json:"href"`
		} `json:"changePassword"`
		ChangeRecoveryQuestion struct {
			Href string `json:"href"`
		} `json:"changeRecoveryQuestion"`
		Deactivate struct {
			Href string `json:"href"`
		} `json:"deactivate"`
		ExpirePassword struct {
			Href string `json:"href"`
		} `json:"expirePassword"`
		ForgotPassword struct {
			Href string `json:"href"`
		} `json:"forgotPassword"`
		ResetFactors struct {
			Href string `json:"href"`
		} `json:"resetFactors"`
		ResetPassword struct {
			Href string `json:"href"`
		} `json:"resetPassword"`
	} `json:"_links"`

	factors []UserMFAFactor
}

type UserMFAFactor struct {
	ID          string    `json:"id"`
	FactorType  string    `json:"factorType"`
	Provider    string    `json:"provider"`
	VendorName  string    `json:"vendorName"`
	Status      string    `json:"status"`
	Created     time.Time `json:"created"`
	LastUpdated time.Time `json:"lastUpdated"`
	Profile     struct {
		CredentialID string `json:"credentialId"`
	} `json:"profile"`
}

type profile struct {
	Email       string `json:"email"`
	FirstName   string `json:"firstName"`
	LastName    string `json:"lastName"`
	Login       string `json:"login"`
	MobilePhone string `json:"mobilePhone"`
	SecondEmail string `json:"secondEmail"`
	PsEmplid    string `json:"psEmplid"`
	NickName    string `json:"nickname"`
	DisplayName string `json:"displayName"`

	ProfileURL        string `json:"profileUrl"`
	PreferredLanguage string `json:"preferredLanguage"`
	UserType          string `json:"userType"`
	Organization      string `json:"organization"`
	Title             string `json:"title"`
	Division          string `json:"division"`
	Department        string `json:"department"`
	CostCenter        string `json:"costCenter"`
	EmployeeNumber    string `json:"employeeNumber"`
	PrimaryPhone      string `json:"primaryPhone"`
	StreetAddress     string `json:"streetAddress"`
	City              string `json:"city"`
	State             string `json:"state"`
	ZipCode           string `json:"zipCode"`
	CountryCode       string `json:"countryCode"`
}

func (u User) String() string {
	return Stringify(u)
}

func (s *UsersService) GetByID(id int) (*User, *Response, error) {
	u := fmt.Sprintf("user/%d", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	user := new(User)
	resp, err := s.client.Do(req, user)
	if err != nil {
		return nil, resp, err
	}

	return user, resp, err
}
<commit_msg>change user input to string<commit_after>package okta

import (
	"fmt"
	"time"
)

type UsersService service

type User struct {
	Activated   string `json:"activated"`
	Created     string `json:"created"`
	Credentials struct {
		Password struct{} `json:"password"`
		Provider struct {
			Name string `json:"name"`
			Type string `json:"type"`
		} `json:"provider"`
		RecoveryQuestion struct {
			Question string `json:"question"`
		} `json:"recovery_question"`
	} `json:"credentials"`
	ID              string  `json:"id"`
	LastLogin       string  `json:"lastLogin"`
	LastUpdated     string  `json:"lastUpdated"`
	PasswordChanged string  `json:"passwordChanged"`
	Profile         profile `json:"profile"`
	Status          string  `json:"status"`
	StatusChanged   string  `json:"statusChanged"`
	Links           struct {
		ChangePassword struct {
			Href string `json:"href"`
		} `json:"changePassword"`
		ChangeRecoveryQuestion struct {
			Href string `json:"href"`
		} `json:"changeRecoveryQuestion"`
		Deactivate struct {
			Href string `json:"href"`
		} `json:"deactivate"`
		ExpirePassword struct {
			Href string `json:"href"`
		} `json:"expirePassword"`
		ForgotPassword struct {
			Href string `json:"href"`
		} `json:"forgotPassword"`
		ResetFactors struct {
			Href string `json:"href"`
		} `json:"resetFactors"`
		ResetPassword struct {
			Href string `json:"href"`
		} `json:"resetPassword"`
	} `json:"_links"`

	factors []UserMFAFactor
}

type UserMFAFactor struct {
	ID          string    `json:"id"`
	FactorType  string    `json:"factorType"`
	Provider    string    `json:"provider"`
	VendorName  string    `json:"vendorName"`
	Status      string    `json:"status"`
	Created     time.Time `json:"created"`
	LastUpdated time.Time `json:"lastUpdated"`
	Profile     struct {
		CredentialID string `json:"credentialId"`
	} `json:"profile"`
}

type profile struct {
	Email       string `json:"email"`
	FirstName   string `json:"firstName"`
	LastName    string `json:"lastName"`
	Login       string `json:"login"`
	MobilePhone string `json:"mobilePhone"`
	SecondEmail string `json:"secondEmail"`
	PsEmplid    string `json:"psEmplid"`
	NickName    string `json:"nickname"`
	DisplayName string `json:"displayName"`

	ProfileURL        string `json:"profileUrl"`
	PreferredLanguage string `json:"preferredLanguage"`
	UserType          string `json:"userType"`
	Organization      string `json:"organization"`
	Title             string `json:"title"`
	Division          string `json:"division"`
	Department        string `json:"department"`
	CostCenter        string `json:"costCenter"`
	EmployeeNumber    string `json:"employeeNumber"`
	PrimaryPhone      string `json:"primaryPhone"`
	StreetAddress     string `json:"streetAddress"`
	City              string `json:"city"`
	State             string `json:"state"`
	ZipCode           string `json:"zipCode"`
	CountryCode       string `json:"countryCode"`
}

func (u User) String() string {
	return Stringify(u)
}

func (s *UsersService) GetByID(id string) (*User, *Response, error) {
	u := fmt.Sprintf("user/%v", id)
	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	user := new(User)
	resp, err := s.client.Do(req, user)
	if err != nil {
		return nil, resp, err
	}

	return user, resp, err
}
<|endoftext|>


<commit_before>package demo

import (
	"encoding/base64"
	"encoding/json"
)

type AppState struct {
	Domain string `json:"domain"`
}

func (s AppState) encodeState() string {
	m, _ := json.Marshal(s)
	state := base64.StdEncoding.EncodeToString(m)
	return state
}

func (n *AppState) decodeState(s string) {
	str, err := base64.StdEncoding.DecodeString(s)

	if err == nil {
		json.Unmarshal(str, n)
	}
}
<commit_msg>add copyright notice header<commit_after>// Copyright 2016 Takbok, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package demo

import (
	"encoding/base64"
	"encoding/json"
)

type AppState struct {
	Domain string `json:"domain"`
}

func (s AppState) encodeState() string {
	m, _ := json.Marshal(s)
	state := base64.StdEncoding.EncodeToString(m)
	return state
}

func (n *AppState) decodeState(s string) {
	str, err := base64.StdEncoding.DecodeString(s)

	if err == nil {
		json.Unmarshal(str, n)
	}
}
<|endoftext|>


<commit_before>package doubleratchet

// TODO: For Bob to be able to send messages right after he initiated a session it's required
// to populate his sending chain with the shared secret. Should it be the same secret both
// parties agreed upon before the communication or should it be a separate key?
// TODO: Max chain length? What happens when N in message header closes in on overflowing? Perform Ratchet step?

// TODO
// Any Double Ratchet message encrypted using Alice's initial sending chain can serve as
// an "initial ciphertext" for X3DH. To deal with the possibility of lost or out-of-order messages,
// a recommended pattern is for Alice to repeatedly send the same X3DH initial message prepended
// to all of her Double Ratchet messages until she receives Bob's first Double Ratchet response message.

import (
	"fmt"
)

// State of the party involved in The Double Ratchet Algorithm.
type State interface {
	// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
	// the resulting message key.
	RatchetEncrypt(plaintext []byte, ad AssociatedData) Message

	// RatchetDecrypt is called to decrypt messages.
	RatchetDecrypt(m Message, ad AssociatedData) ([]byte, error)
}

// Operations on this object are NOT THREAD-SAFE, make sure they're done in sequence.
// TODO: Store skipper separately.
// TODO: Store state separately?
type state struct {
	// 32-byte root key. Both parties MUST agree on this key before starting a ratchet session.
	RK [32]byte

	// DH Ratchet public key (the remote key).
	DHr [32]byte

	// DH Ratchet key pair (the self ratchet key).
	DHs DHPair

	// 32-byte Chain Keys for sending and receiving.
	CKs, CKr [32]byte

	// Message numbers for sending and receiving.
	Ns, Nr uint

	// Number of messages in previous sending chain.
	PN uint

	// Dictionary of skipped-over message keys, indexed by ratchet public key and message number.
	MkSkipped map[string][32]byte

	// MaxSkip should be set high enough to tolerate routine lost or delayed messages,
	// but low enough that a malicious sender can't trigger excessive recipient computation.
	MaxSkip uint

	// Cryptography functions for the Double Ratchet Algorithm to function.
	Crypto Crypto
}

// New creates state with the shared key and public key of the other party initiating the session.
// If this party initiates the session, pubKey must be nil.
func New(sharedKey [32]byte, opts ...Option) (State, error) {
	if sharedKey == [32]byte{} {
		return nil, fmt.Errorf("sharedKey must be non-zero")
	}
	s := &state{
		RK:        sharedKey,
		MkSkipped: make(map[string][32]byte),
		MaxSkip:   1000,
		Crypto:    DefaultCrypto{},
	}

	var err error
	s.DHs, err = s.Crypto.GenerateDH()
	if err != nil {
		return nil, fmt.Errorf("failed to generate dh pair: %s", err)
	}

	for i := range opts {
		if err := opts[i](s); err != nil {
			return nil, fmt.Errorf("failed to apply option: %s", err)
		}
	}

	return s, nil
}

// Option is a constructor option.
type Option func(*state) error

// WithRemoteKey specifies the remote public key for the sending chain.
func WithRemoteKey(dhRemotePubKey [32]byte) Option {
	return func(s *state) error {
		s.DHr = dhRemotePubKey
		s.RK, s.CKs = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
		return nil
	}
}

// WithMaxSkip specifies the maximum number of skipped message in a single chain.
func WithMaxSkip(maxSkip int) Option {
	return func(s *state) error {
		if maxSkip < 0 {
			return fmt.Errorf("maxSkip must be non-negative")
		}
		s.MaxSkip = uint(maxSkip)
		return nil
	}
}

// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
// the resulting message key.
func (s *state) RatchetEncrypt(plaintext []byte, ad AssociatedData) Message {
	var mk [32]byte
	s.CKs, mk = s.Crypto.KdfCK(s.CKs)
	h := MessageHeader{
		DH: s.DHs.PublicKey(),
		N:  s.Ns,
		PN: s.PN,
	}
	s.Ns++
	ciphertext := s.Crypto.Encrypt(mk, plaintext, h.EncodeWithAD(ad))
	return Message{
		Header:     h,
		Ciphertext: ciphertext,
	}
}

// RatchetDecrypt is called to decrypt messages.
func (s *state) RatchetDecrypt(m Message, ad AssociatedData) ([]byte, error) {
	plaintext, err := s.trySkippedMessageKeys(m, ad)
	if err != nil {
		return nil, fmt.Errorf("can't decrypt skipped message: %s", err)
	}
	if plaintext != nil {
		return plaintext, nil
	}
	if m.Header.DH != s.DHs.PublicKey() {
		s.skipMessageKeys(m.Header.PN)
		if err := s.dhRatchet(m.Header); err != nil {
			// TODO: Rollback state changes.
			return nil, fmt.Errorf("failed to perform ratchet step: %s", err)
		}
	}
	s.skipMessageKeys(m.Header.N)
	var mk [32]byte
	s.CKr, mk = s.Crypto.KdfCK(s.CKr)
	s.Nr++
	// TODO: Discard the message in case of error and rollback the skipped key.
	return s.Crypto.Decrypt(mk, m.Ciphertext, m.Header.EncodeWithAD(ad))
}

// trySkippedMessageKeys tries to decrypt the message with a skipped message key.
func (s *state) trySkippedMessageKeys(m Message, ad AssociatedData) ([]byte, error) {
	skippedKey := s.skippedKey(m.Header.DH[:], m.Header.N)
	if mk, ok := s.MkSkipped[skippedKey]; ok {
		plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, m.Header.EncodeWithAD(ad))
		if err != nil {
			return nil, err
		}
		delete(s.MkSkipped, skippedKey)
		return plaintext, nil
	}
	return nil, nil
}

// skippedKey forms a key for a skipped message.
func (s *state) skippedKey(dh []byte, n uint) string {
	// TODO: More compact representation.
	nByte := []byte(fmt.Sprintf("_%d", n))
	return string(append(dh, nByte...))
}

// skipMessageKeys skips message keys in the current receiving chain.
func (s *state) skipMessageKeys(until uint) {
	// TODO: What is it?..
	if s.Nr+s.MaxSkip < until {
		// TODO: Return error.
		return
	}
	// TODO: Why?..
	// TODO: Fill CKr with something so that there's no such a check.
	//if s.CKr != nil {
	//for s.Nr < until {
	//	var mk [32]byte
	//	s.CKr, mk = s.Crypto.KdfCK(s.CKr)
	//	s.MkSkipped[s.skippedKey(s.DHr[:], s.Nr)] = mk
	//	s.Nr += 1
	//}
	//}
}

// dhRatchet performs a single ratchet step.
func (s *state) dhRatchet(mh MessageHeader) error {
	// TODO: Discard state changes in case of error.
	var err error

	s.PN = s.Ns
	s.Ns = 0
	s.Nr = 0
	s.DHr = mh.DH
	s.RK, s.CKr = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
	s.DHs, err = s.Crypto.GenerateDH()
	if err != nil {
		return fmt.Errorf("failed to generate dh pair: %s", err)
	}
	s.RK, s.CKs = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
	return nil
}
<commit_msg>skipMessageKeys now returns error<commit_after>package doubleratchet

// TODO: For Bob to be able to send messages right after he initiated a session it's required
// to populate his sending chain with the shared secret. Should it be the same secret both
// parties agreed upon before the communication or should it be a separate key?
// TODO: Max chain length? What happens when N in message header closes in on overflowing? Perform Ratchet step?

// TODO
// Any Double Ratchet message encrypted using Alice's initial sending chain can serve as
// an "initial ciphertext" for X3DH. To deal with the possibility of lost or out-of-order messages,
// a recommended pattern is for Alice to repeatedly send the same X3DH initial message prepended
// to all of her Double Ratchet messages until she receives Bob's first Double Ratchet response message.

import (
	"fmt"
)

// State of the party involved in The Double Ratchet Algorithm.
type State interface {
	// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
	// the resulting message key.
	RatchetEncrypt(plaintext []byte, ad AssociatedData) Message

	// RatchetDecrypt is called to decrypt messages.
	RatchetDecrypt(m Message, ad AssociatedData) ([]byte, error)
}

// Operations on this object are NOT THREAD-SAFE, make sure they're done in sequence.
// TODO: Store skipper separately.
// TODO: Store state separately?
type state struct {
	// 32-byte root key. Both parties MUST agree on this key before starting a ratchet session.
	RK [32]byte

	// DH Ratchet public key (the remote key).
	DHr [32]byte

	// DH Ratchet key pair (the self ratchet key).
	DHs DHPair

	// 32-byte Chain Keys for sending and receiving.
	CKs, CKr [32]byte

	// Message numbers for sending and receiving.
	Ns, Nr uint

	// Number of messages in previous sending chain.
	PN uint

	// Dictionary of skipped-over message keys, indexed by ratchet public key and message number.
	MkSkipped map[string][32]byte

	// MaxSkip should be set high enough to tolerate routine lost or delayed messages,
	// but low enough that a malicious sender can't trigger excessive recipient computation.
	MaxSkip uint

	// Cryptography functions for the Double Ratchet Algorithm to function.
	Crypto Crypto
}

// New creates state with the shared key and public key of the other party initiating the session.
// If this party initiates the session, pubKey must be nil.
func New(sharedKey [32]byte, opts ...Option) (State, error) {
	if sharedKey == [32]byte{} {
		return nil, fmt.Errorf("sharedKey must be non-zero")
	}
	s := &state{
		RK:        sharedKey,
		MkSkipped: make(map[string][32]byte),
		MaxSkip:   1000,
		Crypto:    DefaultCrypto{},
	}

	var err error
	s.DHs, err = s.Crypto.GenerateDH()
	if err != nil {
		return nil, fmt.Errorf("failed to generate dh pair: %s", err)
	}

	for i := range opts {
		if err := opts[i](s); err != nil {
			return nil, fmt.Errorf("failed to apply option: %s", err)
		}
	}

	return s, nil
}

// Option is a constructor option.
type Option func(*state) error

// WithRemoteKey specifies the remote public key for the sending chain.
func WithRemoteKey(dhRemotePubKey [32]byte) Option {
	return func(s *state) error {
		s.DHr = dhRemotePubKey
		s.RK, s.CKs = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
		return nil
	}
}

// WithMaxSkip specifies the maximum number of skipped message in a single chain.
func WithMaxSkip(maxSkip int) Option {
	return func(s *state) error {
		if maxSkip < 0 {
			return fmt.Errorf("maxSkip must be non-negative")
		}
		s.MaxSkip = uint(maxSkip)
		return nil
	}
}

// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
// the resulting message key.
func (s *state) RatchetEncrypt(plaintext []byte, ad AssociatedData) Message {
	var mk [32]byte
	s.CKs, mk = s.Crypto.KdfCK(s.CKs)
	h := MessageHeader{
		DH: s.DHs.PublicKey(),
		N:  s.Ns,
		PN: s.PN,
	}
	s.Ns++
	ciphertext := s.Crypto.Encrypt(mk, plaintext, h.EncodeWithAD(ad))
	return Message{
		Header:     h,
		Ciphertext: ciphertext,
	}
}

// RatchetDecrypt is called to decrypt messages.
func (s *state) RatchetDecrypt(m Message, ad AssociatedData) ([]byte, error) {
	// Is the messages one of the skipped?
	plaintext, err := s.trySkippedMessageKeys(m, ad)
	if err != nil {
		return nil, fmt.Errorf("can't decrypt skipped message: %s", err)
	}
	if plaintext != nil {
		return plaintext, nil
	}
	if m.Header.DH != s.DHr {
		if err := s.skipMessageKeys(m.Header.PN); err != nil {
			return nil, fmt.Errorf("failed to skip message keys: %s", err)
		}
		if err := s.dhRatchet(m.Header); err != nil {
			// TODO: Rollback state changes.
			return nil, fmt.Errorf("failed to perform ratchet step: %s", err)
		}
	}
	s.skipMessageKeys(m.Header.N)
	var mk [32]byte
	s.CKr, mk = s.Crypto.KdfCK(s.CKr)
	s.Nr++
	// TODO: Discard the message in case of error and rollback the state.
	return s.Crypto.Decrypt(mk, m.Ciphertext, m.Header.EncodeWithAD(ad))
}

// trySkippedMessageKeys tries to decrypt the message with a skipped message key.
func (s *state) trySkippedMessageKeys(m Message, ad AssociatedData) ([]byte, error) {
	k := s.skippedKey(m.Header.DH[:], m.Header.N)
	if mk, ok := s.MkSkipped[k]; ok {
		plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, m.Header.EncodeWithAD(ad))
		if err != nil {
			return nil, err
		}
		delete(s.MkSkipped, k)
		return plaintext, nil
	}
	return nil, nil
}

// skippedKey forms a key for a skipped message.
func (s *state) skippedKey(dh []byte, n uint) string {
	// TODO: More compact representation.
	nByte := []byte(fmt.Sprintf("_%d", n))
	return string(append(dh, nByte...))
}

// skipMessageKeys skips message keys in the current receiving chain.
func (s *state) skipMessageKeys(until uint) error {
	// until exceeds the number of messages in the receiving chain on more than s.MaxSkip
	if s.Nr+s.MaxSkip < until {
		return fmt.Errorf("too many messages: %d", until-s.Nr)
	}
	//if s.CKr != nil {
	//for s.Nr < until {
	//	var mk [32]byte
	//	s.CKr, mk = s.Crypto.KdfCK(s.CKr)
	//	s.MkSkipped[s.skippedKey(s.DHr[:], s.Nr)] = mk
	//	s.Nr += 1
	//}
	//}
	return nil
}

// dhRatchet performs a single ratchet step.
func (s *state) dhRatchet(mh MessageHeader) error {
	// TODO: Discard state changes in case of error.
	var err error

	s.PN = s.Ns
	s.Ns = 0
	s.Nr = 0
	s.DHr = mh.DH
	s.RK, s.CKr = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
	s.DHs, err = s.Crypto.GenerateDH()
	if err != nil {
		return fmt.Errorf("failed to generate dh pair: %s", err)
	}
	s.RK, s.CKs = s.Crypto.KdfRK(s.RK, s.Crypto.DH(s.DHs, s.DHr))
	return nil
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to state tracking.  If enabled, state
// tracking will capture the initial READY packet and many other websocket
// events and maintain an in-memory state of of guilds, channels, users, and
// so forth.  This information can be accessed through the Session.State struct.

package discordgo

import (
	"errors"
	"fmt"
)

// ErrNilState is returned when the state is nil.
var ErrNilState = errors.New("State not instantiated, please use discordgo.New() or assign Session.State.")

// NewState creates an empty state.
func NewState() *State {
	return &State{
		Ready: Ready{
			PrivateChannels: []*Channel{},
			Guilds:          []*Guild{},
		},
	}
}

// OnReady takes a Ready event and updates all internal state.
func (s *State) OnReady(r *Ready) error {
	if s == nil {
		return ErrNilState
	}

	s.Lock()
	defer s.Unlock()

	s.Ready = *r

	for _, g := range s.Guilds {
		for _, c := range g.Channels {
			c.GuildID = g.ID
		}
	}

	return nil
}

// GuildAdd adds a guild to the current world state, or
// updates it if it already exists.
func (s *State) GuildAdd(guild *Guild) error {
	if s == nil {
		return ErrNilState
	}

	s.Lock()
	defer s.Unlock()

	// If the guild exists, replace it.
	for i, g := range s.Guilds {
		if g.ID == guild.ID {
			// Don't stomp on properties that don't come in updates.
			guild.Members = g.Members
			guild.Presences = g.Presences
			guild.Channels = g.Channels
			guild.VoiceStates = g.VoiceStates
			s.Guilds[i] = guild
			return nil
		}
	}

	s.Guilds = append(s.Guilds, guild)
	return nil
}

// GuildRemove removes a guild from current world state.
func (s *State) GuildRemove(guild *Guild) error {
	if s == nil {
		return ErrNilState
	}

	s.Lock()
	defer s.Unlock()

	for i, g := range s.Guilds {
		if g.ID == guild.ID {
			s.Guilds = append(s.Guilds[:i], s.Guilds[i+1:]...)
			return nil
		}
	}

	return errors.New("Guild not found.")
}

// Guild gets a guild by ID.
// Useful for querying if @me is in a guild:
//     _, err := discordgo.Session.State.Guild(guildID)
//     isInGuild := err == nil
func (s *State) Guild(guildID string) (*Guild, error) {
	if s == nil {
		return nil, ErrNilState
	}

	s.RLock()
	defer s.RUnlock()

	for _, g := range s.Guilds {
		if g.ID == guildID {
			return g, nil
		}
	}

	return nil, errors.New("Guild not found.")
}

// TODO: Consider moving Guild state update methods onto *Guild.

// MemberAdd adds a member to the current world state, or
// updates it if it already exists.
func (s *State) MemberAdd(member *Member) error {
	if s == nil {
		return ErrNilState
	}

	guild, err := s.Guild(member.GuildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, m := range guild.Members {
		if m.User.ID == member.User.ID {
			guild.Members[i] = member
			return nil
		}
	}

	guild.Members = append(guild.Members, member)
	return nil
}

// MemberRemove removes a member from current world state.
func (s *State) MemberRemove(member *Member) error {
	if s == nil {
		return ErrNilState
	}

	guild, err := s.Guild(member.GuildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, m := range guild.Members {
		if m.User.ID == member.User.ID {
			guild.Members = append(guild.Members[:i], guild.Members[i+1:]...)
			return nil
		}
	}

	return errors.New("Member not found.")
}

// Member gets a member by ID from a guild.
func (s *State) Member(guildID, userID string) (*Member, error) {
	if s == nil {
		return nil, ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, m := range guild.Members {
		if m.User.ID == userID {
			return m, nil
		}
	}

	return nil, errors.New("Member not found.")
}

// ChannelAdd adds a guild to the current world state, or
// updates it if it already exists.
// Channels may exist either as PrivateChannels or inside
// a guild.
func (s *State) ChannelAdd(channel *Channel) error {
	if s == nil {
		return ErrNilState
	}

	if channel.IsPrivate {
		s.Lock()
		defer s.Unlock()

		// If the channel exists, replace it.
		for i, c := range s.PrivateChannels {
			if c.ID == channel.ID {
				// Don't stomp on messages.
				channel.Messages = c.Messages
				s.PrivateChannels[i] = channel
				return nil
			}
		}

		s.PrivateChannels = append(s.PrivateChannels, channel)
	} else {
		guild, err := s.Guild(channel.GuildID)
		if err != nil {
			return err
		}

		s.Lock()
		defer s.Unlock()

		// If the channel exists, replace it.
		for i, c := range guild.Channels {
			if c.ID == channel.ID {
				// Don't stomp on messages.
				channel.Messages = c.Messages
				guild.Channels[i] = channel
				return nil
			}
		}

		guild.Channels = append(guild.Channels, channel)
	}

	return nil
}

// ChannelRemove removes a channel from current world state.
func (s *State) ChannelRemove(channel *Channel) error {
	if s == nil {
		return ErrNilState
	}

	if channel.IsPrivate {
		s.Lock()
		defer s.Unlock()

		for i, c := range s.PrivateChannels {
			if c.ID == channel.ID {
				s.PrivateChannels = append(s.PrivateChannels[:i], s.PrivateChannels[i+1:]...)
				return nil
			}
		}
	} else {
		guild, err := s.Guild(channel.GuildID)
		if err != nil {
			return err
		}

		s.Lock()
		defer s.Unlock()

		for i, c := range guild.Channels {
			if c.ID == channel.ID {
				guild.Channels = append(guild.Channels[:i], guild.Channels[i+1:]...)
				return nil
			}
		}
	}

	return errors.New("Channel not found.")
}

// GuildChannel gets a channel by ID from a guild.
func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
	if s == nil {
		return nil, ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, c := range guild.Channels {
		if c.ID == channelID {
			return c, nil
		}
	}

	return nil, errors.New("Channel not found.")
}

// PrivateChannel gets a private channel by ID.
func (s *State) PrivateChannel(channelID string) (*Channel, error) {
	if s == nil {
		return nil, ErrNilState
	}

	s.RLock()
	defer s.RUnlock()

	for _, c := range s.PrivateChannels {
		if c.ID == channelID {
			return c, nil
		}
	}

	return nil, errors.New("Channel not found.")
}

// Channel gets a channel by ID, it will look in all guilds an private channels.
func (s *State) Channel(channelID string) (*Channel, error) {
	if s == nil {
		return nil, ErrNilState
	}

	c, err := s.PrivateChannel(channelID)
	if err == nil {
		return c, nil
	}

	for _, g := range s.Guilds {
		c, err := s.GuildChannel(g.ID, channelID)
		if err == nil {
			return c, nil
		}
	}

	return nil, errors.New("Channel not found.")
}

// Emoji returns an emoji for a guild and emoji id.
func (s *State) Emoji(guildID, emojiID string) (*Emoji, error) {
	if s == nil {
		return nil, ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, e := range guild.Emojis {
		if e.ID == emojiID {
			return e, nil
		}
	}

	return nil, errors.New("Emoji not found.")
}

// EmojiAdd adds an emoji to the current world state.
func (s *State) EmojiAdd(guildID string, emoji *Emoji) error {
	if s == nil {
		return ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, e := range guild.Emojis {
		if e.ID == emoji.ID {
			guild.Emojis[i] = emoji
			return nil
		}
	}

	guild.Emojis = append(guild.Emojis, emoji)
	return nil
}

// EmojisAdd adds multiple emojis to the world state.
func (s *State) EmojisAdd(guildID string, emojis []*Emoji) error {
	for _, e := range emojis {
		if err := s.EmojiAdd(guildID, e); err != nil {
			return err
		}
	}
	return nil
}

// MessageAdd adds a message to the current world state, or updates it if it exists.
// If the channel cannot be found, the message is discarded.
// Messages are kept in state up to s.MaxMessageCount
func (s *State) MessageAdd(message *Message) error {
	if s == nil {
		return ErrNilState
	}

	c, err := s.Channel(message.ChannelID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	// If the message exists, replace it.
	for i, m := range c.Messages {
		if m.ID == message.ID {
			c.Messages[i] = message
			return nil
		}
	}

	c.Messages = append(c.Messages, message)

	if len(c.Messages) > s.MaxMessageCount {
		s.Unlock()
		for len(c.Messages) > s.MaxMessageCount {
			err := s.MessageRemove(c.Messages[0])
			if err != nil {
				fmt.Println("message remove error: ", err)
			}
		}
		s.Lock()
	}
	return nil
}

// MessageRemove removes a message from the world state.
func (s *State) MessageRemove(message *Message) error {
	if s == nil {
		return ErrNilState
	}

	c, err := s.Channel(message.ChannelID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, m := range c.Messages {
		if m.ID == message.ID {
			c.Messages = append(c.Messages[:i], c.Messages[i+1:]...)
			return nil
		}
	}

	return errors.New("Message not found.")
}

func (s *State) VoiceStateUpdate(update *VoiceStateUpdate) error {
	var exists bool
	var guild *Guild

	for _, guild = range s.Guilds {
		if guild.ID == update.GuildID {
			exists = true
			break
		}
	}

	if !exists {
		return nil
	}

	// Handle Leaving Channel
	if update.ChannelID == "" {
		for i, state := range guild.VoiceStates {
			if state.UserID == update.UserID {
				guild.VoiceStates = append(guild.VoiceStates[:i], guild.VoiceStates[i+1:]...)
			}
		}
	} else {
		exists := false
		for _, state := range guild.VoiceStates {
			if state.UserID == update.UserID {
				state.ChannelID = update.ChannelID
				exists = true
			}
		}

		if !exists {
			guild.VoiceStates = append(guild.VoiceStates, update.VoiceState)
		}
	}

	return nil
}

// Message gets a message by channel and message ID.
func (s *State) Message(channelID, messageID string) (*Message, error) {
	if s == nil {
		return nil, ErrNilState
	}

	c, err := s.Channel(channelID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, m := range c.Messages {
		if m.ID == messageID {
			return m, nil
		}
	}

	return nil, errors.New("Message not found.")
}

// onInterface handles all events related to states.
func (s *State) onInterface(se *Session, i interface{}) (err error) {
	if s == nil {
		return ErrNilState
	}
	if !se.StateEnabled {
		return nil
	}

	switch t := i.(type) {
	case *Ready:
		err = s.OnReady(t)
	case *GuildCreate:
		err = s.GuildAdd(t.Guild)
	case *GuildUpdate:
		err = s.GuildAdd(t.Guild)
	case *GuildDelete:
		err = s.GuildRemove(t.Guild)
	case *GuildMemberAdd:
		err = s.MemberAdd(t.Member)
	case *GuildMemberUpdate:
		err = s.MemberAdd(t.Member)
	case *GuildMemberRemove:
		err = s.MemberRemove(t.Member)
	case *GuildEmojisUpdate:
		err = s.EmojisAdd(t.GuildID, t.Emojis)
	case *ChannelCreate:
		err = s.ChannelAdd(t.Channel)
	case *ChannelUpdate:
		err = s.ChannelAdd(t.Channel)
	case *ChannelDelete:
		err = s.ChannelRemove(t.Channel)
	case *MessageCreate:
		err = s.MessageAdd(t.Message)
	case *MessageUpdate:
		err = s.MessageAdd(t.Message)
	case *MessageDelete:
		err = s.MessageRemove(t.Message)
	case *VoiceStateUpdate:
		err = s.VoiceStateUpdate(t)
	}

	return
}
<commit_msg>Clean up voice state updates, make them goroutine safe.<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to state tracking.  If enabled, state
// tracking will capture the initial READY packet and many other websocket
// events and maintain an in-memory state of of guilds, channels, users, and
// so forth.  This information can be accessed through the Session.State struct.

package discordgo

import (
	"errors"
	"fmt"
)

// ErrNilState is returned when the state is nil.
var ErrNilState = errors.New("State not instantiated, please use discordgo.New() or assign Session.State.")

// NewState creates an empty state.
func NewState() *State {
	return &State{
		Ready: Ready{
			PrivateChannels: []*Channel{},
			Guilds:          []*Guild{},
		},
	}
}

// OnReady takes a Ready event and updates all internal state.
func (s *State) OnReady(r *Ready) error {
	if s == nil {
		return ErrNilState
	}

	s.Lock()
	defer s.Unlock()

	s.Ready = *r

	for _, g := range s.Guilds {
		for _, c := range g.Channels {
			c.GuildID = g.ID
		}
	}

	return nil
}

// GuildAdd adds a guild to the current world state, or
// updates it if it already exists.
func (s *State) GuildAdd(guild *Guild) error {
	if s == nil {
		return ErrNilState
	}

	s.Lock()
	defer s.Unlock()

	// If the guild exists, replace it.
	for i, g := range s.Guilds {
		if g.ID == guild.ID {
			// Don't stomp on properties that don't come in updates.
			guild.Members = g.Members
			guild.Presences = g.Presences
			guild.Channels = g.Channels
			guild.VoiceStates = g.VoiceStates
			s.Guilds[i] = guild
			return nil
		}
	}

	s.Guilds = append(s.Guilds, guild)
	return nil
}

// GuildRemove removes a guild from current world state.
func (s *State) GuildRemove(guild *Guild) error {
	if s == nil {
		return ErrNilState
	}

	s.Lock()
	defer s.Unlock()

	for i, g := range s.Guilds {
		if g.ID == guild.ID {
			s.Guilds = append(s.Guilds[:i], s.Guilds[i+1:]...)
			return nil
		}
	}

	return errors.New("Guild not found.")
}

// Guild gets a guild by ID.
// Useful for querying if @me is in a guild:
//     _, err := discordgo.Session.State.Guild(guildID)
//     isInGuild := err == nil
func (s *State) Guild(guildID string) (*Guild, error) {
	if s == nil {
		return nil, ErrNilState
	}

	s.RLock()
	defer s.RUnlock()

	for _, g := range s.Guilds {
		if g.ID == guildID {
			return g, nil
		}
	}

	return nil, errors.New("Guild not found.")
}

// TODO: Consider moving Guild state update methods onto *Guild.

// MemberAdd adds a member to the current world state, or
// updates it if it already exists.
func (s *State) MemberAdd(member *Member) error {
	if s == nil {
		return ErrNilState
	}

	guild, err := s.Guild(member.GuildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, m := range guild.Members {
		if m.User.ID == member.User.ID {
			guild.Members[i] = member
			return nil
		}
	}

	guild.Members = append(guild.Members, member)
	return nil
}

// MemberRemove removes a member from current world state.
func (s *State) MemberRemove(member *Member) error {
	if s == nil {
		return ErrNilState
	}

	guild, err := s.Guild(member.GuildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, m := range guild.Members {
		if m.User.ID == member.User.ID {
			guild.Members = append(guild.Members[:i], guild.Members[i+1:]...)
			return nil
		}
	}

	return errors.New("Member not found.")
}

// Member gets a member by ID from a guild.
func (s *State) Member(guildID, userID string) (*Member, error) {
	if s == nil {
		return nil, ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, m := range guild.Members {
		if m.User.ID == userID {
			return m, nil
		}
	}

	return nil, errors.New("Member not found.")
}

// ChannelAdd adds a guild to the current world state, or
// updates it if it already exists.
// Channels may exist either as PrivateChannels or inside
// a guild.
func (s *State) ChannelAdd(channel *Channel) error {
	if s == nil {
		return ErrNilState
	}

	if channel.IsPrivate {
		s.Lock()
		defer s.Unlock()

		// If the channel exists, replace it.
		for i, c := range s.PrivateChannels {
			if c.ID == channel.ID {
				// Don't stomp on messages.
				channel.Messages = c.Messages
				s.PrivateChannels[i] = channel
				return nil
			}
		}

		s.PrivateChannels = append(s.PrivateChannels, channel)
	} else {
		guild, err := s.Guild(channel.GuildID)
		if err != nil {
			return err
		}

		s.Lock()
		defer s.Unlock()

		// If the channel exists, replace it.
		for i, c := range guild.Channels {
			if c.ID == channel.ID {
				// Don't stomp on messages.
				channel.Messages = c.Messages
				guild.Channels[i] = channel
				return nil
			}
		}

		guild.Channels = append(guild.Channels, channel)
	}

	return nil
}

// ChannelRemove removes a channel from current world state.
func (s *State) ChannelRemove(channel *Channel) error {
	if s == nil {
		return ErrNilState
	}

	if channel.IsPrivate {
		s.Lock()
		defer s.Unlock()

		for i, c := range s.PrivateChannels {
			if c.ID == channel.ID {
				s.PrivateChannels = append(s.PrivateChannels[:i], s.PrivateChannels[i+1:]...)
				return nil
			}
		}
	} else {
		guild, err := s.Guild(channel.GuildID)
		if err != nil {
			return err
		}

		s.Lock()
		defer s.Unlock()

		for i, c := range guild.Channels {
			if c.ID == channel.ID {
				guild.Channels = append(guild.Channels[:i], guild.Channels[i+1:]...)
				return nil
			}
		}
	}

	return errors.New("Channel not found.")
}

// GuildChannel gets a channel by ID from a guild.
func (s *State) GuildChannel(guildID, channelID string) (*Channel, error) {
	if s == nil {
		return nil, ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, c := range guild.Channels {
		if c.ID == channelID {
			return c, nil
		}
	}

	return nil, errors.New("Channel not found.")
}

// PrivateChannel gets a private channel by ID.
func (s *State) PrivateChannel(channelID string) (*Channel, error) {
	if s == nil {
		return nil, ErrNilState
	}

	s.RLock()
	defer s.RUnlock()

	for _, c := range s.PrivateChannels {
		if c.ID == channelID {
			return c, nil
		}
	}

	return nil, errors.New("Channel not found.")
}

// Channel gets a channel by ID, it will look in all guilds an private channels.
func (s *State) Channel(channelID string) (*Channel, error) {
	if s == nil {
		return nil, ErrNilState
	}

	c, err := s.PrivateChannel(channelID)
	if err == nil {
		return c, nil
	}

	for _, g := range s.Guilds {
		c, err := s.GuildChannel(g.ID, channelID)
		if err == nil {
			return c, nil
		}
	}

	return nil, errors.New("Channel not found.")
}

// Emoji returns an emoji for a guild and emoji id.
func (s *State) Emoji(guildID, emojiID string) (*Emoji, error) {
	if s == nil {
		return nil, ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, e := range guild.Emojis {
		if e.ID == emojiID {
			return e, nil
		}
	}

	return nil, errors.New("Emoji not found.")
}

// EmojiAdd adds an emoji to the current world state.
func (s *State) EmojiAdd(guildID string, emoji *Emoji) error {
	if s == nil {
		return ErrNilState
	}

	guild, err := s.Guild(guildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, e := range guild.Emojis {
		if e.ID == emoji.ID {
			guild.Emojis[i] = emoji
			return nil
		}
	}

	guild.Emojis = append(guild.Emojis, emoji)
	return nil
}

// EmojisAdd adds multiple emojis to the world state.
func (s *State) EmojisAdd(guildID string, emojis []*Emoji) error {
	for _, e := range emojis {
		if err := s.EmojiAdd(guildID, e); err != nil {
			return err
		}
	}
	return nil
}

// MessageAdd adds a message to the current world state, or updates it if it exists.
// If the channel cannot be found, the message is discarded.
// Messages are kept in state up to s.MaxMessageCount
func (s *State) MessageAdd(message *Message) error {
	if s == nil {
		return ErrNilState
	}

	c, err := s.Channel(message.ChannelID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	// If the message exists, replace it.
	for i, m := range c.Messages {
		if m.ID == message.ID {
			c.Messages[i] = message
			return nil
		}
	}

	c.Messages = append(c.Messages, message)

	if len(c.Messages) > s.MaxMessageCount {
		s.Unlock()
		for len(c.Messages) > s.MaxMessageCount {
			err := s.MessageRemove(c.Messages[0])
			if err != nil {
				fmt.Println("message remove error: ", err)
			}
		}
		s.Lock()
	}
	return nil
}

// MessageRemove removes a message from the world state.
func (s *State) MessageRemove(message *Message) error {
	if s == nil {
		return ErrNilState
	}

	c, err := s.Channel(message.ChannelID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	for i, m := range c.Messages {
		if m.ID == message.ID {
			c.Messages = append(c.Messages[:i], c.Messages[i+1:]...)
			return nil
		}
	}

	return errors.New("Message not found.")
}

func (s *State) voiceStateUpdate(update *VoiceStateUpdate) error {
	guild, err := s.Guild(update.GuildID)
	if err != nil {
		return err
	}

	s.Lock()
	defer s.Unlock()

	// Handle Leaving Channel
	if update.ChannelID == "" {
		for i, state := range guild.VoiceStates {
			if state.UserID == update.UserID {
				guild.VoiceStates = append(guild.VoiceStates[:i], guild.VoiceStates[i+1:]...)
				return nil
			}
		}
	} else {
		for i, state := range guild.VoiceStates {
			if state.UserID == update.UserID {
				guild.VoiceStates[i] = update.VoiceState
				return nil
			}
		}

		guild.VoiceStates = append(guild.VoiceStates, update.VoiceState)
	}

	return nil
}

// Message gets a message by channel and message ID.
func (s *State) Message(channelID, messageID string) (*Message, error) {
	if s == nil {
		return nil, ErrNilState
	}

	c, err := s.Channel(channelID)
	if err != nil {
		return nil, err
	}

	s.RLock()
	defer s.RUnlock()

	for _, m := range c.Messages {
		if m.ID == messageID {
			return m, nil
		}
	}

	return nil, errors.New("Message not found.")
}

// onInterface handles all events related to states.
func (s *State) onInterface(se *Session, i interface{}) (err error) {
	if s == nil {
		return ErrNilState
	}
	if !se.StateEnabled {
		return nil
	}

	switch t := i.(type) {
	case *Ready:
		err = s.OnReady(t)
	case *GuildCreate:
		err = s.GuildAdd(t.Guild)
	case *GuildUpdate:
		err = s.GuildAdd(t.Guild)
	case *GuildDelete:
		err = s.GuildRemove(t.Guild)
	case *GuildMemberAdd:
		err = s.MemberAdd(t.Member)
	case *GuildMemberUpdate:
		err = s.MemberAdd(t.Member)
	case *GuildMemberRemove:
		err = s.MemberRemove(t.Member)
	case *GuildEmojisUpdate:
		err = s.EmojisAdd(t.GuildID, t.Emojis)
	case *ChannelCreate:
		err = s.ChannelAdd(t.Channel)
	case *ChannelUpdate:
		err = s.ChannelAdd(t.Channel)
	case *ChannelDelete:
		err = s.ChannelRemove(t.Channel)
	case *MessageCreate:
		err = s.MessageAdd(t.Message)
	case *MessageUpdate:
		err = s.MessageAdd(t.Message)
	case *MessageDelete:
		err = s.MessageRemove(t.Message)
	case *VoiceStateUpdate:
		err = s.voiceStateUpdate(t)
	}

	return
}
<|endoftext|>