<commit_before>// Copyright © 2013 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 hugolib

import (
	"bytes"
	"fmt"
	"github.com/spf13/hugo/template/bundle"
	"html/template"
	"strings"
	"unicode"
)

var _ = fmt.Println

type ShortcodeFunc func([]string) string

type Shortcode struct {
	Name string
	Func ShortcodeFunc
}

type ShortcodeWithPage struct {
	Params interface{}
	Inner  template.HTML
	Page   *Page
}

type Shortcodes map[string]ShortcodeFunc

func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string {
	leadStart := strings.Index(stringToParse, `{{%`)
	if leadStart >= 0 {
		leadEnd := strings.Index(stringToParse[leadStart:], `%}}`) + leadStart
		if leadEnd > leadStart {
			name, par := SplitParams(stringToParse[leadStart+3 : leadEnd])
			tmpl := GetTemplate(name, t)
			if tmpl == nil {
				return stringToParse
			}
			params := Tokenize(par)
			// Always look for closing tag.
			endStart, endEnd := FindEnd(stringToParse[leadEnd:], name)
			var data = &ShortcodeWithPage{Params: params, Page: p}
			if endStart > 0 {
				s := stringToParse[leadEnd+3 : leadEnd+endStart]
				data.Inner = template.HTML(CleanP(ShortcodesHandle(s, p, t)))
				remainder := CleanP(stringToParse[leadEnd+endEnd:])

				return CleanP(stringToParse[:leadStart]) +
					ShortcodeRender(tmpl, data) +
					CleanP(ShortcodesHandle(remainder, p, t))
			}
			return CleanP(stringToParse[:leadStart]) +
				ShortcodeRender(tmpl, data) +
				CleanP(ShortcodesHandle(stringToParse[leadEnd+3:], p,
					t))
		}
	}
	return stringToParse
}

