<commit_before>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package imagegallery

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/paths"
	"github.com/andreaskoch/allmark2/common/pattern"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/model"
	"github.com/andreaskoch/allmark2/services/converter/markdowntohtml/util"
	"github.com/andreaskoch/allmark2/services/thumbnail"
	"regexp"
	"strings"
)

var (
	// imagegallery: [*description text*](*folder path*)
	markdownPattern = regexp.MustCompile(`imagegallery: \[([^\]]*)\]\(([^)]+)\)`)
)

func New(pathProvider paths.Pather, baseRoute route.Route, files []*model.File, thumbnailIndex *thumbnail.Index) *FilePreviewExtension {
	return &FilePreviewExtension{
		pathProvider:   pathProvider,
		base:           baseRoute,
		files:          files,
		thumbnailIndex: thumbnailIndex,
	}
}

type FilePreviewExtension struct {
	pathProvider   paths.Pather
	base           route.Route
	files          []*model.File
	thumbnailIndex *thumbnail.Index
}

func (converter *FilePreviewExtension) Convert(markdown string) (convertedContent string, converterError error) {

	convertedContent = markdown

	for {

		found, matches := pattern.IsMatch(convertedContent, markdownPattern)
		if !found || (found && len(matches) != 3) {
			break
		}

		// parameters
		originalText := strings.TrimSpace(matches[0])
		title := strings.TrimSpace(matches[1])
		path := strings.TrimSpace(matches[2])

		// get the code
		renderedCode := converter.getGalleryCode(title, path)

		// replace markdown
		convertedContent = strings.Replace(convertedContent, originalText, renderedCode, 1)
	}

	return convertedContent, nil
}