// Clean up odd behavior when closing tag is on first line
// or opening tag is on the last line due to extra line in markdown file
func CleanP(str string) string {
	if strings.HasSuffix(strings.TrimSpace(str), "
") {
		idx := strings.LastIndex(str, "
")
		str = str[:idx]
	}

	if strings.HasPrefix(strings.TrimSpace(str), "
") {
		str = str[strings.Index(str, "
")+5:]
	}

	return str
}

func FindEnd(str string, name string) (int, int) {
	var endPos int
	var startPos int
	var try []string

	try = append(try, "{{% /"+name+" %}}")
	try = append(try, "{{% /"+name+"%}}")
	try = append(try, "{{%/"+name+"%}}")
	try = append(try, "{{%/"+name+" %}}")

	lowest := len(str)
	for _, x := range try {
		start := strings.Index(str, x)
		if start < lowest && start > 0 {
			startPos = start
			endPos = startPos + len(x)
		}
	}

	return startPos, endPos
}

func GetTemplate(name string, t bundle.Template) *template.Template {
	if x := t.Lookup("shortcodes/" + name + ".html"); x != nil {
		return x
	}
	return t.Lookup("_internal/shortcodes/" + name + ".html")
}

func StripShortcodes(stringToParse string) string {
	posStart := strings.Index(stringToParse, "{{%")
	if posStart > 0 {
		posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart
		if posEnd > posStart {
			newString := stringToParse[:posStart] + StripShortcodes(stringToParse[posEnd+3:])
			return newString
		}
	}
	return stringToParse
}

func Tokenize(in string) interface{} {
	first := strings.Fields(in)
	var final = make([]string, 0)

	// if don't need to parse, don't parse.
	if strings.Index(in, " ") < 0 && strings.Index(in, "=") < 1 {
		return append(final, in)
	}

	var keys = make([]string, 0)
	inQuote := false
	start := 0

	for i, v := range first {
		index := strings.Index(v, "=")

		if !inQuote {
			if index > 1 {
				keys = append(keys, v[:index])
				v = v[index+1:]
			}
		}

		// Adjusted to handle htmlencoded and non htmlencoded input
		if !strings.HasPrefix(v, "“") && !strings.HasPrefix(v, "\"") && !inQuote {
			final = append(final, v)
		} else if inQuote && (strings.HasSuffix(v, "”") ||
			strings.HasSuffix(v, "\"")) && !strings.HasSuffix(v, "\\\"") {
			if strings.HasSuffix(v, "\"") {
				first[i] = v[:len(v)-1]
			} else {
				first[i] = v[:len(v)-7]
			}
			final = append(final, strings.Join(first[start:i+1], " "))
			inQuote = false
		} else if (strings.HasPrefix(v, "“") ||
			strings.HasPrefix(v, "\"")) && !inQuote {
			if strings.HasSuffix(v, "”") || strings.HasSuffix(v,
				"\"") {
				if strings.HasSuffix(v, "\"") {
					if len(v) > 1 {
						final = append(final, v[1:len(v)-1])
					} else {
						final = append(final, "")
					}
				} else {
					final = append(final, v[7:len(v)-7])
				}
			} else {
				start = i
				if strings.HasPrefix(v, "\"") {
					first[i] = v[1:]
				} else {
					first[i] = v[7:]
				}
				inQuote = true
			}
		}

		// No closing "... just make remainder the final token
		if inQuote && i == len(first) {
			final = append(final, first[start:]...)
		}
	}

	if len(keys) > 0 && (len(keys) != len(final)) {
		panic("keys and final different lengths")
	}

	if len(keys) > 0 {
		var m = make(map[string]string)
		for i, k := range keys {
			m[k] = final[i]
		}

		return m
	}

	return final
}

func SplitParams(in string) (name string, par2 string) {
	i := strings.IndexFunc(strings.TrimSpace(in), unicode.IsSpace)
	if i < 1 {
		return strings.TrimSpace(in), ""
	}

	return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:])
}

func ShortcodeRender(tmpl *template.Template, data *ShortcodeWithPage) string {
	buffer := new(bytes.Buffer)
	err := tmpl.Execute(buffer, data)
	if err != nil {
		fmt.Println("error processing shortcode", tmpl.Name(), "\n ERR:", err)
	}
	return buffer.String()
}
<commit_msg>Warn about bad shortcode parameters (and don't crash)<commit_after>// Copyright © 2013 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 hugolib

import (
	"bytes"
	"fmt"
	"github.com/spf13/hugo/template/bundle"
	"html/template"
	"strings"
	"unicode"
)

var _ = fmt.Println

type ShortcodeFunc func([]string) string

type Shortcode struct {
	Name string
	Func ShortcodeFunc
}

type ShortcodeWithPage struct {
	Params interface{}
	Inner  template.HTML
	Page   *Page
}

type Shortcodes map[string]ShortcodeFunc

func ShortcodesHandle(stringToParse string, p *Page, t bundle.Template) string {
	leadStart := strings.Index(stringToParse, `{{%`)
	if leadStart >= 0 {
		leadEnd := strings.Index(stringToParse[leadStart:], `%}}`) + leadStart
		if leadEnd > leadStart {
			name, par := SplitParams(stringToParse[leadStart+3 : leadEnd])
			tmpl := GetTemplate(name, t)
			if tmpl == nil {
				return stringToParse
			}
			params := Tokenize(par)
			// Always look for closing tag.
			endStart, endEnd := FindEnd(stringToParse[leadEnd:], name)
			var data = &ShortcodeWithPage{Params: params, Page: p}
			if endStart > 0 {
				s := stringToParse[leadEnd+3 : leadEnd+endStart]
				data.Inner = template.HTML(CleanP(ShortcodesHandle(s, p, t)))
				remainder := CleanP(stringToParse[leadEnd+endEnd:])

				return CleanP(stringToParse[:leadStart]) +
					ShortcodeRender(tmpl, data) +
					CleanP(ShortcodesHandle(remainder, p, t))
			}
			return CleanP(stringToParse[:leadStart]) +
				ShortcodeRender(tmpl, data) +
				CleanP(ShortcodesHandle(stringToParse[leadEnd+3:], p,
					t))
		}
	}
	return stringToParse
}

// Clean up odd behavior when closing tag is on first line
// or opening tag is on the last line due to extra line in markdown file
func CleanP(str string) string {
	if strings.HasSuffix(strings.TrimSpace(str), "
") {
		idx := strings.LastIndex(str, "
")
		str = str[:idx]
	}

	if strings.HasPrefix(strings.TrimSpace(str), "
") {
		str = str[strings.Index(str, "
")+5:]
	}

	return str
}

func FindEnd(str string, name string) (int, int) {
	var endPos int
	var startPos int
	var try []string

	try = append(try, "{{% /"+name+" %}}")
	try = append(try, "{{% /"+name+"%}}")
	try = append(try, "{{%/"+name+"%}}")
	try = append(try, "{{%/"+name+" %}}")

	lowest := len(str)
	for _, x := range try {
		start := strings.Index(str, x)
		if start < lowest && start > 0 {
			startPos = start
			endPos = startPos + len(x)
		}
	}

	return startPos, endPos
}

func GetTemplate(name string, t bundle.Template) *template.Template {
	if x := t.Lookup("shortcodes/" + name + ".html"); x != nil {
		return x
	}
	return t.Lookup("_internal/shortcodes/" + name + ".html")
}

func StripShortcodes(stringToParse string) string {
	posStart := strings.Index(stringToParse, "{{%")
	if posStart > 0 {
		posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart
		if posEnd > posStart {
			newString := stringToParse[:posStart] + StripShortcodes(stringToParse[posEnd+3:])
			return newString
		}
	}
	return stringToParse
}

func Tokenize(in string) interface{} {
	first := strings.Fields(in)
	var final = make([]string, 0)

	// if don't need to parse, don't parse.
	if strings.Index(in, " ") < 0 && strings.Index(in, "=") < 1 {
		return append(final, in)
	}

	var keys = make([]string, 0)
	inQuote := false
	start := 0

	for i, v := range first {
		index := strings.Index(v, "=")

		if index < 0 {
			fmt.Printf("Shortcode parameters must be key=value pairs (no spaces) (saw '%s')\n", v)
			continue
		}

		if !inQuote {
			if index > 1 {
				keys = append(keys, v[:index])
				v = v[index+1:]
			}
		}

		// Adjusted to handle htmlencoded and non htmlencoded input
		if !strings.HasPrefix(v, "“") && !strings.HasPrefix(v, "\"") && !inQuote {
			final = append(final, v)
		} else if inQuote && (strings.HasSuffix(v, "”") ||
			strings.HasSuffix(v, "\"")) && !strings.HasSuffix(v, "\\\"") {
			if strings.HasSuffix(v, "\"") {
				first[i] = v[:len(v)-1]
			} else {
				first[i] = v[:len(v)-7]
			}
			final = append(final, strings.Join(first[start:i+1], " "))
			inQuote = false
		} else if (strings.HasPrefix(v, "“") ||
			strings.HasPrefix(v, "\"")) && !inQuote {
			if strings.HasSuffix(v, "”") || strings.HasSuffix(v,
				"\"") {
				if strings.HasSuffix(v, "\"") {
					if len(v) > 1 {
						final = append(final, v[1:len(v)-1])
					} else {
						final = append(final, "")
					}
				} else {
					final = append(final, v[7:len(v)-7])
				}
			} else {
				start = i
				if strings.HasPrefix(v, "\"") {
					first[i] = v[1:]
				} else {
					first[i] = v[7:]
				}
				inQuote = true
			}
		}

		// No closing "... just make remainder the final token
		if inQuote && i == len(first) {
			final = append(final, first[start:]...)
		}
	}

	if len(keys) > 0 && (len(keys) != len(final)) {
		panic("keys and final different lengths")
	}

	if len(keys) > 0 {
		var m = make(map[string]string)
		for i, k := range keys {
			m[k] = final[i]
		}

		return m
	}

	return final
}

func SplitParams(in string) (name string, par2 string) {
	i := strings.IndexFunc(strings.TrimSpace(in), unicode.IsSpace)
	if i < 1 {
		return strings.TrimSpace(in), ""
	}

	return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:])
}

func ShortcodeRender(tmpl *template.Template, data *ShortcodeWithPage) string {
	buffer := new(bytes.Buffer)
	err := tmpl.Execute(buffer, data)
	if err != nil {
		fmt.Println("error processing shortcode", tmpl.Name(), "\n ERR:", err)
	}
	return buffer.String()
}
<|endoftext|>


<commit_before>package weixinmp

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

type accessToken struct {
	appid  string
	secret string
}

func (this *accessToken) extract() (string, error) {
	fi, err := os.Stat(accessTokenTemp)
	if err != nil && !os.IsExist(err) {
		if token, err := this.fetch(); err != nil {
			return "", err
		} else {
			if err := this.store(token); err != nil {
				return "", err
			}
			return token, nil
		}
	} else {
		expires := fi.ModTime().Unix() + 7200
		if expires <= time.Now().Unix() {
			if token, err := this.fetch(); err != nil {
				return "", err
			} else {
				if err := this.store(token); err != nil {
					return "", err
				}
				return token, nil
			}
		}
	}
	temp, err := os.OpenFile(accessTokenTemp, os.O_RDONLY, os.ModeTemporary)
	defer temp.Close()
	if err != nil {
		return "", err
	}
	raw, err := ioutil.ReadAll(temp)
	if err != nil {
		return "", err
	}
	return string(raw), nil
}

func (this *accessToken) fetch() (string, error) {
	qs := fmt.Sprintf(
		"?grant_type=client_credential&appid=%s&secret=%s",
		this.appid,
		this.secret,
	)
	url := plainPreUrl + "token" + qs
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	raw, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	var rtn struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int64  `json:"expires_in"`
		ErrCode     int64  `json:"errcode"`
		ErrMsg      string `json:"errmsg"`
	}
	if err := json.Unmarshal(raw, &rtn); err != nil {
		return "", err
	}
	if rtn.ErrCode != 0 {
		return "", errors.New(fmt.Sprintf("%d %s", rtn.ErrCode, rtn.ErrMsg))
	}
	return rtn.AccessToken, nil
}

func (this *accessToken) store(token string) error {
	temp, err := os.OpenFile(accessTokenTemp, os.O_WRONLY|os.O_CREATE, os.ModeTemporary)
	defer temp.Close()
	if err != nil {
		return err
	}
	if _, err := temp.Write([]byte(token)); err != nil {
		return err
	}
	return nil
}
<commit_msg>improve access_token extract method<commit_after>package weixinmp

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

type accessToken struct {
	appid  string
	secret string
}

func (this *accessToken) extract() (string, error) {
	fi, err := os.Stat(accessTokenTemp)
	if err != nil && !os.IsExist(err) {
		return this.fetchAndStore()
	}
	expires := fi.ModTime().Unix() + 7200
	if expires <= time.Now().Unix() {
		return this.fetchAndStore()
	}
	temp, err := os.OpenFile(accessTokenTemp, os.O_RDONLY, os.ModeTemporary)
	defer temp.Close()
	if err != nil {
		return "", err
	}
	raw, err := ioutil.ReadAll(temp)
	if err != nil {
		return "", err
	}
	return string(raw), nil
}

func (this *accessToken) fetchAndStore() (string, error) {
	token, err := this.fetch()
	if err != nil {
		return "", err
	}
	if err := this.store(token); err != nil {
		return "", err
	}
	return token, nil
}

func (this *accessToken) fetch() (string, error) {
	qs := fmt.Sprintf(
		"?grant_type=client_credential&appid=%s&secret=%s",
		this.appid,
		this.secret,
	)
	url := plainPreUrl + "token" + qs
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	raw, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	var rtn struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int64  `json:"expires_in"`
		ErrCode     int64  `json:"errcode"`
		ErrMsg      string `json:"errmsg"`
	}
	if err := json.Unmarshal(raw, &rtn); err != nil {
		return "", err
	}
	if rtn.ErrCode != 0 {
		return "", errors.New(fmt.Sprintf("%d %s", rtn.ErrCode, rtn.ErrMsg))
	}
	return rtn.AccessToken, nil
}

func (this *accessToken) store(token string) error {
	temp, err := os.OpenFile(accessTokenTemp, os.O_WRONLY|os.O_CREATE, os.ModeTemporary)
	defer temp.Close()
	if err != nil {
		return err
	}
	if _, err := temp.Write([]byte(token)); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package fosite

import (
	"net/http"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// Implements
// * https://tools.ietf.org/html/rfc6749#section-2.3.1
//   Clients in possession of a client password MAY use the HTTP Basic
//   authentication scheme as defined in [RFC2617] to authenticate with
//   the authorization server.  The client identifier is encoded using the
//   "application/x-www-form-urlencoded" encoding algorithm per
//   Appendix B, and the encoded value is used as the username; the client
//   password is encoded using the same algorithm and used as the
//   password.  The authorization server MUST support the HTTP Basic
//   authentication scheme for authenticating clients that were issued a
//   client password.
//   Including the client credentials in the request-body using the two
//   parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
//   to directly utilize the HTTP Basic authentication scheme (or other
//   password-based HTTP authentication schemes).  The parameters can only
//   be transmitted in the request-body and MUST NOT be included in the
//   request URI.
//   * https://tools.ietf.org/html/rfc6749#section-3.2.1
//   - Confidential clients or other clients issued client credentials MUST
//   authenticate with the authorization server as described in
//   Section 2.3 when making requests to the token endpoint.
//   - If the client type is confidential or the client was issued client
//   credentials (or assigned other authentication requirements), the
//   client MUST authenticate with the authorization server as described
//   in Section 3.2.1.
func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session interface{}) (AccessRequester, error) {
	accessRequest := NewAccessRequest(session)

	if r.Method != "POST" {
		return accessRequest, errors.Wrap(ErrInvalidRequest, "HTTP method is not POST")
	} else if err := r.ParseForm(); err != nil {
		return accessRequest, errors.Wrap(ErrInvalidRequest, err.Error())
	}

	accessRequest.Form = r.PostForm
	if session == nil {
		return accessRequest, errors.New("Session must not be nil")
	}

	accessRequest.Scopes = removeEmpty(strings.Split(r.Form.Get("scope"), " "))
	accessRequest.GrantTypes = removeEmpty(strings.Split(r.Form.Get("grant_type"), " "))
	if len(accessRequest.GrantTypes) < 1 {
		return accessRequest, errors.Wrap(ErrInvalidRequest, "No grant type given")
	}

	clientID, clientSecret, ok := r.BasicAuth()
	if !ok {
		return accessRequest, errors.Wrap(ErrInvalidRequest, "HTTP Authorization header missing or invalid")
	}

	client, err := f.Store.GetClient(clientID)
	if err != nil {
		return accessRequest, errors.Wrap(ErrInvalidClient, err.Error())
	}

	// Enforce client authentication
	if err := f.Hasher.Compare(client.GetHashedSecret(), []byte(clientSecret)); err != nil {
		return accessRequest, errors.Wrap(ErrInvalidClient, err.Error())
	}
	accessRequest.Client = client

	var found bool = false
	for _, loader := range f.TokenEndpointHandlers {
		if err := loader.HandleTokenEndpointRequest(ctx, r, accessRequest); err == nil {
			found = true
		} else if errors.Cause(err) == ErrUnknownRequest {
			// do nothing
		} else if err != nil {
			return accessRequest, err
		}
	}

	if !found {
		return nil, errors.Wrap(ErrInvalidRequest, "")
	}

	if !accessRequest.GetScopes().Has(f.GetMandatoryScope()) {
		return accessRequest, errors.Wrap(ErrInvalidScope, "")
	}

	accessRequest.GrantScope(f.GetMandatoryScope())
	return accessRequest, nil
}
<commit_msg>access: resolve an issue where query params could be used instead of post body<commit_after>package fosite

import (
	"net/http"
	"strings"

	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// Implements
// * https://tools.ietf.org/html/rfc6749#section-2.3.1
//   Clients in possession of a client password MAY use the HTTP Basic
//   authentication scheme as defined in [RFC2617] to authenticate with
//   the authorization server.  The client identifier is encoded using the
//   "application/x-www-form-urlencoded" encoding algorithm per
//   Appendix B, and the encoded value is used as the username; the client
//   password is encoded using the same algorithm and used as the
//   password.  The authorization server MUST support the HTTP Basic
//   authentication scheme for authenticating clients that were issued a
//   client password.
//   Including the client credentials in the request-body using the two
//   parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
//   to directly utilize the HTTP Basic authentication scheme (or other
//   password-based HTTP authentication schemes).  The parameters can only
//   be transmitted in the request-body and MUST NOT be included in the
//   request URI.
//   * https://tools.ietf.org/html/rfc6749#section-3.2.1
//   - Confidential clients or other clients issued client credentials MUST
//   authenticate with the authorization server as described in
//   Section 2.3 when making requests to the token endpoint.
//   - If the client type is confidential or the client was issued client
//   credentials (or assigned other authentication requirements), the
//   client MUST authenticate with the authorization server as described
//   in Section 3.2.1.
func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session interface{}) (AccessRequester, error) {
	accessRequest := NewAccessRequest(session)

	if r.Method != "POST" {
		return accessRequest, errors.Wrap(ErrInvalidRequest, "HTTP method is not POST")
	} else if err := r.ParseForm(); err != nil {
		return accessRequest, errors.Wrap(ErrInvalidRequest, err.Error())
	}

	accessRequest.Form = r.PostForm
	if session == nil {
		return accessRequest, errors.New("Session must not be nil")
	}

	accessRequest.Scopes = removeEmpty(strings.Split(r.PostForm.Get("scope"), " "))
	accessRequest.GrantTypes = removeEmpty(strings.Split(r.PostForm.Get("grant_type"), " "))
	if len(accessRequest.GrantTypes) < 1 {
		return accessRequest, errors.Wrap(ErrInvalidRequest, "No grant type given")
	}

	clientID, clientSecret, ok := r.BasicAuth()
	if !ok {
		return accessRequest, errors.Wrap(ErrInvalidRequest, "HTTP Authorization header missing or invalid")
	}

	client, err := f.Store.GetClient(clientID)
	if err != nil {
		return accessRequest, errors.Wrap(ErrInvalidClient, err.Error())
	}

	// Enforce client authentication
	if err := f.Hasher.Compare(client.GetHashedSecret(), []byte(clientSecret)); err != nil {
		return accessRequest, errors.Wrap(ErrInvalidClient, err.Error())
	}
	accessRequest.Client = client

	var found bool = false
	for _, loader := range f.TokenEndpointHandlers {
		if err := loader.HandleTokenEndpointRequest(ctx, r, accessRequest); err == nil {
			found = true
		} else if errors.Cause(err) == ErrUnknownRequest {
			// do nothing
		} else if err != nil {
			return accessRequest, err
		}
	}

	if !found {
		return nil, errors.Wrap(ErrInvalidRequest, "")
	}

	if !accessRequest.GetScopes().Has(f.GetMandatoryScope()) {
		return accessRequest, errors.Wrap(ErrInvalidScope, "")
	}

	accessRequest.GrantScope(f.GetMandatoryScope())
	return accessRequest, nil
}
<|endoftext|>


<commit_before>package actor

import (
	"strconv"
	"sync"
	"sync/atomic"
)

type ProcessRegistryValue struct {
	Host           string
	LocalPids      map[string]ActorRef //maybe this should be replaced with something lockfree like ctrie instead
	RemoteHandlers []HostResolver
	SequenceID     uint64
	rw             sync.RWMutex
}

var (
	ProcessRegistry = &ProcessRegistryValue{
		Host:           "nonhost",
		LocalPids:      make(map[string]ActorRef),
		RemoteHandlers: make([]HostResolver, 0),
	}
)

type HostResolver func(*PID) (ActorRef, bool)

func (pr *ProcessRegistryValue) RegisterHostResolver(handler HostResolver) {
	pr.RemoteHandlers = append(pr.RemoteHandlers, handler)
}

func (pr *ProcessRegistryValue) getAutoId() string {
	id := strconv.FormatUint(atomic.AddUint64(&pr.SequenceID, 1), 16)
	return id
}

func (pr *ProcessRegistryValue) registerPID(actorRef ActorRef, id string) (*PID, bool) {

	pid := PID{
		Host: pr.Host,
		Id:   id,
	}

	pr.rw.Lock()
	_, found := pr.LocalPids[pid.Id]
	if found {
		pr.rw.Unlock()
		return &pid, false
	}
	pr.LocalPids[pid.Id] = actorRef
	pr.rw.Unlock()
	return &pid, true
}

func (pr *ProcessRegistryValue) unregisterPID(pid *PID) {
	pr.rw.Lock()
	delete(pr.LocalPids, pid.Id)
	pr.rw.Unlock()
}

func (pr *ProcessRegistryValue) fromPID(pid *PID) (ActorRef, bool) {
	if pid.Host != "nonhost" && pid.Host != pr.Host {
		for _, handler := range pr.RemoteHandlers {
			ref, ok := handler(pid)
			if ok {
				return ref, true
			}
		}
		//panic("Unknown host or node")
		return deadLetter, false
	}
	pr.rw.RLock()
	ref, ok := pr.LocalPids[pid.Id]
	if !ok {
		//panic("Unknown PID")
		pr.rw.RUnlock()
		return deadLetter, false
	}
	pr.rw.RUnlock()
	return ref, true
}
<commit_msg>concurrent process registry<commit_after>package actor

import (
	"strconv"
	"sync/atomic"

	cmap "github.com/orcaman/concurrent-map"
)

type ProcessRegistryValue struct {
	Host           string
	LocalPids      cmap.ConcurrentMap
	RemoteHandlers []HostResolver
	SequenceID     uint64
}

var (
	ProcessRegistry = &ProcessRegistryValue{
		Host:           "nonhost",
		LocalPids:      cmap.New(),
		RemoteHandlers: make([]HostResolver, 0),
	}
)

type HostResolver func(*PID) (ActorRef, bool)

func (pr *ProcessRegistryValue) RegisterHostResolver(handler HostResolver) {
	pr.RemoteHandlers = append(pr.RemoteHandlers, handler)

}

func (pr *ProcessRegistryValue) getAutoId() string {
	id := strconv.FormatUint(atomic.AddUint64(&pr.SequenceID, 1), 16)
	return id
}

func (pr *ProcessRegistryValue) registerPID(actorRef ActorRef, id string) (*PID, bool) {

	pid := PID{
		Host: pr.Host,
		Id:   id,
	}

	_, found := pr.LocalPids.Get(pid.Id)
	if found {
		return &pid, false
	}
	pr.LocalPids.Set(pid.Id, actorRef)
	return &pid, true
}

func (pr *ProcessRegistryValue) unregisterPID(pid *PID) {
	pr.LocalPids.Remove(pid.Id)
}

func (pr *ProcessRegistryValue) fromPID(pid *PID) (ActorRef, bool) {
	if pid.Host != "nonhost" && pid.Host != pr.Host {
		for _, handler := range pr.RemoteHandlers {
			ref, ok := handler(pid)
			if ok {
				return ref, true
			}
		}
		//panic("Unknown host or node")
		return deadLetter, false
	}
	ref, ok := pr.LocalPids.Get(pid.Id)
	if !ok {
		//panic("Unknown PID")
		return deadLetter, false
	}
	return ref.(ActorRef), true
}
<|endoftext|>


<commit_before>// The /v1/operator/area endpoints are available only in Consul Enterprise and
// interact with its network area subsystem. Network areas are used to link
// together Consul servers in different Consul datacenters. With network areas,
// Consul datacenters can be linked together in ways other than a fully-connected
// mesh, as is required for Consul's WAN.
package api

import (
	"net"
	"time"
)

// Area defines a network area.
type Area struct {
	// ID is this identifier for an area (a UUID). This must be left empty
	// when creating a new area.
	ID string

	// PeerDatacenter is the peer Consul datacenter that will make up the
	// other side of this network area. Network areas always involve a pair
	// of datacenters: the datacenter where the area was created, and the
	// peer datacenter. This is required.
	PeerDatacenter string

	// RetryJoin specifies the address of Consul servers to join to, such as
	// an IPs or hostnames with an optional port number. This is optional.
	RetryJoin []string

	// UseTLS specifies whether gossip over this area should be encrypted with TLS
	// if possible.
	UseTLS bool
}

// AreaJoinResponse is returned when a join occurs and gives the result for each
// address.
type AreaJoinResponse struct {
	// The address that was joined.
	Address string

	// Whether or not the join was a success.
	Joined bool

	// If we couldn't join, this is the message with information.
	Error string
}

// SerfMember is a generic structure for reporting information about members in
// a Serf cluster. This is only used by the area endpoints right now, but this
// could be expanded to other endpoints in the future.
type SerfMember struct {
	// ID is the node identifier (a UUID).
	ID string

	// Name is the node name.
	Name string

	// Addr has the IP address.
	Addr net.IP

	// Port is the RPC port.
	Port uint16

	// Datacenter is the DC name.
	Datacenter string

	// Role is "client", "server", or "unknown".
	Role string

	// Build has the version of the Consul agent.
	Build string

	// Protocol is the protocol of the Consul agent.
	Protocol int

	// Status is the Serf health status "none", "alive", "leaving", "left",
	// or "failed".
	Status string

	// RTT is the estimated round trip time from the server handling the
	// request to the this member. This will be negative if no RTT estimate
	// is available.
	RTT time.Duration
}

// AreaCreate will create a new network area. The ID in the given structure must
// be empty and a generated ID will be returned on success.
func (op *Operator) AreaCreate(area *Area, q *WriteOptions) (string, *WriteMeta, error) {
	r := op.c.newRequest("POST", "/v1/operator/area")
	r.setWriteOptions(q)
	r.obj = area
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return "", nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt

	var out struct{ ID string }
	if err := decodeBody(resp, &out); err != nil {
		return "", nil, err
	}
	return out.ID, wm, nil
}

// AreaUpdate will update the configuration of the network area with the given ID.
func (op *Operator) AreaUpdate(areaID string, area *Area, q *WriteOptions) (string, *WriteMeta, error) {
	r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID)
	r.setWriteOptions(q)
	r.obj = area
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return "", nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt

	var out struct{ ID string }
	if err := decodeBody(resp, &out); err != nil {
		return "", nil, err
	}
	return out.ID, wm, nil
}

// AreaGet returns a single network area.
func (op *Operator) AreaGet(areaID string, q *QueryOptions) ([]*Area, *QueryMeta, error) {
	var out []*Area
	qm, err := op.c.query("/v1/operator/area/"+areaID, &out, q)
	if err != nil {
		return nil, nil, err
	}
	return out, qm, nil
}

// AreaList returns all the available network areas.
func (op *Operator) AreaList(q *QueryOptions) ([]*Area, *QueryMeta, error) {
	var out []*Area
	qm, err := op.c.query("/v1/operator/area", &out, q)
	if err != nil {
		return nil, nil, err
	}
	return out, qm, nil
}

// AreaDelete deletes the given network area.
func (op *Operator) AreaDelete(areaID string, q *WriteOptions) (*WriteMeta, error) {
	r := op.c.newRequest("DELETE", "/v1/operator/area/"+areaID)
	r.setWriteOptions(q)
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt
	return wm, nil
}

// AreaJoin attempts to join the given set of join addresses to the given
// network area. See the Area structure for details about join addresses.
func (op *Operator) AreaJoin(areaID string, addresses []string, q *WriteOptions) ([]*AreaJoinResponse, *WriteMeta, error) {
	r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID+"/join")
	r.setWriteOptions(q)
	r.obj = addresses
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt

	var out []*AreaJoinResponse
	if err := decodeBody(resp, &out); err != nil {
		return nil, nil, err
	}
	return out, wm, nil
}

// AreaMembers lists the Serf information about the members in the given area.
func (op *Operator) AreaMembers(areaID string, q *QueryOptions) ([]*SerfMember, *QueryMeta, error) {
	var out []*SerfMember
	qm, err := op.c.query("/v1/operator/area/"+areaID+"/members", &out, q)
	if err != nil {
		return nil, nil, err
	}
	return out, qm, nil
}
<commit_msg>Remove operator_area note from godoc overview (#4603)<commit_after>package api

// The /v1/operator/area endpoints are available only in Consul Enterprise and
// interact with its network area subsystem. Network areas are used to link
// together Consul servers in different Consul datacenters. With network areas,
// Consul datacenters can be linked together in ways other than a fully-connected
// mesh, as is required for Consul's WAN.

import (
	"net"
	"time"
)

// Area defines a network area.
type Area struct {
	// ID is this identifier for an area (a UUID). This must be left empty
	// when creating a new area.
	ID string

	// PeerDatacenter is the peer Consul datacenter that will make up the
	// other side of this network area. Network areas always involve a pair
	// of datacenters: the datacenter where the area was created, and the
	// peer datacenter. This is required.
	PeerDatacenter string

	// RetryJoin specifies the address of Consul servers to join to, such as
	// an IPs or hostnames with an optional port number. This is optional.
	RetryJoin []string

	// UseTLS specifies whether gossip over this area should be encrypted with TLS
	// if possible.
	UseTLS bool
}

// AreaJoinResponse is returned when a join occurs and gives the result for each
// address.
type AreaJoinResponse struct {
	// The address that was joined.
	Address string

	// Whether or not the join was a success.
	Joined bool

	// If we couldn't join, this is the message with information.
	Error string
}

// SerfMember is a generic structure for reporting information about members in
// a Serf cluster. This is only used by the area endpoints right now, but this
// could be expanded to other endpoints in the future.
type SerfMember struct {
	// ID is the node identifier (a UUID).
	ID string

	// Name is the node name.
	Name string

	// Addr has the IP address.
	Addr net.IP

	// Port is the RPC port.
	Port uint16

	// Datacenter is the DC name.
	Datacenter string

	// Role is "client", "server", or "unknown".
	Role string

	// Build has the version of the Consul agent.
	Build string

	// Protocol is the protocol of the Consul agent.
	Protocol int

	// Status is the Serf health status "none", "alive", "leaving", "left",
	// or "failed".
	Status string

	// RTT is the estimated round trip time from the server handling the
	// request to the this member. This will be negative if no RTT estimate
	// is available.
	RTT time.Duration
}

// AreaCreate will create a new network area. The ID in the given structure must
// be empty and a generated ID will be returned on success.
func (op *Operator) AreaCreate(area *Area, q *WriteOptions) (string, *WriteMeta, error) {
	r := op.c.newRequest("POST", "/v1/operator/area")
	r.setWriteOptions(q)
	r.obj = area
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return "", nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt

	var out struct{ ID string }
	if err := decodeBody(resp, &out); err != nil {
		return "", nil, err
	}
	return out.ID, wm, nil
}

// AreaUpdate will update the configuration of the network area with the given ID.
func (op *Operator) AreaUpdate(areaID string, area *Area, q *WriteOptions) (string, *WriteMeta, error) {
	r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID)
	r.setWriteOptions(q)
	r.obj = area
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return "", nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt

	var out struct{ ID string }
	if err := decodeBody(resp, &out); err != nil {
		return "", nil, err
	}
	return out.ID, wm, nil
}