func (converter *FilePreviewExtension) getGalleryCode(galleryTitle, path string) string {

	imageLinks := converter.getImageLinksByPath(path)
	if galleryTitle != "" {
		return fmt.Sprintf(`

					%s

						%s

`, galleryTitle, strings.Join(imageLinks, "\n
\n
\n"))
	}

	return fmt.Sprintf(`

						%s

`, strings.Join(imageLinks, "\n
\n
\n"))
}

func (converter *FilePreviewExtension) getImageLinksByPath(path string) []string {

	galleryRoute, err := route.NewFromRequest(path)
	if err != nil {
		// todo: log error
		return []string{}
	}

	baseRoute := converter.base
	fullGalleryRoute, err := route.Combine(baseRoute, galleryRoute)
	if err != nil {
		// todo: log error
		return []string{}
	}

	numberOfFiles := len(converter.files)
	imagelinks := make([]string, numberOfFiles, numberOfFiles)

	for index, file := range converter.files {

		// skip files which are not a child of the supplied path
		if !file.Route().IsChildOf(fullGalleryRoute) {
			continue
		}

		// skip files which are not images
		if !util.IsImageFile(file) {
			continue
		}

		// get paths
		fullSizeImagePath := converter.getImagePath(file.Route())
		thumnailPath := converter.getThumbnailPath(file.Route())

		// image title
		imageTitle := file.Route().LastComponentName() // file name

		imagelinks[index] = fmt.Sprintf(`<a href="%s" title="%s"><img src="%s" /></a>`, fullSizeImagePath, imageTitle, thumnailPath)
	}

	return imagelinks
}

func (converter *FilePreviewExtension) getThumbnailPath(fileRoute route.Route) string {

	// assemble to the full image route
	fullRoute, err := route.Combine(converter.base, fileRoute)
	if err != nil {
		panic(fmt.Sprintf("Cannot combine routes %q and %q.", converter.base, fileRoute))
	}

	// check if there are thumbs for the supplied file route
	thumbs, exists := converter.thumbnailIndex.GetThumbs(fullRoute.Value())
	if !exists {
		return converter.getImagePath(fileRoute) // return the full-size image path
	}

	// lookup thumb by size
	thumb, exists := thumbs.GetThumbBySize(thumbnail.SizeMedium)
	if !exists {
		return converter.getImagePath(fileRoute) // return the full-size image path

	}

	return converter.getImagePath(thumb.ThumbRoute())
}

func (converter *FilePreviewExtension) getImagePath(fileRoute route.Route) string {
	return converter.pathProvider.Path(fileRoute.Value())
}
<commit_msg>Use reponsive image definitions for image gallery images.<commit_after>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package imagegallery

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/paths"
	"github.com/andreaskoch/allmark2/common/pattern"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/model"
	"github.com/andreaskoch/allmark2/services/converter/markdowntohtml/util"
	"github.com/andreaskoch/allmark2/services/thumbnail"
	"regexp"
	"strings"
)

var (
	// imagegallery: [*description text*](*folder path*)
	markdownPattern = regexp.MustCompile(`imagegallery: \[([^\]]*)\]\(([^)]+)\)`)
)

func New(pathProvider paths.Pather, baseRoute route.Route, files []*model.File, thumbnailIndex *thumbnail.Index) *FilePreviewExtension {
	return &FilePreviewExtension{
		pathProvider:   pathProvider,
		base:           baseRoute,
		files:          files,
		thumbnailIndex: thumbnailIndex,
	}
}

type FilePreviewExtension struct {
	pathProvider   paths.Pather
	base           route.Route
	files          []*model.File
	thumbnailIndex *thumbnail.Index
}

func (converter *FilePreviewExtension) Convert(markdown string) (convertedContent string, converterError error) {

	convertedContent = markdown

	for {

		found, matches := pattern.IsMatch(convertedContent, markdownPattern)
		if !found || (found && len(matches) != 3) {
			break
		}

		// parameters
		originalText := strings.TrimSpace(matches[0])
		title := strings.TrimSpace(matches[1])
		path := strings.TrimSpace(matches[2])

		// get the code
		renderedCode := converter.getGalleryCode(title, path)

		// replace markdown
		convertedContent = strings.Replace(convertedContent, originalText, renderedCode, 1)
	}

	return convertedContent, nil
}

func (converter *FilePreviewExtension) getGalleryCode(galleryTitle, path string) string {

	imageLinks := converter.getImageLinksByPath(path)
	if galleryTitle != "" {
		return fmt.Sprintf(`

					%s

						%s

`, galleryTitle, strings.Join(imageLinks, "\n
\n
\n"))
	}

	return fmt.Sprintf(`

						%s

`, strings.Join(imageLinks, "\n
\n
\n"))
}

func (converter *FilePreviewExtension) getImageLinksByPath(path string) []string {

	galleryRoute, err := route.NewFromRequest(path)
	if err != nil {
		// todo: log error
		return []string{}
	}

	baseRoute := converter.base
	fullGalleryRoute, err := route.Combine(baseRoute, galleryRoute)
	if err != nil {
		// todo: log error
		return []string{}
	}

	numberOfFiles := len(converter.files)
	imagelinks := make([]string, numberOfFiles, numberOfFiles)

	for index, file := range converter.files {

		// skip files which are not a child of the supplied path
		if !file.Route().IsChildOf(fullGalleryRoute) {
			continue
		}

		// skip files which are not images
		if !util.IsImageFile(file) {
			continue
		}

		// image title
		imageTitle := file.Route().LastComponentName() // use the file name for the title

		// get paths
		fullSizeImagePath := converter.getImagePath(file.Route())

		// get thumbnail paths
		small, smallExists := converter.getThumbnailPath(file.Route(), thumbnail.SizeSmall)
		medium, mediumExists := converter.getThumbnailPath(file.Route(), thumbnail.SizeMedium)
		large, largeExists := converter.getThumbnailPath(file.Route(), thumbnail.SizeLarge)

		// assemble the image code
		image := "<img"

		// assemble the src sets
		if smallExists || mediumExists || largeExists {

			image += " srcset=\""

			srcSets := make([]string, 0)
			if smallExists {
				srcSets = append(srcSets, small+fmt.Sprintf(" %vw", thumbnail.SizeSmall.MaxWidth))
			}

			if mediumExists {
				srcSets = append(srcSets, medium+fmt.Sprintf(" %vw", thumbnail.SizeMedium.MaxWidth))
			}

			if largeExists {
				srcSets = append(srcSets, large+fmt.Sprintf(" %vw", thumbnail.SizeLarge.MaxWidth))
			}

			image += strings.Join(srcSets, ", ")
		}

		// default image
		if smallExists || mediumExists || largeExists {

			// use the small image as the default
			image += " src=\"" + small + "\""

		} else {

			// use the full image as the defaults
			image += " src=\"" + fullSizeImagePath + "\""

		}

		image += fmt.Sprintf(` alt="%s" />`, imageTitle)

		imagelinks[index] = fmt.Sprintf(`<a href="%s" title="%s">%s</a>`, fullSizeImagePath, imageTitle, image)
	}

	return imagelinks
}

func (converter *FilePreviewExtension) getThumbnailPath(fileRoute route.Route, dimensions thumbnail.ThumbDimension) (thumbnailPath string, thumbnailAvailable bool) {

	// assemble to the full image route
	fullRoute, err := route.Combine(converter.base, fileRoute)
	if err != nil {
		panic(fmt.Sprintf("Cannot combine routes %q and %q.", converter.base, fileRoute))
	}

	// check if there are thumbs for the supplied file route
	thumbs, exists := converter.thumbnailIndex.GetThumbs(fullRoute.Value())
	if !exists {
		return "", false // return the full-size image path
	}

	// lookup thumb by size
	thumb, exists := thumbs.GetThumbBySize(dimensions)
	if !exists {
		return "", false // return the full-size image path

	}

	return converter.getImagePath(thumb.ThumbRoute()), true
}

func (converter *FilePreviewExtension) getImagePath(fileRoute route.Route) string {
	return converter.pathProvider.Path(fileRoute.Value())
}
<|endoftext|>


<commit_before>package chaosmonkey

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

type eventParams struct {
	EventType string `json:"eventType"`
	GroupType string `json:"groupType"`
	GroupName string `json:"groupName"`
	ChaosType string `json:"chaosType,omitempty"`
}

type Event struct {
	*eventParams

	MonkeyType string `json:"monkeyType"`
	EventID    string `json:"eventId"`
	EventTime  int64  `json:"eventTime"`
	Region     string `json:"region"`
}

type Config struct {
	Endpoint string
	Username string
	Password string

	HTTPClient *http.Client
}

type Client struct {
	config *Config
}

func (c *Config) ReadEnvironment() error {
	return nil
}

func NewClient(c *Config) (*Client, error) {
	if c.HTTPClient == nil {
		c.HTTPClient = &http.Client{
			Timeout: 15 * time.Second,
		}
	}
	return &Client{config: c}, nil
}

func (c *Client) TriggerEvent(groupName, chaosType string) (*Event, error) {
	params := eventParams{
		EventType: "CHAOS_TERMINATION",
		GroupType: "ASG",
		GroupName: groupName,
		ChaosType: chaosType,
	}
	payload, err := json.Marshal(&params)
	if err != nil {
		return nil, err
	}

	url := c.config.Endpoint + "/simianarmy/api/v1/chaos"
	resp, err := c.sendRequest("POST", url, bytes.NewReader(payload))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, decodeError(resp)
	}

	var event Event
	if err := json.NewDecoder(resp.Body).Decode(&event); err != nil {
		return nil, err
	}

	return &event, nil
}

func (c *Client) GetEvents() ([]Event, error) {
	url := c.config.Endpoint + "/simianarmy/api/v1/chaos"
	resp, err := c.sendRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, decodeError(resp)
	}

	var events []Event
	if err := json.NewDecoder(resp.Body).Decode(&events); err != nil {
		return nil, err
	}

	return events, nil
}

func (c *Client) sendRequest(method, url string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Add("User-Agent", "havoc")

	if c.config.Username != "" && c.config.Password != "" {
		req.SetBasicAuth(c.config.Username, c.config.Password)
	}

	return c.config.HTTPClient.Do(req)
}

func decodeError(resp *http.Response) error {
	var m struct {
		Message string `json:"message"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&m); err == nil && m.Message != "" {
		return fmt.Errorf("%s", m.Message)
	}
	return fmt.Errorf("%s", resp.Status)
}
<commit_msg>Remove superfluous headers<commit_after>package chaosmonkey

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

type eventParams struct {
	EventType string `json:"eventType"`
	GroupType string `json:"groupType"`
	GroupName string `json:"groupName"`
	ChaosType string `json:"chaosType,omitempty"`
}

type Event struct {
	*eventParams

	MonkeyType string `json:"monkeyType"`
	EventID    string `json:"eventId"`
	EventTime  int64  `json:"eventTime"`
	Region     string `json:"region"`
}

type Config struct {
	Endpoint string
	Username string
	Password string

	HTTPClient *http.Client
}

type Client struct {
	config *Config
}

func (c *Config) ReadEnvironment() error {
	return nil
}

func NewClient(c *Config) (*Client, error) {
	if c.HTTPClient == nil {
		c.HTTPClient = &http.Client{
			Timeout: 15 * time.Second,
		}
	}
	return &Client{config: c}, nil
}

func (c *Client) TriggerEvent(groupName, chaosType string) (*Event, error) {
	params := eventParams{
		EventType: "CHAOS_TERMINATION",
		GroupType: "ASG",
		GroupName: groupName,
		ChaosType: chaosType,
	}
	payload, err := json.Marshal(&params)
	if err != nil {
		return nil, err
	}

	url := c.config.Endpoint + "/simianarmy/api/v1/chaos"
	resp, err := c.sendRequest("POST", url, bytes.NewReader(payload))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, decodeError(resp)
	}

	var event Event
	if err := json.NewDecoder(resp.Body).Decode(&event); err != nil {
		return nil, err
	}

	return &event, nil
}

func (c *Client) GetEvents() ([]Event, error) {
	url := c.config.Endpoint + "/simianarmy/api/v1/chaos"
	resp, err := c.sendRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, decodeError(resp)
	}

	var events []Event
	if err := json.NewDecoder(resp.Body).Decode(&events); err != nil {
		return nil, err
	}

	return events, nil
}

func (c *Client) sendRequest(method, url string, body io.Reader) (*http.Response, error) {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return nil, err
	}
	if c.config.Username != "" && c.config.Password != "" {
		req.SetBasicAuth(c.config.Username, c.config.Password)
	}
	return c.config.HTTPClient.Do(req)
}

func decodeError(resp *http.Response) error {
	var m struct {
		Message string `json:"message"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&m); err == nil && m.Message != "" {
		return fmt.Errorf("%s", m.Message)
	}
	return fmt.Errorf("%s", resp.Status)
}
<|endoftext|>


<commit_before>package hsm

import "container/list"

type HSMType uint32

// The types of HSM.
const (
    HSMTypeStd HSMType = iota
    HSMTypeUser
)

// HSM represents the interface that every state machine class
// should implement.
type HSM interface {
    // Returns the type of this hsm
    Type() HSMType

    // Runs the initialization of this hsm
    Init()
    // Dispatch event to state machine
    Dispatch(event Event)

    // Returns current state of this hsm
    GetState() State
    // Tests whether this hsm is in specified state. It works no matter
    // stateID is in any level as a parent state of current state.
    IsIn(stateID string) bool

    // Transfer to specified target state during state intialization.
    QInit(targetStateID string)
    // Transfer to specified target state as normal state transfer.
    QTran(targetStateID string)
}

// StdHSM is the default HSM implementation.
// Any HSM derived could reuse it as anonymous field.
type StdHSM struct {
    // The type of concrete HSM
    MyType HSMType
    // The state that handles event(it could Super(), Super().Super(), ...)
    // of current state
    SourceState State
    // The current state(it could be child, child's child of SourceState)
    State State
    // The global map for all states and their names in this state machine
    StateTable map[string]State
}

// Constructor for StdHSM. The initial must set top as parent state.
func NewStdHSM(myType HSMType, top, initial State) *StdHSM {
    AssertEqual(TopStateID, top.ID())
    AssertEqual(InitialStateID, initial.ID())
    hsm := &StdHSM{
        MyType:      myType,
        SourceState: initial,
        State:       top,
        StateTable:  make(map[string]State),
    }
    hsm.StateTable[top.ID()] = top
    // setup state table
    hsm.setupStateTable()
    return hsm
}

func (self *StdHSM) Type() HSMType {
    return self.MyType
}

// setupStateTable() initializes StateTable properly
// with all states and their names.
func (self *StdHSM) setupStateTable() {
    for traverse_queue := self.State.Children(); len(traverse_queue) != 0; {
        state := traverse_queue[0]
        traverse_queue = traverse_queue[1:]
        _, ok := self.StateTable[state.ID()]
        AssertFalse(ok)
        self.StateTable[state.ID()] = state
        children := state.Children()
        for _, state := range children {
            traverse_queue = append(traverse_queue, state)
        }
    }
}

// Init() is part of interface HSM.
func (self *StdHSM) Init() {
    self.Init2(self, StdEvents[EventInit])
}

// Init2() is a helper function to initialize the whole state machine.
// All state initialization actions started from initial state
// would be triggered.
func (self *StdHSM) Init2(hsm HSM, event Event) {
    // health check
    AssertNotEqual(nil, self.State)
    AssertNotEqual(nil, self.SourceState)
    // check HSM is not executed yet
    AssertEqual(self.StateTable[TopStateID], self.State)
    AssertEqual(self.StateTable[InitialStateID], self.SourceState)
    // save State in a temporary
    s := self.State
    // top-most initial transition
    Trigger(hsm, self.SourceState, event)
    // initial transition must go *one* level deep
    AssertEqual(s, Trigger(hsm, self.State, StdEvents[EventEmpty]))
    // update the termporary
    s = self.State
    // enter the state
    Trigger(hsm, s, StdEvents[EventEntry])
    for Trigger(hsm, s, StdEvents[EventInit]) == nil { // init handled?
        // initial transition must go *one* level deep
        AssertEqual(s, Trigger(hsm, self.State, StdEvents[EventEmpty]))
        s = self.State
        // enter the substate
        Trigger(hsm, s, StdEvents[EventEntry])
    }
    // we are in well-initialized state now
}

// Dispatch() is part of interface HSM.
func (self *StdHSM) Dispatch(event Event) {
    self.Dispatch2(self, event)
}

// Dispatch2() is a helper function to dispatch event to the concrete HSM.
func (self *StdHSM) Dispatch2(hsm HSM, event Event) {
    // Use `SourceState' to record the state which handle the event indeed(which
    // could be super, super-super, ... state).
    // `State' would stay unchange pointing at the current(most concrete) state.
    for self.SourceState = self.State; self.SourceState != nil; {
        self.SourceState = Trigger(hsm, self.SourceState, event)
    }
}

// GetState() is part of interface HSM.
func (self *StdHSM) GetState() State {
    return self.State
}

// IsIn() is part of interface HSM.
func (self *StdHSM) IsIn(stateID string) bool {
    state := self.StateTable[stateID]
    return self.isIn(state)
}

// isIn() is a helper function for IsIn().
// It will traverse from current state up to top state to find
// the specified state, util it finds a match or reachs top with failture.
func (self *StdHSM) isIn(state State) bool {
    // nagivate from current state up to all super state and
    // try to find specified `state'
    for s := self.State; s != nil; s = Trigger(self, self.State, StdEvents[EventEmpty]) {
        if s == state {
            // a match is found
            return true
        }
    }
    // no match found
    return false
}

// QInit() is part of interface HSM.
func (self *StdHSM) QInit(targetStateID string) {
    target := self.LookupState(targetStateID)
    self.qinit(target)
}

// qinit() is a helper function for QInit().
func (self *StdHSM) qinit(state State) {
    self.State = state
}

// QTran() is part of interface HSM.
func (self *StdHSM) QTran(targetStateID string) {
    target := self.LookupState(targetStateID)
    self.QTran2(self, target)
}

// LookupState() search the specified state in state/name map.
func (self *StdHSM) LookupState(targetStateID string) State {
    AssertNotEqual(TopStateID, targetStateID)
    target, ok := self.StateTable[targetStateID]
    AssertTrue(ok)
    return target
}

// QTran2() is a helper function for QTran().
// It's separated from QTran() in order to deliver the concrete HSM
// (which is the first arguemnt of QTran2()) rather than just
// the embedded StdHSM to the state transfer procedure.
func (self *StdHSM) QTran2(hsm HSM, target State) {
    var p, q, s State
    for s := self.State; s != self.SourceState; {
        // we are about to dereference `s'
        AssertNotEqual(nil, s)
        t := Trigger(hsm, s, StdEvents[EventExit])
        if t != nil {
            s = t
        } else {
            s = Trigger(hsm, s, StdEvents[EventEmpty])
        }
    }

    stateChain := list.New()
    stateChain.Init()

    stateChain.PushBack(nil)
    stateChain.PushBack(target)

    // (a) check `SourceState' == `target' (transition to self)
    if self.SourceState == target {
        Trigger(hsm, self.SourceState, StdEvents[EventExit])
        goto inLCA
    }
    // (b) check `SourceState' == `target.Super()'
    p = Trigger(hsm, target, StdEvents[EventEmpty])
    if self.SourceState == p {
        goto inLCA
    }
    // (c) check `SourceState.Super()' == `target.Super()' (most common)
    q = Trigger(hsm, self.SourceState, StdEvents[EventEmpty])
    if q == p {
        Trigger(hsm, self.SourceState, StdEvents[EventExit])
        goto inLCA
    }
    // (d) check `SourceState.Super()' == `target'
    if q == target {
        Trigger(hsm, self.SourceState, StdEvents[EventExit])
        stateChain.Remove(stateChain.Back())
        goto inLCA
    }
    // (e) check rest of `SourceState' == `target.Super().Super()...'  hierarchy
    stateChain.PushBack(p)
    s = Trigger(hsm, p, StdEvents[EventEmpty])
    for s != nil {
        if self.SourceState == s {
            goto inLCA
        }
        stateChain.PushBack(s)
        s = Trigger(hsm, s, StdEvents[EventEmpty])
    }
    // exit source state
    Trigger(hsm, self.SourceState, StdEvents[EventExit])
    // (f) check rest of `SourceState.Super()' == `target.Super().Super()...'
    for lca := stateChain.Back(); lca != nil; lca = lca.Prev() {
        if q == lca.Value {
            // do not enter the LCA
            stateChain = ListTruncate(stateChain, lca)
            goto inLCA
        }
    }
    // (g) check each `SourceState.Super().Super()...' for target...
    for s = q; s != nil; s = Trigger(hsm, s, StdEvents[EventEmpty]) {
        for lca := stateChain.Back(); lca != nil; lca = lca.Prev() {
            if s == lca.Value {
                stateChain = ListTruncate(stateChain, lca)
                goto inLCA
            }
        }
        Trigger(hsm, s, StdEvents[EventExit])
    }
    // malformed HSM
    AssertTrue(false)
inLCA: // now we are in the LCA of `SourceState' and `target'
    // retrace the entry path in reverse order
    for e := stateChain.Back(); e != nil && e.Value != nil; {
        s, ok := e.Value.(State)
        AssertEqual(true, ok)
        Trigger(hsm, s, StdEvents[EventEntry]) // enter `s' state
        stateChain.Remove(stateChain.Back())
        e = stateChain.Back()
    }
    // update current state
    self.State = target
    for Trigger(hsm, target, StdEvents[EventInit]) == nil {
        // initial transition must go *one* level deep
        AssertEqual(target, Trigger(hsm, self.State, StdEvents[EventEmpty]))
        target = self.State
        Trigger(hsm, target, StdEvents[EventEntry])
    }
}
<commit_msg>add QTranOnEvent function<commit_after>package hsm

import "container/list"

type HSMType uint32

// The types of HSM.
const (
    HSMTypeStd HSMType = iota
    HSMTypeUser
)

// HSM represents the interface that every state machine class
// should implement.
type HSM interface {
    // Returns the type of this hsm
    Type() HSMType

    // Runs the initialization of this hsm
    Init()
    // Dispatch event to state machine
    Dispatch(event Event)

    // Returns current state of this hsm
    GetState() State
    // Tests whether this hsm is in specified state. It works no matter
    // stateID is in any level as a parent state of current state.
    IsIn(stateID string) bool

    // Transfer to specified target state during state intialization.
    QInit(targetStateID string)
    // Transfer to specified target state as normal state transfer.
    QTran(targetStateID string)
    // Transfer to specified target state as normal state transfer,
    // along with specified event dispatched during transfer procedure.
    QTranOnEvent(targetStateID string, event Event)
}

// StdHSM is the default HSM implementation.
// Any HSM derived could reuse it as anonymous field.
type StdHSM struct {
    // The type of concrete HSM
    MyType HSMType
    // The state that handles event(it could Super(), Super().Super(), ...)
    // of current state
    SourceState State
    // The current state(it could be child, child's child of SourceState)
    State State
    // The global map for all states and their names in this state machine
    StateTable map[string]State
}

// Constructor for StdHSM. The initial must set top as parent state.
func NewStdHSM(myType HSMType, top, initial State) *StdHSM {
    AssertEqual(TopStateID, top.ID())
    AssertEqual(InitialStateID, initial.ID())
    hsm := &StdHSM{
        MyType:      myType,
        SourceState: initial,
        State:       top,
        StateTable:  make(map[string]State),
    }
    hsm.StateTable[top.ID()] = top
    // setup state table
    hsm.setupStateTable()
    return hsm
}

func (self *StdHSM) Type() HSMType {
    return self.MyType
}

// setupStateTable() initializes StateTable properly
// with all states and their names.
func (self *StdHSM) setupStateTable() {
    for traverse_queue := self.State.Children(); len(traverse_queue) != 0; {
        state := traverse_queue[0]
        traverse_queue = traverse_queue[1:]
        _, ok := self.StateTable[state.ID()]
        AssertFalse(ok)
        self.StateTable[state.ID()] = state
        children := state.Children()
        for _, state := range children {
            traverse_queue = append(traverse_queue, state)
        }
    }
}

// Init() is part of interface HSM.
func (self *StdHSM) Init() {
    self.Init2(self, StdEvents[EventInit])
}

// Init2() is a helper function to initialize the whole state machine.
// All state initialization actions started from initial state
// would be triggered.
func (self *StdHSM) Init2(hsm HSM, event Event) {
    // health check
    AssertNotEqual(nil, self.State)
    AssertNotEqual(nil, self.SourceState)
    // check HSM is not executed yet
    AssertEqual(self.StateTable[TopStateID], self.State)
    AssertEqual(self.StateTable[InitialStateID], self.SourceState)
    // save State in a temporary
    s := self.State
    // top-most initial transition
    Trigger(hsm, self.SourceState, event)
    // initial transition must go *one* level deep
    AssertEqual(s, Trigger(hsm, self.State, StdEvents[EventEmpty]))
    // update the termporary
    s = self.State
    // enter the state
    Trigger(hsm, s, StdEvents[EventEntry])
    for Trigger(hsm, s, StdEvents[EventInit]) == nil { // init handled?
        // initial transition must go *one* level deep
        AssertEqual(s, Trigger(hsm, self.State, StdEvents[EventEmpty]))
        s = self.State
        // enter the substate
        Trigger(hsm, s, StdEvents[EventEntry])
    }
    // we are in well-initialized state now
}

// Dispatch() is part of interface HSM.
func (self *StdHSM) Dispatch(event Event) {
    self.Dispatch2(self, event)
}

// Dispatch2() is a helper function to dispatch event to the concrete HSM.
func (self *StdHSM) Dispatch2(hsm HSM, event Event) {
    // Use `SourceState' to record the state which handle the event indeed(which
    // could be super, super-super, ... state).
    // `State' would stay unchange pointing at the current(most concrete) state.
    for self.SourceState = self.State; self.SourceState != nil; {
        self.SourceState = Trigger(hsm, self.SourceState, event)
    }
}

// GetState() is part of interface HSM.
func (self *StdHSM) GetState() State {
    return self.State
}

// IsIn() is part of interface HSM.
func (self *StdHSM) IsIn(stateID string) bool {
    state := self.StateTable[stateID]
    return self.isIn(state)
}

// isIn() is a helper function for IsIn().
// It will traverse from current state up to top state to find
// the specified state, util it finds a match or reachs top with failture.
func (self *StdHSM) isIn(state State) bool {
    // nagivate from current state up to all super state and
    // try to find specified `state'
    s := self.State
    for ; s != nil; s = Trigger(self, self.State, StdEvents[EventEmpty]) {
        if s == state {
            // a match is found
            return true
        }
    }
    // no match found
    return false
}

// QInit() is part of interface HSM.
func (self *StdHSM) QInit(targetStateID string) {
    target := self.LookupState(targetStateID)
    self.qinit(target)
}

// qinit() is a helper function for QInit().
func (self *StdHSM) qinit(state State) {
    self.State = state
}

// QTran() is part of interface HSM.
func (self *StdHSM) QTran(targetStateID string) {
    target := self.LookupState(targetStateID)
    self.QTranHSM(self, target)
}

// LookupState() search the specified state in state/name map.
func (self *StdHSM) LookupState(targetStateID string) State {
    AssertNotEqual(TopStateID, targetStateID)
    target, ok := self.StateTable[targetStateID]
    AssertTrue(ok)
    return target
}

// QTran2() is a helper function for QTran().
// It's separated from QTran() in order to deliver the concrete HSM
// (which is the first arguemnt of QTran2()) rather than just
// the embedded StdHSM to the state transfer procedure.
func (self *StdHSM) QTranHSM(hsm HSM, target State) {
    self.QTranHSMOnEvents(
        hsm,
        target,
        StdEvents[EventEntry],
        StdEvents[EventInit],
        StdEvents[EventExit])
}

// QTranOnEvent() is a variant function of QTran().
// Instead of dispatching the default events of
// `EventEntry'/`EventInit'/`EventExit', this function would dispatch
// the given event along the state transfer procedure.
func (self *StdHSM) QTranOnEvent(targetStateID string, event Event) {
    target := self.LookupState(targetStateID)
    self.QTranHSMOnEvent(self, target, event)
}

func (self *StdHSM) QTranHSMOnEvent(hsm HSM, target State, event Event) {
    self.QTranHSMOnEvents(hsm, target, event, event, event)
}

// QTranOnEvents() is the implementation of QTran* functions.
func (self *StdHSM) QTranHSMOnEvents(
    hsm HSM, target State, entryEvent, initEvent, exitEvent Event) {

    var p, q, s State
    for s := self.State; s != self.SourceState; {
        // we are about to dereference `s'
        AssertNotEqual(nil, s)
        t := Trigger(hsm, s, exitEvent)
        if t != nil {
            s = t
        } else {
            s = Trigger(hsm, s, StdEvents[EventEmpty])
        }
    }

    stateChain := list.New()
    stateChain.Init()

    stateChain.PushBack(nil)
    stateChain.PushBack(target)

    // (a) check `SourceState' == `target' (transition to self)
    if self.SourceState == target {
        Trigger(hsm, self.SourceState, exitEvent)
        goto inLCA
    }
    // (b) check `SourceState' == `target.Super()'
    p = Trigger(hsm, target, StdEvents[EventEmpty])
    if self.SourceState == p {
        goto inLCA
    }
    // (c) check `SourceState.Super()' == `target.Super()' (most common)
    q = Trigger(hsm, self.SourceState, StdEvents[EventEmpty])
    if q == p {
        Trigger(hsm, self.SourceState, exitEvent)
        goto inLCA
    }
    // (d) check `SourceState.Super()' == `target'
    if q == target {
        Trigger(hsm, self.SourceState, exitEvent)
        stateChain.Remove(stateChain.Back())
        goto inLCA
    }
    // (e) check rest of `SourceState' == `target.Super().Super()...'  hierarchy
    stateChain.PushBack(p)
    s = Trigger(hsm, p, StdEvents[EventEmpty])
    for s != nil {
        if self.SourceState == s {
            goto inLCA
        }
        stateChain.PushBack(s)
        s = Trigger(hsm, s, StdEvents[EventEmpty])
    }
    // exit source state
    Trigger(hsm, self.SourceState, exitEvent)
    // (f) check rest of `SourceState.Super()' == `target.Super().Super()...'
    for lca := stateChain.Back(); lca != nil; lca = lca.Prev() {
        if q == lca.Value {
            // do not enter the LCA
            stateChain = ListTruncate(stateChain, lca)
            goto inLCA
        }
    }
    // (g) check each `SourceState.Super().Super()...' for target...
    for s = q; s != nil; s = Trigger(hsm, s, StdEvents[EventEmpty]) {
        for lca := stateChain.Back(); lca != nil; lca = lca.Prev() {
            if s == lca.Value {
                stateChain = ListTruncate(stateChain, lca)
                goto inLCA
            }
        }
        Trigger(hsm, s, exitEvent)
    }
    // malformed HSM
    AssertTrue(false)
inLCA: // now we are in the LCA of `SourceState' and `target'
    // retrace the entry path in reverse order
    for e := stateChain.Back(); e != nil && e.Value != nil; {
        s, ok := e.Value.(State)
        AssertEqual(true, ok)
        Trigger(hsm, s, entryEvent) // enter `s' state
        stateChain.Remove(stateChain.Back())
        e = stateChain.Back()
    }
    // update current state
    self.State = target
    for Trigger(hsm, target, initEvent) == nil {
        // initial transition must go *one* level deep
        AssertEqual(target, Trigger(hsm, self.State, StdEvents[EventEmpty]))
        target = self.State
        Trigger(hsm, target, entryEvent)
    }
}
<|endoftext|>


<commit_before>// Package xmux is a net/context aware, tree based high performance HTTP request
// multiplexer forked from httprouter.
//
// A trivial example is:
//
//  package main
//
//  import (
//      "fmt"
//      "net/http"
//      "log"
//
//      "github.com/rs/xhandler"
//      "github.com/rs/xmux"
//      "golang.org/x/net/context"
//  )
//
//  func Index(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, "hello, %s!\n", xmux.Param(ctx, "name"))
//  }
//
//  func main() {
//      mux := xmux.New()
//      mux.GET("/", Index)
//      mux.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":8080", xhandler.New(context.Background(), mux)))
//  }
//
// The muxer matches incoming requests by the request method and the path.
// If a handle is registered for this path and method, the router delegates the
// request to that function.
// For the methods GET, POST, PUT, PATCH and DELETE shortcut functions exist to
// register handlers, for all other methods mux.Handle can be used.
//
// The registered path, against which the muxer matches incoming requests, can
// contain two types of parameters:
//  Syntax    Type
//  :name     named parameter
//  *name     catch-all parameter
//
// Named parameters are dynamic path segments. They match anything until the
// next '/' or the path end:
//  Path: /blog/:category/:post
//
//  Requests:
//   /blog/go/request-routers            match: category="go", post="request-routers"
//   /blog/go/request-routers/           no match, but the router would redirect
//   /blog/go/                           no match
//   /blog/go/request-routers/comments   no match
//
// Catch-all parameters match anything until the path end, including the
// directory index (the '/' before the catch-all). Since they match anything
// until the end, catch-all parameters must always be the final path element.
//  Path: /files/*filepath
//
//  Requests:
//   /files/                             match: filepath="/"
//   /files/LICENSE                      match: filepath="/LICENSE"
//   /files/templates/article.html       match: filepath="/templates/article.html"
//   /files                              no match, but the router would redirect
//
// The value of parameters is saved as aParams type saved into the context.
// Parameters can be retrieved by name using xhandler.Param(ctx, name) method:
//  user := xmux.Param(ctx, "user") // defined by :user or *user
package xmux

import (
	"net/http"
	"sort"
	"strings"

	"github.com/rs/xhandler"

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

// Mux is a xhandler.HandlerC which can be used to dispatch requests to different
// handler functions via configurable routes
type Mux struct {
	trees map[string]*node

	// Enables automatic redirection if the current route can't be matched but a
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301 for GET requests
	// and 307 for all other request methods.
	RedirectTrailingSlash bool

	// If enabled, the router tries to fix the current request path, if no
	// handle is registered for it.
	// First superfluous path elements like ../ or // are removed.
	// Afterwards the router does a case-insensitive lookup of the cleaned path.
	// If a handle can be found for this route, the router makes a redirection
	// to the corrected path with status code 301 for GET requests and 307 for
	// all other request methods.
	// For example /FOO and /..//Foo could be redirected to /foo.
	// RedirectTrailingSlash is independent of this option.
	RedirectFixedPath bool

	// If enabled, the router checks if another method is allowed for the
	// current route, if the current request can not be routed.
	// If this is the case, the request is answered with 'Method Not Allowed'
	// and HTTP status code 405.
	// If no other Method is allowed, the request is delegated to the NotFound
	// handler.
	HandleMethodNotAllowed bool

	// Configurable http.Handler which is called when no matching route is
	// found. If it is not set, http.Error with http.StatusNotFound is used.
	NotFound xhandler.HandlerC

	// Configurable http.Handler which is called when a request
	// cannot be routed and HandleMethodNotAllowed is true.
	// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
	MethodNotAllowed xhandler.HandlerC

	// Function to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// 500 (Internal Server Error).
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(context.Context, http.ResponseWriter, *http.Request, interface{})
}

// ParamHolder holds URL parameters.
type ParamHolder struct {
	params []param
}

type param struct {
	key   string
	value string
}

// Get returns the value of the first Param which key matches the given name.
// If no matching Param is found, an empty string is returned.
func (ps ParamHolder) Get(name string) string {
	for i := range ps.params {
		if ps.params[i].key == name {
			return ps.params[i].value
		}
	}
	return ""
}

type key int

const paramsKey key = iota

var emptyParams = ParamHolder{}

func newParamContext(ctx context.Context, p ParamHolder) context.Context {
	return context.WithValue(ctx, paramsKey, p)
}

// Params returns URL parameters stored in context
func Params(ctx context.Context) ParamHolder {
	if ctx == nil {
		return emptyParams
	}
	if p, ok := ctx.Value(paramsKey).(ParamHolder); ok {
		return p
	}
	return emptyParams
}

// Param picks one URL parameters stored in context by its name.
//
// This is a shortcut for:
//   xmux.Params(ctx).Get("name")
func Param(ctx context.Context, name string) string {
	return Params(ctx).Get(name)
}

// New returns a new muxer instance
func New() *Mux {
	return &Mux{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
	}
}

// NewGroup creates a new routes group with the provided path prefix.
// All routes added to the returned group will have the path prepended.
func (mux *Mux) NewGroup(path string) *Group {
	return newRouteGroup(mux, path)
}

// GET is a shortcut for mux.Handle("GET", path, handler)
func (mux *Mux) GET(path string, handler xhandler.HandlerC) {
	mux.HandleC("GET", path, handler)
}

// HEAD is a shortcut for mux.Handle("HEAD", path, handler)
func (mux *Mux) HEAD(path string, handler xhandler.HandlerC) {
	mux.HandleC("HEAD", path, handler)
}

// OPTIONS is a shortcut for mux.Handle("OPTIONS", path, handler)
func (mux *Mux) OPTIONS(path string, handler xhandler.HandlerC) {
	mux.HandleC("OPTIONS", path, handler)
}

// POST is a shortcut for mux.Handle("POST", path, handler)
func (mux *Mux) POST(path string, handler xhandler.HandlerC) {
	mux.HandleC("POST", path, handler)
}

// PUT is a shortcut for mux.Handle("PUT", path, handler)
func (mux *Mux) PUT(path string, handler xhandler.HandlerC) {
	mux.HandleC("PUT", path, handler)
}

// PATCH is a shortcut for mux.Handle("PATCH", path, handler)
func (mux *Mux) PATCH(path string, handler xhandler.HandlerC) {
	mux.HandleC("PATCH", path, handler)
}

// DELETE is a shortcut for mux.Handle("DELETE", path, handler)
func (mux *Mux) DELETE(path string, handler xhandler.HandlerC) {
	mux.HandleC("DELETE", path, handler)
}

// HandleC registers a net/context aware request handler with the given
// path and method.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (mux *Mux) HandleC(method, path string, handler xhandler.HandlerC) {
	if path[0] != '/' {
		panic("path must begin with '/' in path '" + path + "'")
	}

	if mux.trees == nil {
		mux.trees = make(map[string]*node)
	}

	root := mux.trees[method]
	if root == nil {
		root = new(node)
		mux.trees[method] = root
	}

	root.addRoute(path, handler)
}

// Handle regiester a standard http.Handler request handler with the given
// path and method. With this adapter, your handler won't have access to the
// context and thus won't work with URL parameters.
func (mux *Mux) Handle(method, path string, handler http.Handler) {
	mux.HandleC(method, path,
		xhandler.HandlerFuncC(func(_ context.Context, w http.ResponseWriter, r *http.Request) {
			handler.ServeHTTP(w, r)
		}),
	)
}

// HandleFunc regiester a standard http.HandlerFunc request handler with the given
// path and method. With this adapter, your handler won't have access to the
// context and thus won't work with URL parameters.
func (mux *Mux) HandleFunc(method, path string, handler http.HandlerFunc) {
	mux.HandleC(method, path,
		xhandler.HandlerFuncC(func(_ context.Context, w http.ResponseWriter, r *http.Request) {
			handler(w, r)
		}),
	)
}

func (mux *Mux) recv(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if rcv := recover(); rcv != nil {
		mux.PanicHandler(ctx, w, r, rcv)
	}
}

// Lookup allows the manual lookup of a method + path combo.
// This is e.g. useful to build a framework around this router.
// If the path was found, it returns the handle function and the path parameter
// values. Otherwise the third return value indicates whether a redirection to
// the same path with an extra / without the trailing slash should be performed.
func (mux *Mux) Lookup(method, path string) (xhandler.HandlerC, ParamHolder, bool) {
	if root := mux.trees[method]; root != nil {
		return root.getValue(path)
	}
	return nil, emptyParams, false
}

// ServeHTTPC implements xhandler.HandlerC interface
func (mux *Mux) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if mux.PanicHandler != nil {
		defer mux.recv(ctx, w, r)
	}

	if root := mux.trees[r.Method]; root != nil {
		path := r.URL.Path

		if handler, p, tsr := root.getValue(path); handler != nil {
			if len(p.params) > 0 {
				ctx = newParamContext(ctx, p)
			}
			handler.ServeHTTPC(ctx, w, r)
			return
		} else if r.Method != "CONNECT" && path != "/" {
			code := 301 // Permanent redirect, request with GET method
			if r.Method != "GET" {
				// Temporary redirect, request with same method
				// As of Go 1.3, Go does not support status code 308.
				code = 307
			}

			if tsr && mux.RedirectTrailingSlash {
				if len(path) > 1 && path[len(path)-1] == '/' {
					r.URL.Path = path[:len(path)-1]
				} else {
					r.URL.Path = path + "/"
				}
				http.Redirect(w, r, r.URL.String(), code)
				return
			}

			// Try to fix the request path
			if mux.RedirectFixedPath {
				fixedPath, found := root.findCaseInsensitivePath(
					CleanPath(path),
					mux.RedirectTrailingSlash,
				)
				if found {
					r.URL.Path = string(fixedPath)
					http.Redirect(w, r, r.URL.String(), code)
					return
				}
			}
		}
	}

	// Handle 405
	if mux.HandleMethodNotAllowed {
		methods := []string{}
		for method := range mux.trees {
			// Skip the requested method - we already tried this one
			if method == r.Method {
				continue
			}

			handler, _, _ := mux.trees[method].getValue(r.URL.Path)
			if handler != nil {
				methods = append(methods, method)
			}
		}
		if len(methods) > 0 && methods[0] != "OPTIONS" {
			sort.Strings(methods)
			w.Header().Set("Allow", strings.Join(methods, ", "))
			if mux.MethodNotAllowed != nil {
				mux.MethodNotAllowed.ServeHTTPC(ctx, w, r)
			} else {
				http.Error(w,
					http.StatusText(http.StatusMethodNotAllowed),
					http.StatusMethodNotAllowed,
				)
			}
			return
		}
	}

	// Handle 404
	if mux.NotFound != nil {
		mux.NotFound.ServeHTTPC(ctx, w, r)
	} else {
		http.Error(w, "404 page not found", http.StatusNotFound)
	}
}
<commit_msg>Use net/http status constants<commit_after>// Package xmux is a net/context aware, tree based high performance HTTP request
// multiplexer forked from httprouter.
//
// A trivial example is:
//
//  package main
//
//  import (
//      "fmt"
//      "net/http"
//      "log"
//
//      "github.com/rs/xhandler"
//      "github.com/rs/xmux"
//      "golang.org/x/net/context"
//  )
//
//  func Index(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//      fmt.Fprint(w, "Welcome!\n")
//  }
//
//  func Hello(ctx context.Context, w http.ResponseWriter, r *http.Request) {
//      fmt.Fprintf(w, "hello, %s!\n", xmux.Param(ctx, "name"))
//  }
//
//  func main() {
//      mux := xmux.New()
//      mux.GET("/", Index)
//      mux.GET("/hello/:name", Hello)
//
//      log.Fatal(http.ListenAndServe(":8080", xhandler.New(context.Background(), mux)))
//  }
//
// The muxer matches incoming requests by the request method and the path.
// If a handle is registered for this path and method, the router delegates the
// request to that function.
// For the methods GET, POST, PUT, PATCH and DELETE shortcut functions exist to
// register handlers, for all other methods mux.Handle can be used.
//
// The registered path, against which the muxer matches incoming requests, can
// contain two types of parameters:
//  Syntax    Type
//  :name     named parameter
//  *name     catch-all parameter
//
// Named parameters are dynamic path segments. They match anything until the
// next '/' or the path end:
//  Path: /blog/:category/:post
//
//  Requests:
//   /blog/go/request-routers            match: category="go", post="request-routers"
//   /blog/go/request-routers/           no match, but the router would redirect
//   /blog/go/                           no match
//   /blog/go/request-routers/comments   no match
//
// Catch-all parameters match anything until the path end, including the
// directory index (the '/' before the catch-all). Since they match anything
// until the end, catch-all parameters must always be the final path element.
//  Path: /files/*filepath
//
//  Requests:
//   /files/                             match: filepath="/"
//   /files/LICENSE                      match: filepath="/LICENSE"
//   /files/templates/article.html       match: filepath="/templates/article.html"
//   /files                              no match, but the router would redirect
//
// The value of parameters is saved as aParams type saved into the context.
// Parameters can be retrieved by name using xhandler.Param(ctx, name) method:
//  user := xmux.Param(ctx, "user") // defined by :user or *user
package xmux

import (
	"net/http"
	"sort"
	"strings"

	"github.com/rs/xhandler"

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

// Mux is a xhandler.HandlerC which can be used to dispatch requests to different
// handler functions via configurable routes
type Mux struct {
	trees map[string]*node

	// Enables automatic redirection if the current route can't be matched but a
	// handler for the path with (without) the trailing slash exists.
	// For example if /foo/ is requested but a route only exists for /foo, the
	// client is redirected to /foo with http status code 301 for GET requests
	// and 307 for all other request methods.
	RedirectTrailingSlash bool

	// If enabled, the router tries to fix the current request path, if no
	// handle is registered for it.
	// First superfluous path elements like ../ or // are removed.
	// Afterwards the router does a case-insensitive lookup of the cleaned path.
	// If a handle can be found for this route, the router makes a redirection
	// to the corrected path with status code 301 for GET requests and 307 for
	// all other request methods.
	// For example /FOO and /..//Foo could be redirected to /foo.
	// RedirectTrailingSlash is independent of this option.
	RedirectFixedPath bool

	// If enabled, the router checks if another method is allowed for the
	// current route, if the current request can not be routed.
	// If this is the case, the request is answered with 'Method Not Allowed'
	// and HTTP status code 405.
	// If no other Method is allowed, the request is delegated to the NotFound
	// handler.
	HandleMethodNotAllowed bool

	// Configurable http.Handler which is called when no matching route is
	// found. If it is not set, http.Error with http.StatusNotFound is used.
	NotFound xhandler.HandlerC

	// Configurable http.Handler which is called when a request
	// cannot be routed and HandleMethodNotAllowed is true.
	// If it is not set, http.Error with http.StatusMethodNotAllowed is used.
	MethodNotAllowed xhandler.HandlerC

	// Function to handle panics recovered from http handlers.
	// It should be used to generate a error page and return the http error code
	// 500 (Internal Server Error).
	// The handler can be used to keep your server from crashing because of
	// unrecovered panics.
	PanicHandler func(context.Context, http.ResponseWriter, *http.Request, interface{})
}

// ParamHolder holds URL parameters.
type ParamHolder struct {
	params []param
}

type param struct {
	key   string
	value string
}

// Get returns the value of the first Param which key matches the given name.
// If no matching Param is found, an empty string is returned.
func (ps ParamHolder) Get(name string) string {
	for i := range ps.params {
		if ps.params[i].key == name {
			return ps.params[i].value
		}
	}
	return ""
}

type key int

const paramsKey key = iota

var emptyParams = ParamHolder{}

func newParamContext(ctx context.Context, p ParamHolder) context.Context {
	return context.WithValue(ctx, paramsKey, p)
}

// Params returns URL parameters stored in context
func Params(ctx context.Context) ParamHolder {
	if ctx == nil {
		return emptyParams
	}
	if p, ok := ctx.Value(paramsKey).(ParamHolder); ok {
		return p
	}
	return emptyParams
}

// Param picks one URL parameters stored in context by its name.
//
// This is a shortcut for:
//   xmux.Params(ctx).Get("name")
func Param(ctx context.Context, name string) string {
	return Params(ctx).Get(name)
}

// New returns a new muxer instance
func New() *Mux {
	return &Mux{
		RedirectTrailingSlash:  true,
		RedirectFixedPath:      true,
		HandleMethodNotAllowed: true,
	}
}

// NewGroup creates a new routes group with the provided path prefix.
// All routes added to the returned group will have the path prepended.
func (mux *Mux) NewGroup(path string) *Group {
	return newRouteGroup(mux, path)
}

// GET is a shortcut for mux.Handle("GET", path, handler)
func (mux *Mux) GET(path string, handler xhandler.HandlerC) {
	mux.HandleC("GET", path, handler)
}

// HEAD is a shortcut for mux.Handle("HEAD", path, handler)
func (mux *Mux) HEAD(path string, handler xhandler.HandlerC) {
	mux.HandleC("HEAD", path, handler)
}

// OPTIONS is a shortcut for mux.Handle("OPTIONS", path, handler)
func (mux *Mux) OPTIONS(path string, handler xhandler.HandlerC) {
	mux.HandleC("OPTIONS", path, handler)
}

// POST is a shortcut for mux.Handle("POST", path, handler)
func (mux *Mux) POST(path string, handler xhandler.HandlerC) {
	mux.HandleC("POST", path, handler)
}

// PUT is a shortcut for mux.Handle("PUT", path, handler)
func (mux *Mux) PUT(path string, handler xhandler.HandlerC) {
	mux.HandleC("PUT", path, handler)
}

// PATCH is a shortcut for mux.Handle("PATCH", path, handler)
func (mux *Mux) PATCH(path string, handler xhandler.HandlerC) {
	mux.HandleC("PATCH", path, handler)
}

// DELETE is a shortcut for mux.Handle("DELETE", path, handler)
func (mux *Mux) DELETE(path string, handler xhandler.HandlerC) {
	mux.HandleC("DELETE", path, handler)
}

// HandleC registers a net/context aware request handler with the given
// path and method.
//
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
// functions can be used.
//
// This function is intended for bulk loading and to allow the usage of less
// frequently used, non-standardized or custom methods (e.g. for internal
// communication with a proxy).
func (mux *Mux) HandleC(method, path string, handler xhandler.HandlerC) {
	if path[0] != '/' {
		panic("path must begin with '/' in path '" + path + "'")
	}

	if mux.trees == nil {
		mux.trees = make(map[string]*node)
	}

	root := mux.trees[method]
	if root == nil {
		root = new(node)
		mux.trees[method] = root
	}

	root.addRoute(path, handler)
}

// Handle regiester a standard http.Handler request handler with the given
// path and method. With this adapter, your handler won't have access to the
// context and thus won't work with URL parameters.
func (mux *Mux) Handle(method, path string, handler http.Handler) {
	mux.HandleC(method, path,
		xhandler.HandlerFuncC(func(_ context.Context, w http.ResponseWriter, r *http.Request) {
			handler.ServeHTTP(w, r)
		}),
	)
}

// HandleFunc regiester a standard http.HandlerFunc request handler with the given
// path and method. With this adapter, your handler won't have access to the
// context and thus won't work with URL parameters.
func (mux *Mux) HandleFunc(method, path string, handler http.HandlerFunc) {
	mux.HandleC(method, path,
		xhandler.HandlerFuncC(func(_ context.Context, w http.ResponseWriter, r *http.Request) {
			handler(w, r)
		}),
	)
}

func (mux *Mux) recv(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if rcv := recover(); rcv != nil {
		mux.PanicHandler(ctx, w, r, rcv)
	}
}

// Lookup allows the manual lookup of a method + path combo.
// This is e.g. useful to build a framework around this router.
// If the path was found, it returns the handle function and the path parameter
// values. Otherwise the third return value indicates whether a redirection to
// the same path with an extra / without the trailing slash should be performed.
func (mux *Mux) Lookup(method, path string) (xhandler.HandlerC, ParamHolder, bool) {
	if root := mux.trees[method]; root != nil {
		return root.getValue(path)
	}
	return nil, emptyParams, false
}

// ServeHTTPC implements xhandler.HandlerC interface
func (mux *Mux) ServeHTTPC(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	if mux.PanicHandler != nil {
		defer mux.recv(ctx, w, r)
	}

	if root := mux.trees[r.Method]; root != nil {
		path := r.URL.Path

		if handler, p, tsr := root.getValue(path); handler != nil {
			if len(p.params) > 0 {
				ctx = newParamContext(ctx, p)
			}
			handler.ServeHTTPC(ctx, w, r)
			return
		} else if r.Method != "CONNECT" && path != "/" {
			code := http.StatusMovedPermanently // Permanent redirect, request with GET method
			if r.Method != "GET" {
				// Temporary redirect, request with same method
				// As of Go 1.3, Go does not support status code 308.
				code = http.StatusTemporaryRedirect
			}

			if tsr && mux.RedirectTrailingSlash {
				if len(path) > 1 && path[len(path)-1] == '/' {
					r.URL.Path = path[:len(path)-1]
				} else {
					r.URL.Path = path + "/"
				}
				http.Redirect(w, r, r.URL.String(), code)
				return
			}

			// Try to fix the request path
			if mux.RedirectFixedPath {
				fixedPath, found := root.findCaseInsensitivePath(
					CleanPath(path),
					mux.RedirectTrailingSlash,
				)
				if found {
					r.URL.Path = string(fixedPath)
					http.Redirect(w, r, r.URL.String(), code)
					return
				}
			}
		}
	}

	// Handle 405
	if mux.HandleMethodNotAllowed {
		methods := []string{}
		for method := range mux.trees {
			// Skip the requested method - we already tried this one
			if method == r.Method {
				continue
			}

			handler, _, _ := mux.trees[method].getValue(r.URL.Path)
			if handler != nil {
				methods = append(methods, method)
			}
		}
		if len(methods) > 0 && methods[0] != "OPTIONS" {
			sort.Strings(methods)
			w.Header().Set("Allow", strings.Join(methods, ", "))
			if mux.MethodNotAllowed != nil {
				mux.MethodNotAllowed.ServeHTTPC(ctx, w, r)
			} else {
				http.Error(w,
					http.StatusText(http.StatusMethodNotAllowed),
					http.StatusMethodNotAllowed,
				)
			}
			return
		}
	}

	// Handle 404
	if mux.NotFound != nil {
		mux.NotFound.ServeHTTPC(ctx, w, r)
	} else {
		http.Error(w, "404 page not found", http.StatusNotFound)
	}
}
<|endoftext|>


<commit_before>package download

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const (
	proxyLatestURL = "https://proxy.golang.org/%s/@latest"
	proxyZipURL    = "https://proxy.golang.org/%s/@v/%s.zip"
	reposDir       = "_repos/src"
)

type moduleVersion struct {
	Version string
}

// ProxyDownload downloads a package from proxy.golang.org
func ProxyDownload(path string) (string, error) {
	path = strings.ToLower(path)
	u := fmt.Sprintf(proxyLatestURL, path)
	resp, err := http.Get(u)
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		b, _ := ioutil.ReadAll(resp.Body)
		return "", fmt.Errorf("could not get latest module version from %s: %s", u, string(b))
	}

	var mv moduleVersion

	err = json.NewDecoder(resp.Body).Decode(&mv)
	if err != nil {
		return "", err
	}

	resp, err = http.Get(fmt.Sprintf(proxyZipURL, path, mv.Version))
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return "", fmt.Errorf("status %d", resp.StatusCode)
	}

	zipPath := filepath.Base(path) + "@" + mv.Version + ".zip"
	out, err := os.Create(filepath.Join(reposDir, zipPath))
	if err != nil {
		return "", err
	}

	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return "", err
	}

	err = os.RemoveAll(filepath.Join(reposDir, path))
	if err != nil {
		return "", err
	}

	cmd := exec.Command("unzip", "-o", filepath.Join(reposDir, zipPath), "-d", reposDir)

	err = cmd.Run()
	if err != nil {
		return "", err
	}

	err = os.RemoveAll(filepath.Join(reposDir, zipPath))
	if err != nil {
		return "", err
	}

	return mv.Version, os.Rename(filepath.Join(reposDir, path+"@"+mv.Version), filepath.Join(reposDir, path))
}
<commit_msg>lowercase path in proxy download<commit_after>package download

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const (
	proxyLatestURL = "https://proxy.golang.org/%s/@latest"
	proxyZipURL    = "https://proxy.golang.org/%s/@v/%s.zip"
	reposDir       = "_repos/src"
)

type moduleVersion struct {
	Version string
}

// ProxyDownload downloads a package from proxy.golang.org
func ProxyDownload(path string) (string, error) {
	lowerPath := strings.ToLower(path)
	u := fmt.Sprintf(proxyLatestURL, lowerPath)
	resp, err := http.Get(u)
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		b, _ := ioutil.ReadAll(resp.Body)
		return "", fmt.Errorf("could not get latest module version from %s: %s", u, string(b))
	}

	var mv moduleVersion

	err = json.NewDecoder(resp.Body).Decode(&mv)
	if err != nil {
		return "", err
	}

	resp, err = http.Get(fmt.Sprintf(proxyZipURL, lowerPath, mv.Version))
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return "", fmt.Errorf("status %d", resp.StatusCode)
	}

	zipPath := filepath.Base(path) + "@" + mv.Version + ".zip"
	out, err := os.Create(filepath.Join(reposDir, zipPath))
	if err != nil {
		return "", err
	}

	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return "", err
	}

	err = os.RemoveAll(filepath.Join(reposDir, path))
	if err != nil {
		return "", err
	}

	cmd := exec.Command("unzip", "-o", filepath.Join(reposDir, zipPath), "-d", reposDir)

	err = cmd.Run()
	if err != nil {
		return "", err
	}

	err = os.RemoveAll(filepath.Join(reposDir, zipPath))
	if err != nil {
		return "", err
	}

	return mv.Version, os.Rename(filepath.Join(reposDir, path+"@"+mv.Version), filepath.Join(reposDir, path))
}
<|endoftext|>