// AreaGet returns a single network area.
func (op *Operator) AreaGet(areaID string, q *QueryOptions) ([]*Area, *QueryMeta, error) {
	var out []*Area
	qm, err := op.c.query("/v1/operator/area/"+areaID, &out, q)
	if err != nil {
		return nil, nil, err
	}
	return out, qm, nil
}

// AreaList returns all the available network areas.
func (op *Operator) AreaList(q *QueryOptions) ([]*Area, *QueryMeta, error) {
	var out []*Area
	qm, err := op.c.query("/v1/operator/area", &out, q)
	if err != nil {
		return nil, nil, err
	}
	return out, qm, nil
}

// AreaDelete deletes the given network area.
func (op *Operator) AreaDelete(areaID string, q *WriteOptions) (*WriteMeta, error) {
	r := op.c.newRequest("DELETE", "/v1/operator/area/"+areaID)
	r.setWriteOptions(q)
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt
	return wm, nil
}

// AreaJoin attempts to join the given set of join addresses to the given
// network area. See the Area structure for details about join addresses.
func (op *Operator) AreaJoin(areaID string, addresses []string, q *WriteOptions) ([]*AreaJoinResponse, *WriteMeta, error) {
	r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID+"/join")
	r.setWriteOptions(q)
	r.obj = addresses
	rtt, resp, err := requireOK(op.c.doRequest(r))
	if err != nil {
		return nil, nil, err
	}
	defer resp.Body.Close()

	wm := &WriteMeta{}
	wm.RequestTime = rtt

	var out []*AreaJoinResponse
	if err := decodeBody(resp, &out); err != nil {
		return nil, nil, err
	}
	return out, wm, nil
}

// AreaMembers lists the Serf information about the members in the given area.
func (op *Operator) AreaMembers(areaID string, q *QueryOptions) ([]*SerfMember, *QueryMeta, error) {
	var out []*SerfMember
	qm, err := op.c.query("/v1/operator/area/"+areaID+"/members", &out, q)
	if err != nil {
		return nil, nil, err
	}
	return out, qm, nil
}
<|endoftext|>


<commit_before>package server

import (
	"path"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/iron-io/functions/api/ifaces"
	"github.com/iron-io/functions/api/models"
	"github.com/iron-io/functions/api/runner"
	titancommon "github.com/iron-io/titan/common"
)

// Would be nice to not have this is a global, but hard to pass things around to the
// handlers in Gin without it.
var Api *Server

type Server struct {
	Runner          *runner.Runner
	Router          *gin.Engine
	Datastore       models.Datastore
	AppListeners    []ifaces.AppListener
	SpecialHandlers []ifaces.SpecialHandler
}

func New(ds models.Datastore, r *runner.Runner) *Server {
	Api = &Server{
		Router:    gin.Default(),
		Datastore: ds,
		Runner:    r,
	}
	return Api
}

// AddAppListener adds a listener that will be notified on App changes.
func (s *Server) AddAppListener(listener ifaces.AppListener) {
	s.AppListeners = append(s.AppListeners, listener)
}