<commit_before>package download

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
)

const (
	proxyLatestURL = "https://proxy.golang.org/%s/@latest"
	proxyZipURL    = "https://proxy.golang.org/%s/@v/%s.zip"
	reposDir       = "_repos/src"
)

type moduleVersion struct {
	Version string
}

// ProxyDownload downloads a package from proxy.golang.org
func ProxyDownload(path string) error {
	resp, err := http.Get(fmt.Sprintf(proxyLatestURL, path))
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	var mv moduleVersion

	err = json.NewDecoder(resp.Body).Decode(&mv)
	if err != nil {
		return err
	}

	resp, err = http.Get(fmt.Sprintf(proxyZipURL, path, mv.Version))
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("status %d", resp.StatusCode)
	}

	zipPath := filepath.Base(path) + "@" + mv.Version + ".zip"
	out, err := os.Create(filepath.Join(reposDir, zipPath))
	if err != nil {
		return err
	}

	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return err
	}

	err = os.RemoveAll(filepath.Join(reposDir, path))
	if err != nil {
		return err
	}

	cmd := exec.Command("unzip", "-o", filepath.Join(reposDir, zipPath), "-d", reposDir)

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

	return os.Rename(filepath.Join(reposDir, path+"@"+mv.Version), filepath.Join(reposDir, path))
}
<commit_msg>remove zip file after extraction<commit_after>package download

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
)