func (s *Server) FireBeforeAppUpdate(ctx context.Context, app *models.App) error {
	for _, l := range s.AppListeners {
		err := l.BeforeAppUpdate(ctx, app)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) FireAfterAppUpdate(ctx context.Context, app *models.App) error {
	for _, l := range s.AppListeners {
		err := l.AfterAppUpdate(ctx, app)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) AddSpecialHandler(handler ifaces.SpecialHandler) {
	s.SpecialHandlers = append(s.SpecialHandlers, handler)
}

func (s *Server) UseSpecialHandlers(ginC *gin.Context) error {
	c := &SpecialHandlerContext{
		server:     s,
		ginContext: ginC,
	}
	for _, l := range s.SpecialHandlers {
		err := l.Handle(c)
		if err != nil {
			return err
		}
	}
	// now call the normal runner call
	handleRunner(ginC)
	return nil
}

func extractFields(c *gin.Context) logrus.Fields {
	fields := logrus.Fields{"action": path.Base(c.HandlerName())}
	for _, param := range c.Params {
		fields[param.Key] = param.Value
	}
	return fields
}

func (s *Server) Run(ctx context.Context) {

	s.Router.Use(func(c *gin.Context) {
		ctx, _ := titancommon.LoggerWithFields(ctx, extractFields(c))
		c.Set("ctx", ctx)
		c.Next()
	})

	bindHandlers(s.Router)

	// Default to :8080
	s.Router.Run()
}

func bindHandlers(engine *gin.Engine) {
	engine.GET("/", handlePing)
	engine.GET("/version", handleVersion)

	v1 := engine.Group("/v1")
	{
		v1.GET("/apps", handleAppList)
		v1.POST("/apps", handleAppCreate)

		v1.GET("/apps/:app", handleAppGet)
		v1.PUT("/apps/:app", handleAppUpdate)
		v1.DELETE("/apps/:app", handleAppDelete)

		v1.GET("/routes", handleRouteList)

		apps := v1.Group("/apps/:app")
		{
			apps.GET("/routes", handleRouteList)
			apps.POST("/routes", handleRouteCreate)
			apps.GET("/routes/*route", handleRouteGet)
			apps.PUT("/routes/*route", handleRouteUpdate)
			apps.DELETE("/routes/*route", handleRouteDelete)
		}
	}

	engine.Any("/r/:app/*route", handleRunner)

	// This final route is used for extensions, see Server.Add
	engine.NoRoute(handleSpecial)
}

func simpleError(err error) *models.Error {
	return &models.Error{&models.ErrorBody{Message: err.Error()}}
}
<commit_msg>server port comment about default/PORT env var<commit_after>package server

import (
	"path"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/iron-io/functions/api/ifaces"
	"github.com/iron-io/functions/api/models"
	"github.com/iron-io/functions/api/runner"
	titancommon "github.com/iron-io/titan/common"
)

// Would be nice to not have this is a global, but hard to pass things around to the
// handlers in Gin without it.
var Api *Server

type Server struct {
	Runner          *runner.Runner
	Router          *gin.Engine
	Datastore       models.Datastore
	AppListeners    []ifaces.AppListener
	SpecialHandlers []ifaces.SpecialHandler
}

func New(ds models.Datastore, r *runner.Runner) *Server {
	Api = &Server{
		Router:    gin.Default(),
		Datastore: ds,
		Runner:    r,
	}
	return Api
}

// AddAppListener adds a listener that will be notified on App changes.
func (s *Server) AddAppListener(listener ifaces.AppListener) {
	s.AppListeners = append(s.AppListeners, listener)
}

func (s *Server) FireBeforeAppUpdate(ctx context.Context, app *models.App) error {
	for _, l := range s.AppListeners {
		err := l.BeforeAppUpdate(ctx, app)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) FireAfterAppUpdate(ctx context.Context, app *models.App) error {
	for _, l := range s.AppListeners {
		err := l.AfterAppUpdate(ctx, app)
		if err != nil {
			return err
		}
	}
	return nil
}

func (s *Server) AddSpecialHandler(handler ifaces.SpecialHandler) {
	s.SpecialHandlers = append(s.SpecialHandlers, handler)
}

func (s *Server) UseSpecialHandlers(ginC *gin.Context) error {
	c := &SpecialHandlerContext{
		server:     s,
		ginContext: ginC,
	}
	for _, l := range s.SpecialHandlers {
		err := l.Handle(c)
		if err != nil {
			return err
		}
	}
	// now call the normal runner call
	handleRunner(ginC)
	return nil
}

func extractFields(c *gin.Context) logrus.Fields {
	fields := logrus.Fields{"action": path.Base(c.HandlerName())}
	for _, param := range c.Params {
		fields[param.Key] = param.Value
	}
	return fields
}

func (s *Server) Run(ctx context.Context) {

	s.Router.Use(func(c *gin.Context) {
		ctx, _ := titancommon.LoggerWithFields(ctx, extractFields(c))
		c.Set("ctx", ctx)
		c.Next()
	})

	bindHandlers(s.Router)

	// By default it serves on :8080 unless a
	// PORT environment variable was defined.
	s.Router.Run()
}

func bindHandlers(engine *gin.Engine) {
	engine.GET("/", handlePing)
	engine.GET("/version", handleVersion)

	v1 := engine.Group("/v1")
	{
		v1.GET("/apps", handleAppList)
		v1.POST("/apps", handleAppCreate)

		v1.GET("/apps/:app", handleAppGet)
		v1.PUT("/apps/:app", handleAppUpdate)
		v1.DELETE("/apps/:app", handleAppDelete)

		v1.GET("/routes", handleRouteList)

		apps := v1.Group("/apps/:app")
		{
			apps.GET("/routes", handleRouteList)
			apps.POST("/routes", handleRouteCreate)
			apps.GET("/routes/*route", handleRouteGet)
			apps.PUT("/routes/*route", handleRouteUpdate)
			apps.DELETE("/routes/*route", handleRouteDelete)
		}
	}

	engine.Any("/r/:app/*route", handleRunner)

	// This final route is used for extensions, see Server.Add
	engine.NoRoute(handleSpecial)
}

func simpleError(err error) *models.Error {
	return &models.Error{&models.ErrorBody{Message: err.Error()}}
}
<|endoftext|>


<commit_before>package service

import (
	proxy "github.com/jeffjen/docker-ambassador/proxy"

	log "github.com/Sirupsen/logrus"

	"encoding/json"
	"net/http"
)

func ProxyHelper(w http.ResponseWriter, r *http.Request) {
	if err := common("POST", r); err != nil {
		http.Error(w, err.Error(), 400)
		return
	}

	var (
		meta = new(proxy.Info)

		dec = json.NewDecoder(r.Body)
	)

	if err := dec.Decode(meta); err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bad proxy spec")
		http.Error(w, "bad proxy spec", 400)
		return
	}

	if err := proxy.Listen(meta); err != nil {
		if err != proxy.ErrProxyExist {
			log.WithFields(log.Fields{"err": err}).Warning("proxy failed")
			http.Error(w, "internal server error", 500)
			return
		}
	}

	w.Write([]byte("done"))
}

func ProxyRemove(w http.ResponseWriter, r *http.Request, args []string) {
	if err := common("DELETE", r); err != nil {
		http.Error(w, err.Error(), 400)
		return
	}

	var From string = args[0]

	if meta, ok := proxy.ProxyStore[From]; ok {
		meta.Cancel()
		w.Write([]byte("done"))
	} else {
		http.Error(w, "not found", 404)
	}

	return
}
<commit_msg>FIX: cancel proxy endpoint residual<commit_after>package service

import (
	proxy "github.com/jeffjen/docker-ambassador/proxy"

	log "github.com/Sirupsen/logrus"

	"encoding/json"
	"net/http"
)

func ProxyHelper(w http.ResponseWriter, r *http.Request) {
	if err := common("POST", r); err != nil {
		http.Error(w, err.Error(), 400)
		return
	}

	var (
		meta = new(proxy.Info)

		dec = json.NewDecoder(r.Body)
	)

	if err := dec.Decode(meta); err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bad proxy spec")
		http.Error(w, "bad proxy spec", 400)
		return
	}

	if err := proxy.Listen(meta); err != nil {
		if err != proxy.ErrProxyExist {
			log.WithFields(log.Fields{"err": err}).Warning("proxy failed")
			http.Error(w, "internal server error", 500)
			return
		}
	}

	w.Write([]byte("done"))
}

func ProxyRemove(w http.ResponseWriter, r *http.Request, args []string) {
	if err := common("DELETE", r); err != nil {
		http.Error(w, err.Error(), 400)
		return
	}

	var From string = args[0]

	if meta, ok := proxy.ProxyStore[From]; ok {
		delete(proxy.ProxyStore, meta.From)
		meta.Cancel()
		w.Write([]byte("done"))
	} else {
		http.Error(w, "not found", 404)
	}

	return
}
<|endoftext|>


<commit_before>package agent

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/codegangsta/cli"

	"github.com/subutai-io/base/agent/agent/alert"
	"github.com/subutai-io/base/agent/agent/connect"
	"github.com/subutai-io/base/agent/agent/container"
	"github.com/subutai-io/base/agent/agent/executer"
	"github.com/subutai-io/base/agent/agent/utils"
	"github.com/subutai-io/base/agent/cli"
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/lib/gpg"
	"github.com/subutai-io/base/agent/log"
)

type Response struct {
	Beat Heartbeat `json:"response"`
}

type Heartbeat struct {
	Type       string                `json:"type"`
	Hostname   string                `json:"hostname"`
	Id         string                `json:"id"`
	Arch       string                `json:"arch"`
	Instance   string                `json:"instance"`
	Interfaces []utils.Iface         `json:"interfaces,omitempty"`
	Containers []container.Container `json:"containers,omitempty"`
	Alert      []alert.Load          `json:"alert,omitempty"`
}

var (
	lastHeartbeat     []byte
	mutex             sync.Mutex
	fingerprint       string
	hostname          string
	client            *http.Client
	instanceType      string
	instanceArch      string
	lastHeartbeatTime time.Time
	pool              []container.Container
)

func initAgent() {
	// move .gnupg dir to app home
	os.Setenv("GNUPGHOME", config.Agent.DataPrefix+".gnupg")

	instanceType = utils.InstanceType()
	instanceArch = strings.ToUpper(runtime.GOARCH)
	client = tlsConfig()
}

func Start(c *cli.Context) {
	http.HandleFunc("/trigger", trigger)
	http.HandleFunc("/ping", ping)
	http.HandleFunc("/heartbeat", heartbeatCall)
	go http.ListenAndServe(":7070", nil)

	initAgent()
	go lib.Collect()
	go connectionMonitor()
	go alert.AlertProcessing()

	for {
		if heartbeat() {
			time.Sleep(30 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
		container.ContainersRestoreState(pool)
	}
}

func connectionMonitor() {
	for {
		hostname, _ = os.Hostname()
		if fingerprint == "" || config.Management.GpgUser == "" {
			fingerprint = gpg.GetFingerprint(hostname + "@subutai.io")
			connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
		} else {
			resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/check/" + fingerprint)
			if err == nil && resp.StatusCode == http.StatusOK {
				resp.Body.Close()
				log.Debug("Connection monitor check - success")
			} else {
				log.Debug("Connection monitor check - failed")
				connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
				lastHeartbeat = []byte{}
				go heartbeat()
			}
		}

		time.Sleep(time.Second * 10)
	}
}

func heartbeat() bool {
	mutex.Lock()
	defer mutex.Unlock()
	if len(lastHeartbeat) > 0 && time.Since(lastHeartbeatTime) < time.Second*5 {
		return false
	}

	pool = container.GetActiveContainers(false)
	beat := Heartbeat{
		Type:       "HEARTBEAT",
		Hostname:   hostname,
		Id:         fingerprint,
		Arch:       instanceArch,
		Instance:   instanceType,
		Containers: pool,
		Interfaces: utils.GetInterfaces(),
		Alert:      alert.CurrentAlerts(pool),
	}
	res := Response{Beat: beat}
	jbeat, _ := json.Marshal(&res)

	lastHeartbeatTime = time.Now()
	if string(jbeat) == string(lastHeartbeat) {
		return true
	}
	lastHeartbeat = jbeat

	message, err := json.Marshal(map[string]string{
		"hostId":   fingerprint,
		"response": gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jbeat)),
	})
	log.Check(log.WarnLevel, "Marshal response json", err)

	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/heartbeat", url.Values{"heartbeat": {string(message)}})
	if !log.Check(log.WarnLevel, "Sending heartbeat: "+string(jbeat), err) {
		log.Debug(resp.Status)
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return true
		}
	}
	lastHeartbeat = []byte{}
	return false
}

func execute(rsp executer.EncRequest) {
	var req executer.Request
	var md, contName, pub, keyring, payload string
	var err error

	if rsp.HostId == fingerprint {
		md = gpg.DecryptWrapper(rsp.Request)
	} else {
		contName = nameById(rsp.HostId)
		if contName == "" {
			lastHeartbeat = []byte{}
			heartbeat()
			contName = nameById(rsp.HostId)
			if contName == "" {
				return
			}
		}

		pub = config.Agent.LxcPrefix + contName + "/public.pub"
		keyring = config.Agent.LxcPrefix + contName + "/secret.sec"
		log.Info("Getting public keyring", "keyring", keyring)
		md = gpg.DecryptNoDefaultKeyring(rsp.Request, keyring, pub)
	}
	i := strings.Index(md, "{")
	j := strings.LastIndex(md, "}") + 1
	if i > j && i > 0 {
		log.Warn("Error getting JSON request")
		return
	}
	request := md[i:j]

	err = json.Unmarshal([]byte(request), &req.Request)
	log.Check(log.WarnLevel, "Decrypting request", err)

	//create channels for stdout and stderr
	sOut := make(chan executer.ResponseOptions)
	if rsp.HostId == fingerprint {
		go executer.ExecHost(req.Request, sOut)
	} else {
		go executer.AttachContainer(contName, req.Request, sOut)
	}

	for sOut != nil {
		elem, ok := <-sOut
		if ok {
			resp := executer.Response{ResponseOpts: elem}
			jsonR, err := json.Marshal(resp)
			log.Check(log.WarnLevel, "Marshal response", err)
			if rsp.HostId == fingerprint {
				payload = gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jsonR))
			} else {
				payload = gpg.EncryptWrapperNoDefaultKeyring(contName, config.Management.GpgUser, string(jsonR), pub, keyring)
			}
			message, err := json.Marshal(map[string]string{
				"hostId":   elem.Id,
				"response": payload,
			})
			log.Check(log.WarnLevel, "Marshal response json "+elem.CommandId, err)
			go response(message)
		} else {
			sOut = nil
		}
	}
	go heartbeat()
}

func tlsConfig() *http.Client {
	tlsconfig := newTLSConfig()
	for tlsconfig == nil || len(tlsconfig.Certificates[0].Certificate) == 0 {
		time.Sleep(time.Second * 2)
		for utils.PublicCert() == "" {
			x509generate()
		}
		tlsconfig = newTLSConfig()
	}

	transport := &http.Transport{TLSClientConfig: tlsconfig}
	return &http.Client{Transport: transport, Timeout: time.Second * 30}
}

func response(msg []byte) {
	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/response", url.Values{"response": {string(msg)}})
	if !log.Check(log.WarnLevel, "Sending response "+string(msg), err) {
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return
		}
	}
	time.Sleep(time.Second * 5)
	go response(msg)

}

func command() {
	var rsp []executer.EncRequest

	resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/requests/" + fingerprint)
	if log.Check(log.WarnLevel, "Getting requests", err) {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNoContent {
		return
	}

	data, err := ioutil.ReadAll(resp.Body)
	if !log.Check(log.WarnLevel, "Reading body", err) {
		log.Check(log.WarnLevel, "Unmarshal payload", json.Unmarshal(data, &rsp))
		for _, request := range rsp {
			go execute(request)
		}
	}
}

func ping(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func trigger(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodPost && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusAccepted)
		go command()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func heartbeatCall(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
		lastHeartbeat = []byte{}
		heartbeat()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func nameById(id string) string {
	for _, c := range pool {
		if c.Id == id {
			return c.Name
		}
	}
	return ""
}
<commit_msg>Removed useless checks.<commit_after>package agent

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/codegangsta/cli"

	"github.com/subutai-io/base/agent/agent/alert"
	"github.com/subutai-io/base/agent/agent/connect"
	"github.com/subutai-io/base/agent/agent/container"
	"github.com/subutai-io/base/agent/agent/executer"
	"github.com/subutai-io/base/agent/agent/utils"
	"github.com/subutai-io/base/agent/cli"
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/lib/gpg"
	"github.com/subutai-io/base/agent/log"
)

type Response struct {
	Beat Heartbeat `json:"response"`
}

type Heartbeat struct {
	Type       string                `json:"type"`
	Hostname   string                `json:"hostname"`
	Id         string                `json:"id"`
	Arch       string                `json:"arch"`
	Instance   string                `json:"instance"`
	Interfaces []utils.Iface         `json:"interfaces,omitempty"`
	Containers []container.Container `json:"containers,omitempty"`
	Alert      []alert.Load          `json:"alert,omitempty"`
}

var (
	lastHeartbeat     []byte
	mutex             sync.Mutex
	fingerprint       string
	hostname          string
	client            *http.Client
	instanceType      string
	instanceArch      string
	lastHeartbeatTime time.Time
	pool              []container.Container
)

func initAgent() {
	// move .gnupg dir to app home
	os.Setenv("GNUPGHOME", config.Agent.DataPrefix+".gnupg")

	instanceType = utils.InstanceType()
	instanceArch = strings.ToUpper(runtime.GOARCH)
	client = tlsConfig()
}

func Start(c *cli.Context) {
	http.HandleFunc("/trigger", trigger)
	http.HandleFunc("/ping", ping)
	http.HandleFunc("/heartbeat", heartbeatCall)
	go http.ListenAndServe(":7070", nil)

	initAgent()
	go lib.Collect()
	go connectionMonitor()
	go alert.AlertProcessing()

	for {
		if heartbeat() {
			time.Sleep(30 * time.Second)
		} else {
			time.Sleep(5 * time.Second)
		}
		container.ContainersRestoreState(pool)
	}
}

func connectionMonitor() {
	for {
		hostname, _ = os.Hostname()
		if fingerprint == "" || config.Management.GpgUser == "" {
			fingerprint = gpg.GetFingerprint(hostname + "@subutai.io")
			connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
		} else {
			resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/check/" + fingerprint)
			if err == nil && resp.StatusCode == http.StatusOK {
				resp.Body.Close()
				log.Debug("Connection monitor check - success")
			} else {
				log.Debug("Connection monitor check - failed")
				connect.Connect(config.Management.Host, config.Management.Port, config.Agent.GpgUser, config.Management.Secret)
				lastHeartbeat = []byte{}
				go heartbeat()
			}
		}

		time.Sleep(time.Second * 10)
	}
}

func heartbeat() bool {
	mutex.Lock()
	defer mutex.Unlock()
	if len(lastHeartbeat) > 0 && time.Since(lastHeartbeatTime) < time.Second*5 {
		return false
	}

	pool = container.GetActiveContainers(false)
	beat := Heartbeat{
		Type:       "HEARTBEAT",
		Hostname:   hostname,
		Id:         fingerprint,
		Arch:       instanceArch,
		Instance:   instanceType,
		Containers: pool,
		Interfaces: utils.GetInterfaces(),
		Alert:      alert.CurrentAlerts(pool),
	}
	res := Response{Beat: beat}
	jbeat, _ := json.Marshal(&res)

	lastHeartbeatTime = time.Now()
	if string(jbeat) == string(lastHeartbeat) {
		return true
	}
	lastHeartbeat = jbeat

	message, err := json.Marshal(map[string]string{
		"hostId":   fingerprint,
		"response": gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jbeat)),
	})
	log.Check(log.WarnLevel, "Marshal response json", err)

	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/heartbeat", url.Values{"heartbeat": {string(message)}})
	if !log.Check(log.WarnLevel, "Sending heartbeat: "+string(jbeat), err) {
		log.Debug(resp.Status)
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return true
		}
	}
	lastHeartbeat = []byte{}
	return false
}