const (
	proxyLatestURL = "https://proxy.golang.org/%s/@latest"
	proxyZipURL    = "https://proxy.golang.org/%s/@v/%s.zip"
	reposDir       = "_repos/src"
)

type moduleVersion struct {
	Version string
}

// ProxyDownload downloads a package from proxy.golang.org
func ProxyDownload(path string) error {
	resp, err := http.Get(fmt.Sprintf(proxyLatestURL, path))
	if err != nil {
		return err
	}

	defer resp.Body.Close()

	var mv moduleVersion

	err = json.NewDecoder(resp.Body).Decode(&mv)
	if err != nil {
		return err
	}

	resp, err = http.Get(fmt.Sprintf(proxyZipURL, path, mv.Version))
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return fmt.Errorf("status %d", resp.StatusCode)
	}

	zipPath := filepath.Base(path) + "@" + mv.Version + ".zip"
	out, err := os.Create(filepath.Join(reposDir, zipPath))
	if err != nil {
		return err
	}

	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return err
	}

	err = os.RemoveAll(filepath.Join(reposDir, path))
	if err != nil {
		return err
	}

	cmd := exec.Command("unzip", "-o", filepath.Join(reposDir, zipPath), "-d", reposDir)

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

	err = os.RemoveAll(filepath.Join(reposDir, zipPath))
	if err != nil {
		return err
	}

	return os.Rename(filepath.Join(reposDir, path+"@"+mv.Version), filepath.Join(reposDir, path))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os/exec"
	"regexp"
)