func execute(rsp executer.EncRequest) {
	var req executer.Request
	var md, contName, pub, keyring, payload string

	if rsp.HostId == fingerprint {
		md = gpg.DecryptWrapper(rsp.Request)
	} else {
		contName = nameById(rsp.HostId)
		if contName == "" {
			lastHeartbeat = []byte{}
			heartbeat()
			contName = nameById(rsp.HostId)
			if contName == "" {
				return
			}
		}

		pub = config.Agent.LxcPrefix + contName + "/public.pub"
		keyring = config.Agent.LxcPrefix + contName + "/secret.sec"
		log.Info("Getting public keyring", "keyring", keyring)
		md = gpg.DecryptNoDefaultKeyring(rsp.Request, keyring, pub)
	}
	if log.Check(log.WarnLevel, "Decrypting request", json.Unmarshal([]byte(md), &req.Request)) {
		return
	}

	//create channels for stdout and stderr
	sOut := make(chan executer.ResponseOptions)
	if rsp.HostId == fingerprint {
		go executer.ExecHost(req.Request, sOut)
	} else {
		go executer.AttachContainer(contName, req.Request, sOut)
	}

	for sOut != nil {
		elem, ok := <-sOut
		if ok {
			resp := executer.Response{ResponseOpts: elem}
			jsonR, err := json.Marshal(resp)
			log.Check(log.WarnLevel, "Marshal response", err)
			if rsp.HostId == fingerprint {
				payload = gpg.EncryptWrapper(config.Agent.GpgUser, config.Management.GpgUser, string(jsonR))
			} else {
				payload = gpg.EncryptWrapperNoDefaultKeyring(contName, config.Management.GpgUser, string(jsonR), pub, keyring)
			}
			message, err := json.Marshal(map[string]string{
				"hostId":   elem.Id,
				"response": payload,
			})
			log.Check(log.WarnLevel, "Marshal response json "+elem.CommandId, err)
			go response(message)
		} else {
			sOut = nil
		}
	}
	go heartbeat()
}

func tlsConfig() *http.Client {
	tlsconfig := newTLSConfig()
	for tlsconfig == nil || len(tlsconfig.Certificates[0].Certificate) == 0 {
		time.Sleep(time.Second * 2)
		for utils.PublicCert() == "" {
			x509generate()
		}
		tlsconfig = newTLSConfig()
	}

	transport := &http.Transport{TLSClientConfig: tlsconfig}
	return &http.Client{Transport: transport, Timeout: time.Second * 30}
}

func response(msg []byte) {
	resp, err := client.PostForm("https://"+config.Management.Host+":8444/rest/v1/agent/response", url.Values{"response": {string(msg)}})
	if !log.Check(log.WarnLevel, "Sending response "+string(msg), err) {
		resp.Body.Close()
		if resp.StatusCode == http.StatusAccepted {
			return
		}
	}
	time.Sleep(time.Second * 5)
	go response(msg)

}

func command() {
	var rsp []executer.EncRequest

	resp, err := client.Get("https://" + config.Management.Host + ":8444/rest/v1/agent/requests/" + fingerprint)
	if log.Check(log.WarnLevel, "Getting requests", err) {
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode == http.StatusNoContent {
		return
	}

	data, err := ioutil.ReadAll(resp.Body)
	if !log.Check(log.WarnLevel, "Reading body", err) {
		log.Check(log.WarnLevel, "Unmarshal payload", json.Unmarshal(data, &rsp))
		for _, request := range rsp {
			go execute(request)
		}
	}
}

func ping(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func trigger(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodPost && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusAccepted)
		go command()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func heartbeatCall(rw http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet && strings.Split(request.RemoteAddr, ":")[0] == config.Management.Host {
		rw.WriteHeader(http.StatusOK)
		lastHeartbeat = []byte{}
		heartbeat()
	} else {
		rw.WriteHeader(http.StatusForbidden)
	}
}

func nameById(id string) string {
	for _, c := range pool {
		if c.Id == id {
			return c.Name
		}
	}
	return ""
}
<|endoftext|>


<commit_before>package lib

import (
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/lib/container"
	"github.com/subutai-io/base/agent/lib/net"
	"github.com/subutai-io/base/agent/lib/net/p2p"
)

func Cleanup(vlan string) {
	for _, name := range container.Containers() {
		if container.GetConfigItem(config.Agent.LxcPrefix+name+"/config", "#vlan_id") == vlan {
			LxcDestroy(name)
		}
	}
	net.DelIface("gw-" + vlan)
	p2p.RemoveByIface("p2p-" + vlan)
	ProxyDel(vlan, "", true)
}
<commit_msg>Changed p2p interface name on cleanup.<commit_after>package lib

import (
	"github.com/subutai-io/base/agent/config"
	"github.com/subutai-io/base/agent/lib/container"
	"github.com/subutai-io/base/agent/lib/net"
	"github.com/subutai-io/base/agent/lib/net/p2p"
)

func Cleanup(vlan string) {
	for _, name := range container.Containers() {
		if container.GetConfigItem(config.Agent.LxcPrefix+name+"/config", "#vlan_id") == vlan {
			LxcDestroy(name)
		}
	}
	net.DelIface("gw-" + vlan)
	p2p.RemoveByIface("p2p" + vlan)
	ProxyDel(vlan, "", true)
}
<|endoftext|>


<commit_before>package admin

import (
	"fmt"
	"log"
	"net/http"
	"path"
	"reflect"
	"regexp"
	"strings"
	"time"

	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/roles"
)

type (
	handle func(c *Context)

	handler struct {
		Path   *regexp.Regexp
		Handle handle
	}
)

type Router struct {
	Prefix      string
	routers     map[string][]handler
	middlewares []*Middleware
}

func newRouter() *Router {
	return &Router{routers: map[string][]handler{
		"GET":    []handler{},
		"PUT":    []handler{},
		"POST":   []handler{},
		"DELETE": []handler{},
	}}
}

type Middleware struct {
	Handler func(*Context, *Middleware)
	next    *Middleware
}

func (middleware Middleware) Next(context *Context) {
	if next := middleware.next; next != nil {
		next.Handler(context, next)
	}
}

func (r *Router) Use(handler func(*Context, *Middleware)) {
	r.middlewares = append(r.middlewares, &Middleware{Handler: handler})
}

func (r *Router) Get(path string, handle handle) {
	r.routers["GET"] = append(r.routers["GET"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Post(path string, handle handle) {
	r.routers["POST"] = append(r.routers["POST"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Put(path string, handle handle) {
	r.routers["PUT"] = append(r.routers["PUT"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Delete(path string, handle handle) {
	r.routers["DELETE"] = append(r.routers["DELETE"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (admin *Admin) MountTo(prefix string, mux *http.ServeMux) {
	prefix = "/" + strings.Trim(prefix, "/")
	router := admin.router
	router.Prefix = prefix

	admin.compile()

	controller := &controller{admin}
	router.Get("^/?$", controller.Dashboard)
	router.Get("^/!search$", controller.SearchCenter)

	var registerToRouter = func(res *Resource) {
		// New
		router.Get(fmt.Sprintf("/%v/new", res.ToParam()), controller.New)

		// Create
		router.Post(fmt.Sprintf("/%v", res.ToParam()), controller.Create)

		// Show
		router.Get(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Show)

		// Edit
		router.Get(fmt.Sprintf("/%v/:id/edit", res.ToParam()), controller.Edit)

		// Update
		router.Put(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Update)
		router.Post(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Update)

		// Delete
		router.Delete(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Delete)

		// Index
		router.Get(fmt.Sprintf("/%v", res.ToParam()), controller.Index)

		// Action
		router.Post(fmt.Sprintf("/%v/action/[^/]+(\\?.*)?$", res.ToParam()), controller.Action)
	}

	for _, res := range admin.resources {
		if !res.Config.Invisible {
			registerToRouter(res)
		}
	}

	mux.Handle(prefix, admin)     // /:prefix
	mux.Handle(prefix+"/", admin) // /:prefix/:xxx
}

func (res *Resource) configure() {
	modelType := res.GetAdmin().Config.DB.NewScope(res.Value).GetModelStruct().ModelType
	for i := 0; i < modelType.NumField(); i++ {
		if fieldStruct := modelType.Field(i); fieldStruct.Anonymous {
			if injector, ok := reflect.New(fieldStruct.Type).Interface().(resource.ConfigureResourceInterface); ok {
				injector.ConfigureQorResource(res)
			}
		}
	}

	if injector, ok := res.Value.(resource.ConfigureResourceInterface); ok {
		injector.ConfigureQorResource(res)
	}
}

func (admin *Admin) compile() {
	admin.generateMenuLinks()

	router := admin.GetRouter()

	for _, res := range admin.resources {
		res.configure()
	}

	router.Use(func(context *Context, middleware *Middleware) {
		w := context.Writer
		req := context.Request

		// 128 MB
		req.ParseMultipartForm(32 << 22)
		if len(req.Form["_method"]) > 0 {
			req.Method = strings.ToUpper(req.Form["_method"][0])
		}

		var pathMatch = regexp.MustCompile(path.Join(router.Prefix, `(\w+)(?:/(\w+))?[^/]*`))
		var matches = pathMatch.FindStringSubmatch(req.URL.Path)
		if len(matches) > 1 {
			context.setResource(admin.GetResource(matches[1]))
			if len(matches) > 2 {
				context.ResourceID = matches[2]
			}
		}

		handlers := router.routers[strings.ToUpper(req.Method)]
		relativePath := strings.TrimPrefix(req.URL.Path, router.Prefix)
		for _, handler := range handlers {
			if handler.Path.MatchString(relativePath) {
				handler.Handle(context)
				return
			}
		}
		http.NotFound(w, req)
	})

	for index, middleware := range router.middlewares {
		var next *Middleware
		if len(router.middlewares) > index+1 {
			next = router.middlewares[index+1]
		}
		middleware.next = next
	}
}

func (admin *Admin) NewContext(w http.ResponseWriter, r *http.Request) *Context {
	context := Context{Context: &qor.Context{Config: admin.Config, Request: r, Writer: w}, Admin: admin}

	return &context
}

func (admin *Admin) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var relativePath = strings.TrimPrefix(req.URL.Path, admin.router.Prefix)
	var context = admin.NewContext(w, req)

	if regexp.MustCompile("^/assets/.*$").MatchString(relativePath) {
		(&controller{admin}).Asset(context)
		return
	}

	defer func() func() {
		begin := time.Now()
		log.Printf("Start [%s] %s\n", req.Method, req.RequestURI)

		return func() {
			log.Printf("Finish [%s] %s Took %.2fms\n", req.Method, req.RequestURI, time.Now().Sub(begin).Seconds()*1000)
		}
	}()()

	var currentUser qor.CurrentUser
	if admin.auth != nil {
		if currentUser = admin.auth.GetCurrentUser(context); currentUser == nil {
			http.Redirect(w, req, admin.auth.LoginURL(context), http.StatusSeeOther)
			return
		} else {
			context.CurrentUser = currentUser
			context.SetDB(context.GetDB().Set("qor:current_user", context.CurrentUser))
		}
	}
	context.Roles = roles.MatchedRoles(req, currentUser)

	firstStack := admin.router.middlewares[0]
	firstStack.Handler(context, firstStack)
}
<commit_msg>Register sub route<commit_after>package admin

import (
	"fmt"
	"log"
	"net/http"
	"path"
	"reflect"
	"regexp"
	"strings"
	"time"

	"github.com/qor/qor"
	"github.com/qor/qor/resource"
	"github.com/qor/qor/roles"
)

type (
	handle func(c *Context)

	handler struct {
		Path   *regexp.Regexp
		Handle handle
	}
)

type Router struct {
	Prefix      string
	routers     map[string][]handler
	middlewares []*Middleware
}

func newRouter() *Router {
	return &Router{routers: map[string][]handler{
		"GET":    []handler{},
		"PUT":    []handler{},
		"POST":   []handler{},
		"DELETE": []handler{},
	}}
}

type Middleware struct {
	Handler func(*Context, *Middleware)
	next    *Middleware
}

func (middleware Middleware) Next(context *Context) {
	if next := middleware.next; next != nil {
		next.Handler(context, next)
	}
}

func (r *Router) Use(handler func(*Context, *Middleware)) {
	r.middlewares = append(r.middlewares, &Middleware{Handler: handler})
}

func (r *Router) Get(path string, handle handle) {
	r.routers["GET"] = append(r.routers["GET"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Post(path string, handle handle) {
	r.routers["POST"] = append(r.routers["POST"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Put(path string, handle handle) {
	r.routers["PUT"] = append(r.routers["PUT"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (r *Router) Delete(path string, handle handle) {
	r.routers["DELETE"] = append(r.routers["DELETE"], handler{Path: regexp.MustCompile(path), Handle: handle})
}

func (admin *Admin) MountTo(prefix string, mux *http.ServeMux) {
	prefix = "/" + strings.Trim(prefix, "/")
	router := admin.router
	router.Prefix = prefix

	admin.compile()

	controller := &controller{admin}
	router.Get("^/?$", controller.Dashboard)
	router.Get("^/!search$", controller.SearchCenter)

	var registerToRouter = func(res *Resource) {
		// New
		router.Get(fmt.Sprintf("/%v/new", res.ToParam()), controller.New)

		// Create
		router.Post(fmt.Sprintf("/%v", res.ToParam()), controller.Create)

		// Show
		router.Get(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Show)

		// Edit
		router.Get(fmt.Sprintf("/%v/:id/edit", res.ToParam()), controller.Edit)

		// Update
		router.Put(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Update)
		router.Post(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Update)

		// Delete
		router.Delete(fmt.Sprintf("/%v/:id", res.ToParam()), controller.Delete)

		// Index
		router.Get(fmt.Sprintf("/%v", res.ToParam()), controller.Index)

		// Action
		router.Post(fmt.Sprintf("/%v/action/[^/]+(\\?.*)?$", res.ToParam()), controller.Action)

		// Sub Resources
		for _, meta := range res.ConvertSectionToMetas(res.ShowAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				subParam := meta.Resource.(*Resource).ToParam()
				router.Get(fmt.Sprintf("/%v/:id/%v", res.ToParam(), subParam), controller.Index)
				router.Get(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Show)
			}
		}

		for _, meta := range res.ConvertSectionToMetas(res.EditAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				subParam := meta.Resource.(*Resource).ToParam()
				router.Post(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Update)
				router.Put(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Update)
				router.Delete(fmt.Sprintf("/%v/:id/%v/:id", res.ToParam(), subParam), controller.Delete)
			}
		}

		for _, meta := range res.ConvertSectionToMetas(res.NewAttrs()) {
			if meta.FieldStruct != nil && meta.FieldStruct.Relationship != nil {
				subParam := meta.Resource.(*Resource).ToParam()
				router.Post(fmt.Sprintf("/%v/:id/%v", res.ToParam(), subParam), controller.Create)

				router.Get(fmt.Sprintf("/%v/new", res.ToParam()), controller.New)
			}
		}
	}

	for _, res := range admin.resources {
		if !res.Config.Invisible {
			registerToRouter(res)
		}
	}

	mux.Handle(prefix, admin)     // /:prefix
	mux.Handle(prefix+"/", admin) // /:prefix/:xxx
}

func (res *Resource) configure() {
	modelType := res.GetAdmin().Config.DB.NewScope(res.Value).GetModelStruct().ModelType
	for i := 0; i < modelType.NumField(); i++ {
		if fieldStruct := modelType.Field(i); fieldStruct.Anonymous {
			if injector, ok := reflect.New(fieldStruct.Type).Interface().(resource.ConfigureResourceInterface); ok {
				injector.ConfigureQorResource(res)
			}
		}
	}

	if injector, ok := res.Value.(resource.ConfigureResourceInterface); ok {
		injector.ConfigureQorResource(res)
	}
}

func (admin *Admin) compile() {
	admin.generateMenuLinks()

	router := admin.GetRouter()

	for _, res := range admin.resources {
		res.configure()
	}

	router.Use(func(context *Context, middleware *Middleware) {
		w := context.Writer
		req := context.Request

		// 128 MB
		req.ParseMultipartForm(32 << 22)
		if len(req.Form["_method"]) > 0 {
			req.Method = strings.ToUpper(req.Form["_method"][0])
		}

		var pathMatch = regexp.MustCompile(path.Join(router.Prefix, `(\w+)(?:/(\w+))?[^/]*`))
		var matches = pathMatch.FindStringSubmatch(req.URL.Path)
		if len(matches) > 1 {
			context.setResource(admin.GetResource(matches[1]))
			if len(matches) > 2 {
				context.ResourceID = matches[2]
			}
		}

		handlers := router.routers[strings.ToUpper(req.Method)]
		relativePath := strings.TrimPrefix(req.URL.Path, router.Prefix)
		for _, handler := range handlers {
			if handler.Path.MatchString(relativePath) {
				handler.Handle(context)
				return
			}
		}
		http.NotFound(w, req)
	})

	for index, middleware := range router.middlewares {
		var next *Middleware
		if len(router.middlewares) > index+1 {
			next = router.middlewares[index+1]
		}
		middleware.next = next
	}
}

func (admin *Admin) NewContext(w http.ResponseWriter, r *http.Request) *Context {
	context := Context{Context: &qor.Context{Config: admin.Config, Request: r, Writer: w}, Admin: admin}

	return &context
}

func (admin *Admin) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	var relativePath = strings.TrimPrefix(req.URL.Path, admin.router.Prefix)
	var context = admin.NewContext(w, req)

	if regexp.MustCompile("^/assets/.*$").MatchString(relativePath) {
		(&controller{admin}).Asset(context)
		return
	}

	defer func() func() {
		begin := time.Now()
		log.Printf("Start [%s] %s\n", req.Method, req.RequestURI)

		return func() {
			log.Printf("Finish [%s] %s Took %.2fms\n", req.Method, req.RequestURI, time.Now().Sub(begin).Seconds()*1000)
		}
	}()()

	var currentUser qor.CurrentUser
	if admin.auth != nil {
		if currentUser = admin.auth.GetCurrentUser(context); currentUser == nil {
			http.Redirect(w, req, admin.auth.LoginURL(context), http.StatusSeeOther)
			return
		} else {
			context.CurrentUser = currentUser
			context.SetDB(context.GetDB().Set("qor:current_user", context.CurrentUser))
		}
	}
	context.Roles = roles.MatchedRoles(req, currentUser)

	firstStack := admin.router.middlewares[0]
	firstStack.Handler(context, firstStack)
}
<|endoftext|>


<commit_before>package annotations

// var (
// 	_ = moz.RegisterAnnotation("oauth", OAuthAnnotationGenerator)
// )
//
// // OAuthAnnotationGenerator defines a code generator for package level generator for creating
// // a http package for providing oauth authentication.
// func OAuthAnnotationGenerator(toDir string, an ast.AnnotationDeclaration, pkg ast.PackageDeclaration) ([]gen.WriteDirective, error) {
// 	var directives []gen.WriteDirective
//
// 	return directives, nil
// }
<commit_msg>Update natural types and fix bugs<commit_after><|endoftext|>