type Matcher struct {
	re *regexp.Regexp
}

func NewMatcher(expr string) (m *Matcher, err error) {
	m = &Matcher{}
	m.re, err = regexp.Compile(expr)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (m *Matcher) MatchString(s string) bool {
	return m.re.MatchString(s)
}

type Processor struct {
	cmd *exec.Cmd
}

func NewProcessor(name string, arg ...string) (p *Processor, err error) {
	if _, err = exec.LookPath(name); err != nil {
		return nil, err
	}
	p = &Processor{}
	p.cmd = exec.Command(name, arg...)
	return p, nil
}

func (p *Processor) Process(a []string) error {
	in, err := p.cmd.StdinPipe()
	if err != nil {
		return err
	}
	defer in.Close()

	out, err := p.cmd.StdoutPipe()
	if err != nil {
		return err
	}
	defer out.Close()

	if err = p.cmd.Start(); err != nil {
		return err
	}
	for _, s := range a {
		fmt.Fprintln(in, s)
	}
	if err = in.Close(); err != nil {
		return err
	}

	b := bufio.NewScanner(out)
	for i := 0; i < len(a) && b.Scan(); i++ {
		a[i] = b.Text()
	}
	return b.Err()
}

type Lines struct {
	matcher        *Matcher
	processor      *Processor
	lines          []string
	matchedLines   []string
	matchedIndexes map[int]bool
}

func NewLines(m *Matcher, p *Processor) *Lines {
	return &Lines{
		matcher:        m,
		processor:      p,
		lines:          []string{},
		matchedLines:   []string{},
		matchedIndexes: make(map[int]bool),
	}
}
<commit_msg>Implement Lines.LoadLines<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"os/exec"
	"regexp"
)

type Matcher struct {
	re *regexp.Regexp
}

func NewMatcher(expr string) (m *Matcher, err error) {
	m = &Matcher{}
	m.re, err = regexp.Compile(expr)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (m *Matcher) MatchString(s string) bool {
	return m.re.MatchString(s)
}

type Processor struct {
	cmd *exec.Cmd
}

func NewProcessor(name string, arg ...string) (p *Processor, err error) {
	if _, err = exec.LookPath(name); err != nil {
		return nil, err
	}
	p = &Processor{}
	p.cmd = exec.Command(name, arg...)
	return p, nil
}

func (p *Processor) Process(a []string) error {
	in, err := p.cmd.StdinPipe()
	if err != nil {
		return err
	}
	defer in.Close()

	out, err := p.cmd.StdoutPipe()
	if err != nil {
		return err
	}
	defer out.Close()

	if err = p.cmd.Start(); err != nil {
		return err
	}
	for _, s := range a {
		fmt.Fprintln(in, s)
	}
	if err = in.Close(); err != nil {
		return err
	}

	b := bufio.NewScanner(out)
	for i := 0; i < len(a) && b.Scan(); i++ {
		a[i] = b.Text()
	}
	return b.Err()
}

type Lines struct {
	matcher        *Matcher
	processor      *Processor
	lines          []string
	matchedLines   []string
	matchedIndexes map[int]bool
}

func NewLines(m *Matcher, p *Processor) *Lines {
	return &Lines{
		matcher:        m,
		processor:      p,
		lines:          []string{},
		matchedLines:   []string{},
		matchedIndexes: make(map[int]bool),
	}
}

func (l *Lines) LoadLines(r io.Reader) error {
	b := bufio.NewScanner(r)
	for i := 0; b.Scan(); i++ {
		line := b.Text()
		if l.matcher.MatchString(line) {
			l.matchedLines = append(l.matchedLines, line)
			l.matchedIndexes[i] = true
		}
		l.lines = append(l.lines, line)
	}
	return b.Err()
}
<|endoftext|>


<commit_before>package mtgox

import (
	"code.google.com/p/go.net/websocket"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"github.com/yanatan16/mtgox/jsonws"
	"github.com/yanatan16/mtgox/msgwatch"
	"strings"
	"fmt"
	"io/ioutil"
	"time"
	exq "github.com/yanatan16/exchequer"
)

type StreamType string
type OrderType string

const (
	api_host      string = "wss://websocket.mtgox.com:443"
	api_path      string = "/mtgox"
	http_endpoint string = "http://mtgox.com/api/2"
	origin_url    string = "http://localhost"

	TICKER StreamType = "ticker"
	DEPTH  StreamType = "depth"
	TRADES StreamType = "trades"

	BID OrderType = "bid"
	ASK OrderType = "ask"
)

var (
	// TODO: use https://mtgox.com/api/2/stream/list_public
	channels map[string]string = make(map[string]string)
	randStr  chan string
)

type StreamingApi struct {
	*msgwatch.MsgWatcher
	ws     *jsonws.JsonWebsocket
	key    []byte
	secret []byte
}

type Config struct {
	Currencies []string
	Key        string
	Secret     string
}

type CallResult struct {
	Result map[string]interface{}
	Success bool
	Error string
}

func NewFromConfig(cfgfile string) (*StreamingApi, error) {
	file, err := ioutil.ReadFile(cfgfile)
	if err != nil {
		return nil, err
	}

	m := new(Config)
	err = json.Unmarshal(file, m)
	if err != nil {
		return nil, err
	}

	return New(m.Key, m.Secret, m.Currencies...)
}

func New(key, secret string, currencies ...string) (*StreamingApi, error) {
	url := fmt.Sprintf("%s%s?Currency=%s", api_host, api_path, strings.Join(currencies, ","))
	config, _ := websocket.NewConfig(url, origin_url)
	ws, err := jsonws.New(config)

	if err != nil {
		return nil, err
	}

	api := &StreamingApi{
		MsgWatcher: msgwatch.New(ws.RecvForever()),
		ws:         ws,
	}

	api.key, err = hex.DecodeString(strings.Replace(key, "-", "", -1))
	if err != nil {
		return nil, err
	}

	api.secret, err = base64.StdEncoding.DecodeString(secret)
	if err != nil {
		return nil, err
	}

	remarks := api.Listen("remark")
	go func() {
		for remark := range remarks {
			fmt.Println("Remark:", remark)
		}
	}()

	return api, err
}

func (api *StreamingApi) Close() error {
	return api.ws.Close()
}

// Unsubscribe from a named channel
func (api *StreamingApi) Unsubscribe(name string) error {
	if key, ok := api.Channels[name]; ok {
		return api.ws.Send(map[string]interface{}{
			"op":      "unsubscribe",
			"channel": key,
		})
	}

	return errors.New("No channel with name " + name + ".")
}

// Subscribe to a type of channel. Returns the Listen(typ) listener.
func (api *StreamingApi) Subscribe(typ StreamType) (chan map[string]interface{}, error) {
	err := api.ws.Send(map[string]interface{}{
		"op":   "mtgox.subscribe",
		"type": string(typ),
	})

	if err != nil {
		return nil, err
	}

	return api.Listen("ticker"), nil
}

func (api *StreamingApi) sign(body []byte) ([]byte, error) {
	mac := hmac.New(sha512.New, api.secret)
	_, err := mac.Write(body)
	if err != nil {
		return nil, err
	}

	return mac.Sum(nil), nil
}

func (api *StreamingApi) authenticatedSend(msg map[string]interface{}) error {
	if api.key == nil || api.secret == nil {
		return errors.New("API Key or secret is invalid or missing.")
	}

	req, err := json.Marshal(msg)
	if err != nil {
		return err
	}

	signedReq, err := api.sign(req)
	if err != nil {
		return err
	}

	reqid := msg["id"]

	fullReq := append(append(api.key, signedReq...), req...)
	encodedReq := base64.StdEncoding.EncodeToString(fullReq)

	fmt.Println("Request:", string(req))
	return api.ws.Send(map[string]interface{}{
		"op":      "call",
		"id":      reqid,
		"call":    encodedReq,
		"context": "mtgox.com",
	})
}

func (api *StreamingApi) call(endpoint string, params map[string]interface{}) (chan *CallResult, error) {
	if params == nil {
		params = make(map[string]interface{})
	}
	msg := map[string]interface{}{
		"call":   endpoint,
		"item":   "BTC",
		"params": params,
		"id":     <-ids,
		"nonce":  <-nonces,
	}

	err := api.authenticatedSend(msg)
	if err != nil {
		return nil, err
	}

	out := interpretResult(api.ListenResult(msg["id"].(string)))

	return out, nil
}

func interpretResult(in chan map[string]interface{}) (chan *CallResult) {
	out := make(chan *CallResult)
	go func () {
		res := <- in
		if op, err := exq.String(res, "op"); err == nil {
			if op == "remark" {
				out <- &CallResult{
					Success: false,
					Error: res["remark"].(string),
				}
			} else if op == "result" {
				out <- &CallResult{
					Success: true,
					Result: res["result"].(map[string]interface{}),
				}
			} else {
				out <- &CallResult{
					Success: false,
					Error: fmt.Sprintf("Don't know how to interpret: %s", res),
				}
			}
		} else {
			out <- &CallResult{
				Success: false,
				Error: fmt.Sprintf("Error accessing object: %s", err.Error()),
			}
		}
	}()
	return out
}

func (api *StreamingApi) Info() (chan *CallResult, error) {
	return api.call("private/info", nil)
}

func (api *StreamingApi) Address(description string) (chan *CallResult, error) {
	m := make(map[string]interface{})
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/address", m)
}

func (api *StreamingApi) AddPrivateKey(key string, desc string) (chan *CallResult, error) {
	return api.call("bitcoin/addpriv", map[string]interface{}{
		"key":         key,
		"keytype":     "auto",
		"description": desc,
	})
}

func (api *StreamingApi) AddWallet(walletdat, description string) (chan *CallResult, error) {
	m := map[string]interface{}{
		"wallet": walletdat,
	}
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/wallet_add", m)
}

func (api *StreamingApi) Send(addr string, amount_int uint64) (chan *CallResult, error) {
	return api.call("bitcoin/send_simple", map[string]interface{}{
		"address":    addr,
		"amount_int": amount_int,
	})
}

func (api *StreamingApi) IdKey() (chan *CallResult, error) {
	return api.call("private/idkey", nil)
}

func (api *StreamingApi) FullHistory(currency string, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) QueryHistory(currency string, typ string, begin, end *time.Time, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if typ != "" {
		m["type"] = typ
	}
	if begin != nil {
		m["date_start"] = begin.String()
	}
	if end != nil {
		m["date_end"] = end.String()
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) SubmitOrder(typ string, amount, price uint64) (chan *CallResult, error) {
	return api.call("order/add", map[string]interface{}{
		"type":       typ,
		"amount_int": amount,
		"price_int":  price,
	})
}

func (api *StreamingApi) CancelOrder(oid string) (chan *CallResult, error) {
	return api.call("order/cancel", map[string]interface{}{
		"oid": oid,
	})
}

func (api *StreamingApi) Orders() (chan *CallResult, error) {
	return api.call("private/orders", nil)
}

func (api *StreamingApi) OrderResult(oid string) (chan *CallResult, error) {
	return api.call("order/result", map[string]interface{}{"oid": oid})
}

func (api *StreamingApi) AddressDetails(addr string) (chan *CallResult, error) {
	return api.call("bitcoin/addr_details", map[string]interface{}{"hash": addr})
}

func (api *StreamingApi) Lag() (chan *CallResult, error) {
	return api.call("order/lag", nil)
}
<commit_msg>Update links to golang-mtgox<commit_after>package mtgox

import (
	"code.google.com/p/go.net/websocket"
	"crypto/hmac"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"errors"
	"github.com/yanatan16/golang-mtgox/jsonws"
	"github.com/yanatan16/golang-mtgox/msgwatch"
	"strings"
	"fmt"
	"io/ioutil"
	"time"
	exq "github.com/yanatan16/exchequer"
)

type StreamType string
type OrderType string

const (
	api_host      string = "wss://websocket.mtgox.com:443"
	api_path      string = "/mtgox"
	http_endpoint string = "http://mtgox.com/api/2"
	origin_url    string = "http://localhost"

	TICKER StreamType = "ticker"
	DEPTH  StreamType = "depth"
	TRADES StreamType = "trades"

	BID OrderType = "bid"
	ASK OrderType = "ask"
)

var (
	// TODO: use https://mtgox.com/api/2/stream/list_public
	channels map[string]string = make(map[string]string)
	randStr  chan string
)

type StreamingApi struct {
	*msgwatch.MsgWatcher
	ws     *jsonws.JsonWebsocket
	key    []byte
	secret []byte
}

type Config struct {
	Currencies []string
	Key        string
	Secret     string
}

type CallResult struct {
	Result map[string]interface{}
	Success bool
	Error string
}

func NewFromConfig(cfgfile string) (*StreamingApi, error) {
	file, err := ioutil.ReadFile(cfgfile)
	if err != nil {
		return nil, err
	}

	m := new(Config)
	err = json.Unmarshal(file, m)
	if err != nil {
		return nil, err
	}

	return New(m.Key, m.Secret, m.Currencies...)
}

func New(key, secret string, currencies ...string) (*StreamingApi, error) {
	url := fmt.Sprintf("%s%s?Currency=%s", api_host, api_path, strings.Join(currencies, ","))
	config, _ := websocket.NewConfig(url, origin_url)
	ws, err := jsonws.New(config)

	if err != nil {
		return nil, err
	}

	api := &StreamingApi{
		MsgWatcher: msgwatch.New(ws.RecvForever()),
		ws:         ws,
	}

	api.key, err = hex.DecodeString(strings.Replace(key, "-", "", -1))
	if err != nil {
		return nil, err
	}

	api.secret, err = base64.StdEncoding.DecodeString(secret)
	if err != nil {
		return nil, err
	}

	remarks := api.Listen("remark")
	go func() {
		for remark := range remarks {
			fmt.Println("Remark:", remark)
		}
	}()

	return api, err
}

func (api *StreamingApi) Close() error {
	return api.ws.Close()
}

// Unsubscribe from a named channel
func (api *StreamingApi) Unsubscribe(name string) error {
	if key, ok := api.Channels[name]; ok {
		return api.ws.Send(map[string]interface{}{
			"op":      "unsubscribe",
			"channel": key,
		})
	}

	return errors.New("No channel with name " + name + ".")
}

// Subscribe to a type of channel. Returns the Listen(typ) listener.
func (api *StreamingApi) Subscribe(typ StreamType) (chan map[string]interface{}, error) {
	err := api.ws.Send(map[string]interface{}{
		"op":   "mtgox.subscribe",
		"type": string(typ),
	})

	if err != nil {
		return nil, err
	}

	return api.Listen("ticker"), nil
}

func (api *StreamingApi) sign(body []byte) ([]byte, error) {
	mac := hmac.New(sha512.New, api.secret)
	_, err := mac.Write(body)
	if err != nil {
		return nil, err
	}

	return mac.Sum(nil), nil
}

func (api *StreamingApi) authenticatedSend(msg map[string]interface{}) error {
	if api.key == nil || api.secret == nil {
		return errors.New("API Key or secret is invalid or missing.")
	}

	req, err := json.Marshal(msg)
	if err != nil {
		return err
	}

	signedReq, err := api.sign(req)
	if err != nil {
		return err
	}

	reqid := msg["id"]

	fullReq := append(append(api.key, signedReq...), req...)
	encodedReq := base64.StdEncoding.EncodeToString(fullReq)

	fmt.Println("Request:", string(req))
	return api.ws.Send(map[string]interface{}{
		"op":      "call",
		"id":      reqid,
		"call":    encodedReq,
		"context": "mtgox.com",
	})
}

func (api *StreamingApi) call(endpoint string, params map[string]interface{}) (chan *CallResult, error) {
	if params == nil {
		params = make(map[string]interface{})
	}
	msg := map[string]interface{}{
		"call":   endpoint,
		"item":   "BTC",
		"params": params,
		"id":     <-ids,
		"nonce":  <-nonces,
	}

	err := api.authenticatedSend(msg)
	if err != nil {
		return nil, err
	}

	out := interpretResult(api.ListenResult(msg["id"].(string)))

	return out, nil
}

func interpretResult(in chan map[string]interface{}) (chan *CallResult) {
	out := make(chan *CallResult)
	go func () {
		res := <- in
		if op, err := exq.String(res, "op"); err == nil {
			if op == "remark" {
				out <- &CallResult{
					Success: false,
					Error: res["remark"].(string),
				}
			} else if op == "result" {
				out <- &CallResult{
					Success: true,
					Result: res["result"].(map[string]interface{}),
				}
			} else {
				out <- &CallResult{
					Success: false,
					Error: fmt.Sprintf("Don't know how to interpret: %s", res),
				}
			}
		} else {
			out <- &CallResult{
				Success: false,
				Error: fmt.Sprintf("Error accessing object: %s", err.Error()),
			}
		}
	}()
	return out
}

func (api *StreamingApi) Info() (chan *CallResult, error) {
	return api.call("private/info", nil)
}

func (api *StreamingApi) Address(description string) (chan *CallResult, error) {
	m := make(map[string]interface{})
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/address", m)
}

func (api *StreamingApi) AddPrivateKey(key string, desc string) (chan *CallResult, error) {
	return api.call("bitcoin/addpriv", map[string]interface{}{
		"key":         key,
		"keytype":     "auto",
		"description": desc,
	})
}

func (api *StreamingApi) AddWallet(walletdat, description string) (chan *CallResult, error) {
	m := map[string]interface{}{
		"wallet": walletdat,
	}
	if description != "" {
		m["description"] = description
	}
	return api.call("bitcoin/wallet_add", m)
}

func (api *StreamingApi) Send(addr string, amount_int uint64) (chan *CallResult, error) {
	return api.call("bitcoin/send_simple", map[string]interface{}{
		"address":    addr,
		"amount_int": amount_int,
	})
}

func (api *StreamingApi) IdKey() (chan *CallResult, error) {
	return api.call("private/idkey", nil)
}

func (api *StreamingApi) FullHistory(currency string, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) QueryHistory(currency string, typ string, begin, end *time.Time, page int) (chan *CallResult, error) {
	m := map[string]interface{}{
		"currency": currency,
	}
	if typ != "" {
		m["type"] = typ
	}
	if begin != nil {
		m["date_start"] = begin.String()
	}
	if end != nil {
		m["date_end"] = end.String()
	}
	if page != 0 {
		m["page"] = page
	}
	return api.call("wallet/history", m)
}

func (api *StreamingApi) SubmitOrder(typ string, amount, price uint64) (chan *CallResult, error) {
	return api.call("order/add", map[string]interface{}{
		"type":       typ,
		"amount_int": amount,
		"price_int":  price,
	})
}

func (api *StreamingApi) CancelOrder(oid string) (chan *CallResult, error) {
	return api.call("order/cancel", map[string]interface{}{
		"oid": oid,
	})
}

func (api *StreamingApi) Orders() (chan *CallResult, error) {
	return api.call("private/orders", nil)
}

func (api *StreamingApi) OrderResult(oid string) (chan *CallResult, error) {
	return api.call("order/result", map[string]interface{}{"oid": oid})
}

func (api *StreamingApi) AddressDetails(addr string) (chan *CallResult, error) {
	return api.call("bitcoin/addr_details", map[string]interface{}{"hash": addr})
}

func (api *StreamingApi) Lag() (chan *CallResult, error) {
	return api.call("order/lag", nil)
}
<|endoftext|>


<commit_before>// Copyright 2016 Zebra Project.
//
// 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 rib

import (
	"fmt"
	"net"

	"github.com/coreswitch/cmd"
	"github.com/coreswitch/netutil"
)

var Parser *cmd.Node

func Config(command int, path []string) {
	if command == cmd.Set {
		fmt.Println("[cmd] add", path)
	} else {
		fmt.Println("[cmd] del", path)
	}
	ret, fn, args, _ := Parser.ParseCmd(path)
	if ret == cmd.ParseSuccess {
		fn.(func(int, cmd.Args) int)(command, args)
	}
}

func RouterIdApi(Cmd int, Args cmd.Args) int {
	id := Args[0].(net.IP)
	if Cmd == cmd.Set {
		VrfDefault().RouterIdSet(id)
	} else {
		VrfDefault().RouterIdUnset()
	}
	return cmd.Success
}

func IPv4RouteApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	fmt.Println("Static route:", prefix, nexthop)
	if Cmd == cmd.Set {
		server.StaticAdd(prefix, nexthop)
	} else {
		server.StaticDelete(prefix, nexthop)
	}
	return cmd.Success
}

func IPv6RouteApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	fmt.Println("Static route:", prefix, nexthop)
	if Cmd == cmd.Set {
		//server.StaticAdd(prefix, nexthop)
	} else {
		//server.StaticDelete(prefix, nexthop)
	}
	return cmd.Success
}

func IPv4VrfRouteApi(Cmd int, Args cmd.Args) int {
	vrfName := Args[0].(string)
	prefix := Args[1].(*netutil.Prefix)
	nexthop := Args[2].(net.IP)

	fmt.Println("Vrf Static route:", vrfName, prefix, nexthop)

	vrf := VrfLookupByName(vrfName)
	if vrf == nil {
		fmt.Println("IPv4VrfStatic: Can't find VRF")
		return cmd.Success
	}
	if Cmd == cmd.Set {
		vrf.StaticAdd(prefix, nexthop)
	} else {
		vrf.StaticDelete(prefix, nexthop)
	}

	return cmd.Success
}

func IPv4VrfRouteApi2(Cmd int, Args cmd.Args) int {
	return cmd.Success
}

var InterfaceVlanBindHook func(int, int)

var InterfaceVlanFea bool

func InterfaceVlanApi(Cmd int, Args cmd.Args) int {
	ifName := Args[0].(string)
	vlanId := Args[1].(uint64)
	ifc := InterfaceConfigGet(ifName)
	ifc.VlanId = int(vlanId)

	if InterfaceVlanFea {
		vlan := VlanDB.Lookup(uint16(vlanId))
		if vlan != nil {
			if InterfaceVlanBindHook != nil {
				InterfaceVlanBindHook(int(vlanId), ifc.Index)
			}
		}
		vlan.Ports = append(vlan.Ports, ifc)
	} else {
		if Cmd == cmd.Set {
			server.VIFAdd(ifName, vlanId)
		} else {
			server.VIFDelete(ifName, vlanId)
		}
	}

	return cmd.Success
}

func InterfaceVrfApi(Cmd int, Args cmd.Args) int {
	ifName := Args[0].(string)
	vrfName := Args[1].(string)

	if Cmd == cmd.Set {
		server.IfVrfBind(ifName, vrfName)
	} else {
		server.IfVrfUnbind(ifName, vrfName)
	}

	return cmd.Success
}

func InterfaceAddress(Cmd int, Args cmd.Args) int {
	ifName := Args[0].(string)
	addr := Args[1].(*netutil.Prefix)
	if Cmd == cmd.Set {
		server.AddrAdd(ifName, addr)
	} else if Cmd == cmd.Delete {
		server.AddrDelete(ifName, addr)
	}
	return cmd.Success
}

func InterfaceShutdown(Cmd int, Args cmd.Args) int {
	ifname := Args[0].(string)
	ifc := InterfaceConfigGet(ifname)
	if Cmd == cmd.Set {
		ifc.ShutdownSet()
	} else {
		ifc.ShutdownUnset()
	}
	return cmd.Success
}

func InterfaceDescription(Cmd int, Args cmd.Args) int {
	ifname := Args[0].(string)
	desc := Args[1].(string)
	ifc := InterfaceConfigGet(ifname)
	if Cmd == cmd.Set {
		ifc.DescriptionSet(desc)
	} else {
		ifc.DescriptionUnset()
	}
	return cmd.Success
}

func InterfaceMtu(Cmd int, Args cmd.Args) int {
	ifname := Args[0].(string)
	ifc := InterfaceConfigGet(ifname)
	mtu := Args[1].(uint64)
	fmt.Println("MTU", ifc, mtu)
	if Cmd == cmd.Set {
		ifc.MtuSet(uint32(mtu))
	} else {
		ifc.MtuUnset()
	}
	return cmd.Success
}

func VrfApi(Cmd int, Args cmd.Args) int {
	name := Args[0].(string)
	if Cmd == cmd.Set {
		server.VrfAdd(name)
	} else {
		server.VrfDelete(name)
	}
	return cmd.Success
}

func VrfHubNodeApi(Cmd int, Args cmd.Args) int {
	name := Args[0].(string)
	hubNode := Args[1].(string)
	if Cmd == cmd.Set {
		fmt.Println("HubNode add", name, hubNode)
		VrfHubNodeAdd(name, hubNode)
	} else {
		fmt.Println("HubNode delete", name, hubNode)
		VrfHubNodeDelete(name, hubNode)
	}
	return cmd.Success
}

func InitAPI() {
	Parser = cmd.NewParser()
	Parser.InstallCmd([]string{"vrf", "name", "WORD"}, VrfApi)
	Parser.InstallCmd([]string{"vlans", "vlan", "<1-4096>"}, VlanApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "vlan", "<1-4096>"}, InterfaceVlanApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "vlans", "<1-4096>"}, InterfaceVlanApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "vrf", "WORD"}, InterfaceVrfApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "ipv4", "address", "A.B.C.D/M"}, InterfaceAddress)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "ipv6", "address", "X:X::X:X/M"}, InterfaceAddress)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "shutdown"}, InterfaceShutdown)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "description", "LINE"}, InterfaceDescription)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "mtu", "<68-65535>"}, InterfaceMtu)
	Parser.InstallCmd([]string{"routing-options", "router-id", "A.B.C.D"}, RouterIdApi)
	Parser.InstallCmd([]string{"routing-options", "static", "route", "A.B.C.D/M", "nexthop", "A.B.C.D"}, IPv4RouteApi)
	Parser.InstallCmd([]string{"routing-options", "static", "route-ipv6", "X:X::X:X/M", "nexthop", "X:X::X:X"}, IPv6RouteApi)
	Parser.InstallCmd([]string{"vrf", "name", "WORD", "hub-node", "WORD"}, VrfHubNodeApi)
	Parser.InstallCmd([]string{"vrf", "name", "WORD", "static", "route", "A.B.C.D/M", "nexthop", "A.B.C.D"}, IPv4VrfRouteApi)
	Parser.InstallCmd([]string{"vrf", "name", "WORD", "static", "route", "A.B.C.D/M", "interface", "WORD"}, IPv4VrfRouteApi2)
}
<commit_msg>Add API for SRv6.<commit_after>// Copyright 2016 Zebra Project.
//
// 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 rib

import (
	"fmt"
	"net"

	"github.com/coreswitch/cmd"
	"github.com/coreswitch/netutil"
)

var Parser *cmd.Node

func Config(command int, path []string) {
	if command == cmd.Set {
		fmt.Println("[cmd] add", path)
	} else {
		fmt.Println("[cmd] del", path)
	}
	ret, fn, args, _ := Parser.ParseCmd(path)
	if ret == cmd.ParseSuccess {
		fn.(func(int, cmd.Args) int)(command, args)
	}
}

func RouterIdApi(Cmd int, Args cmd.Args) int {
	id := Args[0].(net.IP)
	if Cmd == cmd.Set {
		VrfDefault().RouterIdSet(id)
	} else {
		VrfDefault().RouterIdUnset()
	}
	return cmd.Success
}

func IPv4RouteApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	fmt.Println("Static route:", prefix, nexthop)
	if Cmd == cmd.Set {
		server.StaticAdd(prefix, nexthop)
	} else {
		server.StaticDelete(prefix, nexthop)
	}
	return cmd.Success
}

func IPv4RouteSeg6ModeApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	mode := Args[2].(string)
	fmt.Println("Static IPv4 seg6 mode:", prefix, nexthop, mode)
	if Cmd == cmd.Set {
	} else {
	}
	return cmd.Success
}

func IPv4RouteSeg6SegmentsApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	Args = Args[2:]
	fmt.Println("Static IPv4 seg6 segments:", prefix, nexthop, Args)
	if Cmd == cmd.Set {
	} else {
	}
	return cmd.Success
}

func IPv6RouteApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	fmt.Println("Static route:", prefix, nexthop)
	if Cmd == cmd.Set {
	} else {
	}
	return cmd.Success
}

func IPv6RouteSeg6ModeApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	mode := Args[2].(string)
	fmt.Println("Static IPv6 seg6 mode:", prefix, nexthop, mode)
	if Cmd == cmd.Set {
	} else {
	}
	return cmd.Success
}

func IPv6RouteSeg6SegmentsApi(Cmd int, Args cmd.Args) int {
	prefix := Args[0].(*netutil.Prefix)
	nexthop := Args[1].(net.IP)
	Args = Args[2:]
	fmt.Println("Static IPv6 seg6 segments:", prefix, nexthop, Args)
	if Cmd == cmd.Set {
	} else {
	}
	return cmd.Success
}

func IPv4VrfRouteApi(Cmd int, Args cmd.Args) int {
	vrfName := Args[0].(string)
	prefix := Args[1].(*netutil.Prefix)
	nexthop := Args[2].(net.IP)

	fmt.Println("Vrf Static route:", vrfName, prefix, nexthop)

	vrf := VrfLookupByName(vrfName)
	if vrf == nil {
		fmt.Println("IPv4VrfStatic: Can't find VRF")
		return cmd.Success
	}
	if Cmd == cmd.Set {
		vrf.StaticAdd(prefix, nexthop)
	} else {
		vrf.StaticDelete(prefix, nexthop)
	}

	return cmd.Success
}

func IPv4VrfRouteApi2(Cmd int, Args cmd.Args) int {
	return cmd.Success
}

var InterfaceVlanBindHook func(int, int)

var InterfaceVlanFea bool

func InterfaceVlanApi(Cmd int, Args cmd.Args) int {
	ifName := Args[0].(string)
	vlanId := Args[1].(uint64)
	ifc := InterfaceConfigGet(ifName)
	ifc.VlanId = int(vlanId)

	if InterfaceVlanFea {
		vlan := VlanDB.Lookup(uint16(vlanId))
		if vlan != nil {
			if InterfaceVlanBindHook != nil {
				InterfaceVlanBindHook(int(vlanId), ifc.Index)
			}
		}
		vlan.Ports = append(vlan.Ports, ifc)
	} else {
		if Cmd == cmd.Set {
			server.VIFAdd(ifName, vlanId)
		} else {
			server.VIFDelete(ifName, vlanId)
		}
	}

	return cmd.Success
}

func InterfaceVrfApi(Cmd int, Args cmd.Args) int {
	ifName := Args[0].(string)
	vrfName := Args[1].(string)

	if Cmd == cmd.Set {
		server.IfVrfBind(ifName, vrfName)
	} else {
		server.IfVrfUnbind(ifName, vrfName)
	}

	return cmd.Success
}

func InterfaceAddress(Cmd int, Args cmd.Args) int {
	ifName := Args[0].(string)
	addr := Args[1].(*netutil.Prefix)
	if Cmd == cmd.Set {
		server.AddrAdd(ifName, addr)
	} else if Cmd == cmd.Delete {
		server.AddrDelete(ifName, addr)
	}
	return cmd.Success
}

func InterfaceShutdown(Cmd int, Args cmd.Args) int {
	ifname := Args[0].(string)
	ifc := InterfaceConfigGet(ifname)
	if Cmd == cmd.Set {
		ifc.ShutdownSet()
	} else {
		ifc.ShutdownUnset()
	}
	return cmd.Success
}

func InterfaceDescription(Cmd int, Args cmd.Args) int {
	ifname := Args[0].(string)
	desc := Args[1].(string)
	ifc := InterfaceConfigGet(ifname)
	if Cmd == cmd.Set {
		ifc.DescriptionSet(desc)
	} else {
		ifc.DescriptionUnset()
	}
	return cmd.Success
}

func InterfaceMtu(Cmd int, Args cmd.Args) int {
	ifname := Args[0].(string)
	ifc := InterfaceConfigGet(ifname)
	mtu := Args[1].(uint64)
	fmt.Println("MTU", ifc, mtu)
	if Cmd == cmd.Set {
		ifc.MtuSet(uint32(mtu))
	} else {
		ifc.MtuUnset()
	}
	return cmd.Success
}

func VrfApi(Cmd int, Args cmd.Args) int {
	name := Args[0].(string)
	if Cmd == cmd.Set {
		server.VrfAdd(name)
	} else {
		server.VrfDelete(name)
	}
	return cmd.Success
}

func VrfHubNodeApi(Cmd int, Args cmd.Args) int {
	name := Args[0].(string)
	hubNode := Args[1].(string)
	if Cmd == cmd.Set {
		fmt.Println("HubNode add", name, hubNode)
		VrfHubNodeAdd(name, hubNode)
	} else {
		fmt.Println("HubNode delete", name, hubNode)
		VrfHubNodeDelete(name, hubNode)
	}
	return cmd.Success
}

func InitAPI() {
	Parser = cmd.NewParser()
	Parser.InstallCmd([]string{"vrf", "name", "WORD"}, VrfApi)
	Parser.InstallCmd([]string{"vlans", "vlan", "<1-4096>"}, VlanApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "vlan", "<1-4096>"}, InterfaceVlanApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "vlans", "<1-4096>"}, InterfaceVlanApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "vrf", "WORD"}, InterfaceVrfApi)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "ipv4", "address", "A.B.C.D/M"}, InterfaceAddress)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "ipv6", "address", "X:X::X:X/M"}, InterfaceAddress)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "shutdown"}, InterfaceShutdown)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "description", "LINE"}, InterfaceDescription)
	Parser.InstallCmd([]string{"interfaces", "interface", "WORD", "mtu", "<68-65535>"}, InterfaceMtu)
	Parser.InstallCmd([]string{"routing-options", "router-id", "A.B.C.D"}, RouterIdApi)
	Parser.InstallCmd([]string{"routing-options", "ipv4", "route", "A.B.C.D/M", "nexthop", "A.B.C.D"}, IPv4RouteApi)
	Parser.InstallCmd([]string{"routing-options", "ipv4", "route", "A.B.C.D/M", "nexthop", "A.B.C.D", "seg6", "mode", "WORD"}, IPv4RouteSeg6ModeApi)
	Parser.InstallCmd([]string{"routing-options", "ipv4", "route", "A.B.C.D/M", "nexthop", "A.B.C.D", "seg6", "segments", "X:X::X:X", "&"}, IPv4RouteSeg6SegmentsApi)

	Parser.InstallCmd([]string{"routing-options", "ipv6", "route", "X:X::X:X/M", "nexthop", "X:X::X:X"}, IPv6RouteApi)
	Parser.InstallCmd([]string{"routing-options", "ipv6", "route", "X:X::X:X/M", "nexthop", "X:X::X:X", "seg6", "mode", "WORD"}, IPv6RouteSeg6ModeApi)
	Parser.InstallCmd([]string{"routing-options", "ipv6", "route", "X:X::X:X/M", "nexthop", "X:X::X:X", "seg6", "segments", "X:X::X:X", "&"}, IPv6RouteSeg6SegmentsApi)

	Parser.InstallCmd([]string{"vrf", "name", "WORD", "hub-node", "WORD"}, VrfHubNodeApi)
	Parser.InstallCmd([]string{"vrf", "name", "WORD", "static", "route", "A.B.C.D/M", "nexthop", "A.B.C.D"}, IPv4VrfRouteApi)
	Parser.InstallCmd([]string{"vrf", "name", "WORD", "static", "route", "A.B.C.D/M", "interface", "WORD"}, IPv4VrfRouteApi2)
}
<|endoftext|>


<commit_before>// Copyright 2017 Google 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 monitor

// TODO(ismail): write extensive tests for verification steps, where necessary
// tests should go into integration tests
<commit_msg>Create an empty test to allow compliation (#832)<commit_after>// Copyright 2017 Google 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 monitor

import "testing"

// TODO(ismail): write extensive tests for verification steps, where necessary
// tests should go into integration tests

// TestSomething is an empty test allows this file to compile.
func TestSomething(*testing.T) {
}
<|endoftext|>