<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"time"

	"github.com/pressly/chi"
	"github.com/pressly/chi/middleware"
	"github.com/pressly/chi/render"
	"golang.org/x/net/context"
)

func main() {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("..."))
	})

	r.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("pong"))
	})

	r.Get("/panic", func(w http.ResponseWriter, r *http.Request) {
		panic("test")
	})

	// Slow handlers/operations.
	r.Group(func(r chi.Router) {
		// Stop processing when client disconnects.
		r.Use(middleware.CloseNotify)

		// Stop processing after 2.5 seconds.
		r.Use(middleware.Timeout(2500 * time.Millisecond))

		r.Get("/slow", func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			rand.Seed(time.Now().Unix())

			// Processing will take 1-5 seconds.
			processTime := time.Duration(rand.Intn(4)+1) * time.Second

			select {
			case <-ctx.Done():
				return

			case <-time.After(processTime):
				// The above channel simulates some hard work.
			}

			w.Write([]byte(fmt.Sprintf("Processed in %v seconds\n", processTime)))
		})
	})

	// Throttle very expensive handlers/operations.
	r.Group(func(r chi.Router) {
		// Stop processing after 30 seconds.
		r.Use(middleware.Timeout(30 * time.Second))

		// Only one request will be processed at a time.
		r.Use(middleware.Throttle(1))

		r.Get("/throttled", func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
			select {
			case <-ctx.Done():
				switch ctx.Err() {
				case context.DeadlineExceeded:
					w.WriteHeader(504)
					w.Write([]byte("Processing too slow\n"))
				default:
					w.Write([]byte("Canceled\n"))
				}
				return

			case <-time.After(5 * time.Second):
				// The above channel simulates some hard work.
			}

			w.Write([]byte("Processed\n"))
		})
	})

	// RESTy routes for "articles" resource
	r.Route("/articles", func(r chi.Router) {
		r.Get("/", paginate, listArticles) // GET /articles
		r.Post("/", createArticle)         // POST /articles

		r.Route("/:articleID", func(r chi.Router) {
			r.Use(ArticleCtx)
			r.Get("/", getArticle)       // GET /articles/123
			r.Put("/", updateArticle)    // PUT /articles/123
			r.Delete("/", deleteArticle) // DELETE /articles/123
		})
	})

	// Mount the admin sub-router
	r.Mount("/admin", adminRouter())

	http.ListenAndServe(":3333", r)
}

type Article struct {
	ID    string `json:"id"`
	Title string `json:"title"`
}

func ArticleCtx(next chi.Handler) chi.Handler {
	return chi.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		articleID := chi.URLParam(ctx, "articleID")
		article, err := dbGetArticle(articleID)
		if err != nil {
			http.Error(w, http.StatusText(404), 404)
			return
		}
		ctx = context.WithValue(ctx, "article", article)
		next.ServeHTTPC(ctx, w, r)
	})
}

func listArticles(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("list of articles.."))
	// or render.Data(w, 200, []byte("list of articles.."))
}

func createArticle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var article *Article

	// btw, you could do this body reading / marhsalling in a nice bind middleware
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), 422)
		return
	}
	defer r.Body.Close()

	if err := json.Unmarshal(data, &article); err != nil {
		http.Error(w, err.Error(), 422)
		return
	}

	// should really send back the json marshalled new article.
	// build your own responder :)
	w.Write([]byte(article.Title))
}

func getArticle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	article, ok := ctx.Value("article").(*Article)
	if !ok {
		http.Error(w, http.StatusText(422), 422)
		return
	}

	// Build your own responder, see the "./render" pacakge as a starting
	// point for your own.
	render.JSON(w, 200, article)

	// or..
	// w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
}

func updateArticle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	article, ok := ctx.Value("article").(*Article)
	if !ok {
		http.Error(w, http.StatusText(404), 404)
		return
	}

	// btw, you could do this body reading / marhsalling in a nice bind middleware
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), 422)
		return
	}
	defer r.Body.Close()

	uArticle := struct {
		*Article
		_ interface{} `json:"id,omitempty"` // prevents 'id' from being overridden
	}{Article: article}

	if err := json.Unmarshal(data, &uArticle); err != nil {
		http.Error(w, err.Error(), 422)
		return
	}

	render.JSON(w, 200, uArticle)

	// w.Write([]byte(fmt.Sprintf("updated article, title:%s", uArticle.Title)))
}

func deleteArticle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	article, ok := ctx.Value("article").(*Article)
	if !ok {
		http.Error(w, http.StatusText(422), 422)
		return
	}
	_ = article // delete the article from the data store..
	w.WriteHeader(204)
}

func dbGetArticle(id string) (*Article, error) {
	//.. fetch the article from a data store of some kind..
	return &Article{ID: id, Title: "Going all the way,"}, nil
}

func paginate(next chi.Handler) chi.Handler {
	return chi.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		// just a stub.. some ideas are to look at URL query params for something like
		// the page number, or the limit, and send a query cursor down the chain
		next.ServeHTTPC(ctx, w, r)
	})
}

// A completely separate router for administrator routes
func adminRouter() http.Handler { // or chi.Router {
	r := chi.NewRouter()
	r.Use(AdminOnly)
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("admin: index"))
	})
	r.Get("/accounts", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("admin: list accounts.."))
	})
	r.Get("/users/:userId", func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(fmt.Sprintf("admin: view user id %v", chi.URLParam(ctx, "userId"))))
	})
	return r
}

func AdminOnly(next chi.Handler) chi.Handler {
	return chi.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		isAdmin, ok := ctx.Value("acl.admin").(bool)
		if !ok || !isAdmin {
			http.Error(w, http.StatusText(403), 403)
			return
		}
		next.ServeHTTPC(ctx, w, r)
	})
}
<commit_msg>REST example using chi v2<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"time"

	"github.com/pressly/chi"
	"github.com/pressly/chi/middleware"
	"github.com/pressly/chi/render"
)

func main() {
	r := chi.NewRouter()

	r.Use(middleware.RequestID)
	r.Use(middleware.Logger)
	r.Use(middleware.Recoverer)

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("..."))
	})

	r.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("pong"))
	})

	r.Get("/panic", func(w http.ResponseWriter, r *http.Request) {
		panic("test")
	})

	// Slow handlers/operations.
	r.Group(func(r chi.Router) {
		// Stop processing when client disconnects.
		r.Use(middleware.CloseNotify)

		// Stop processing after 2.5 seconds.
		r.Use(middleware.Timeout(2500 * time.Millisecond))

		r.Get("/slow", func(w http.ResponseWriter, r *http.Request) {
			rand.Seed(time.Now().Unix())

			// Processing will take 1-5 seconds.
			processTime := time.Duration(rand.Intn(4)+1) * time.Second

			select {
			case <-r.Context().Done():
				return

			case <-time.After(processTime):
				// The above channel simulates some hard work.
			}

			w.Write([]byte(fmt.Sprintf("Processed in %v seconds\n", processTime)))
		})
	})

	// Throttle very expensive handlers/operations.
	r.Group(func(r chi.Router) {
		// Stop processing after 30 seconds.
		r.Use(middleware.Timeout(30 * time.Second))

		// Only one request will be processed at a time.
		r.Use(middleware.Throttle(1))

		r.Get("/throttled", func(w http.ResponseWriter, r *http.Request) {
			select {
			case <-r.Context().Done():
				switch r.Context().Err() {
				case context.DeadlineExceeded:
					w.WriteHeader(504)
					w.Write([]byte("Processing too slow\n"))
				default:
					w.Write([]byte("Canceled\n"))
				}
				return

			case <-time.After(5 * time.Second):
				// The above channel simulates some hard work.
			}

			w.Write([]byte("Processed\n"))
		})
	})

	// RESTy routes for "articles" resource
	r.Route("/articles", func(r chi.Router) {
		r.Group(func(r chi.Router) {
			r.Use(paginate)
			r.Get("/", listArticles) // GET /articles
		})
		r.Post("/", createArticle) // POST /articles

		r.Route("/:articleID", func(r chi.Router) {
			r.Use(ArticleCtx)
			r.Get("/", getArticle)       // GET /articles/123
			r.Put("/", updateArticle)    // PUT /articles/123
			r.Delete("/", deleteArticle) // DELETE /articles/123
		})
	})

	// Mount the admin sub-router
	r.Mount("/admin", adminRouter())

	http.ListenAndServe(":3333", r)
}

type Article struct {
	ID    string `json:"id"`
	Title string `json:"title"`
}

func ArticleCtx(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		articleID := chi.URLParam(r.Context(), "articleID")
		article, err := dbGetArticle(articleID)
		if err != nil {
			http.Error(w, http.StatusText(404), 404)
			return
		}
		ctx := context.WithValue(r.Context(), "article", article)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

func listArticles(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("list of articles.."))
	// or render.Data(w, 200, []byte("list of articles.."))
}

func createArticle(w http.ResponseWriter, r *http.Request) {
	var article *Article

	// btw, you could do this body reading / marhsalling in a nice bind middleware
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), 422)
		return
	}
	defer r.Body.Close()

	if err := json.Unmarshal(data, &article); err != nil {
		http.Error(w, err.Error(), 422)
		return
	}

	// should really send back the json marshalled new article.
	// build your own responder :)
	w.Write([]byte(article.Title))
}

func getArticle(w http.ResponseWriter, r *http.Request) {
	article, ok := r.Context().Value("article").(*Article)
	if !ok {
		http.Error(w, http.StatusText(422), 422)
		return
	}

	// Build your own responder, see the "./render" pacakge as a starting
	// point for your own.
	render.JSON(w, 200, article)

	// or..
	// w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
}

func updateArticle(w http.ResponseWriter, r *http.Request) {
	article, ok := r.Context().Value("article").(*Article)
	if !ok {
		http.Error(w, http.StatusText(404), 404)
		return
	}

	// btw, you could do this body reading / marhsalling in a nice bind middleware
	data, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), 422)
		return
	}
	defer r.Body.Close()

	uArticle := struct {
		*Article
		_ interface{} `json:"id,omitempty"` // prevents 'id' from being overridden
	}{Article: article}

	if err := json.Unmarshal(data, &uArticle); err != nil {
		http.Error(w, err.Error(), 422)
		return
	}

	render.JSON(w, 200, uArticle)

	// w.Write([]byte(fmt.Sprintf("updated article, title:%s", uArticle.Title)))
}

func deleteArticle(w http.ResponseWriter, r *http.Request) {
	article, ok := r.Context().Value("article").(*Article)
	if !ok {
		http.Error(w, http.StatusText(422), 422)
		return
	}
	_ = article // delete the article from the data store..
	w.WriteHeader(204)
}

func dbGetArticle(id string) (*Article, error) {
	//.. fetch the article from a data store of some kind..
	return &Article{ID: id, Title: "Going all the way,"}, nil
}

func paginate(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// just a stub.. some ideas are to look at URL query params for something like
		// the page number, or the limit, and send a query cursor down the chain
		next.ServeHTTP(w, r)
	})
}

// A completely separate router for administrator routes
func adminRouter() http.Handler { // or chi.Router {
	r := chi.NewRouter()
	r.Use(AdminOnly)
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("admin: index"))
	})
	r.Get("/accounts", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("admin: list accounts.."))
	})
	r.Get("/users/:userId", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(fmt.Sprintf("admin: view user id %v", chi.URLParam(r.Context(), "userId"))))
	})
	return r
}

func AdminOnly(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		isAdmin, ok := r.Context().Value("acl.admin").(bool)
		if !ok || !isAdmin {
			http.Error(w, http.StatusText(403), 403)
			return
		}
		next.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>package lnwire

// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go

import (
	"bytes"
	"fmt"
	"io"

	"github.com/roasbeef/btcd/wire"
)

// MessageHeaderSize is the number of bytes in a lightning message header.
// The bytes are allocated as follows: network magic 4 bytes + command 4
// bytes + payload length 4 bytes. Note that a checksum is omitted as lightning
// messages are assumed to be transmitted over an AEAD secured connection which
// provides integrity over the entire message.
const MessageHeaderSize = 12

// MaxMessagePayload is the maximum bytes a message can be regardless of other
// individual limits imposed by messages themselves.
const MaxMessagePayload = 1024 * 1024 * 32 //  32MB

// Commands used in lightning message headers which detail the type of message.
// TODO(roasbeef): update with latest type numbering from spec
const (
	CmdInit = uint32(1)

	// Commands for opening a channel funded by one party (single funder).
	CmdSingleFundingRequest      = uint32(100)
	CmdSingleFundingResponse     = uint32(110)
	CmdSingleFundingComplete     = uint32(120)
	CmdSingleFundingSignComplete = uint32(130)

	// Command for locking a funded channel
	CmdFundingLocked = uint32(200)

	// Commands for the workflow of cooperatively closing an active channel.
	CmdCloseRequest  = uint32(300)
	CmdCloseComplete = uint32(310)

	// Commands for negotiating HTLCs.
	CmdUpdateAddHTLC    = uint32(1000)
	CmdUpdateFufillHTLC = uint32(1010)
	CmdUpdateFailHTLC   = uint32(1020)

	// Commands for modifying commitment transactions.
	CmdCommitSig    = uint32(2000)
	CmdRevokeAndAck = uint32(2010)

	// Commands for reporting protocol errors.
	CmdError = uint32(4000)

	// Commands for discovery service.
	CmdChannelAnnouncement       = uint32(5000)
	CmdChannelUpdateAnnouncement = uint32(5010)
	CmdNodeAnnouncement          = uint32(5020)
	CmdAnnounceSignatures        = uint32(5030)

	// Commands for connection keep-alive.
	CmdPing = uint32(6000)
	CmdPong = uint32(6010)
)

// UnknownMessage is an implementation of the error interface that allows the
// creation of an error in response to an unknown message.
type UnknownMessage struct {
	messageType uint32
}

// Error returns a human readable string describing the error.
//
// This is part of the error interface.
func (u *UnknownMessage) Error() string {
	return fmt.Sprintf("unable to parse message of unknown type: %v",
		u.messageType)
}

// Message is an interface that defines a lightning wire protocol message. The
// interface is general in order to allow implementing types full control over
// the representation of its data.
type Message interface {
	Decode(io.Reader, uint32) error
	Encode(io.Writer, uint32) error
	Command() uint32
	MaxPayloadLength(uint32) uint32
}

// makeEmptyMessage creates a new empty message of the proper concrete type
// based on the command ID.
func makeEmptyMessage(command uint32) (Message, error) {
	var msg Message

	switch command {
	case CmdInit:
		msg = &Init{}
	case CmdSingleFundingRequest:
		msg = &SingleFundingRequest{}
	case CmdSingleFundingResponse:
		msg = &SingleFundingResponse{}
	case CmdSingleFundingComplete:
		msg = &SingleFundingComplete{}
	case CmdSingleFundingSignComplete:
		msg = &SingleFundingSignComplete{}
	case CmdFundingLocked:
		msg = &FundingLocked{}
	case CmdCloseRequest:
		msg = &CloseRequest{}
	case CmdCloseComplete:
		msg = &CloseComplete{}
	case CmdUpdateAddHTLC:
		msg = &UpdateAddHTLC{}
	case CmdUpdateFailHTLC:
		msg = &UpdateFailHTLC{}
	case CmdUpdateFufillHTLC:
		msg = &UpdateFufillHTLC{}
	case CmdCommitSig:
		msg = &CommitSig{}
	case CmdRevokeAndAck:
		msg = &RevokeAndAck{}
	case CmdError:
		msg = &Error{}
	case CmdChannelAnnouncement:
		msg = &ChannelAnnouncement{}
	case CmdChannelUpdateAnnouncement:
		msg = &ChannelUpdateAnnouncement{}
	case CmdNodeAnnouncement:
		msg = &NodeAnnouncement{}
	case CmdPing:
		msg = &Ping{}
	case CmdAnnounceSignatures:
		msg = &AnnounceSignatures{}
	case CmdPong:
		msg = &Pong{}
	default:
		return nil, fmt.Errorf("unhandled command [%d]", command)
	}

	return msg, nil
}

// messageHeader represents the header structure for all lightning protocol
// messages.
type messageHeader struct {
	// magic represents Which Blockchain Technology(TM) to use.
	// NOTE(j): We don't need to worry about the magic overlapping with
	// bitcoin since this is inside encrypted comms anyway, but maybe we
	// should use the XOR (^wire.TestNet3) just in case???
	magic   wire.BitcoinNet // 4 bytes
	command uint32          // 4 bytes
	length  uint32          // 4 bytes
}

// readMessageHeader reads a lightning protocol message header from r.
func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
	// As the message header is a fixed size structure, read bytes for the
	// entire header at once.
	var headerBytes [MessageHeaderSize]byte
	n, err := io.ReadFull(r, headerBytes[:])
	if err != nil {
		return n, nil, err
	}
	hr := bytes.NewReader(headerBytes[:])

	// Create and populate the message header from the raw header bytes.
	hdr := messageHeader{}
	err = readElements(hr,
		&hdr.magic,
		&hdr.command,
		&hdr.length)
	if err != nil {
		return n, nil, err
	}

	return n, &hdr, nil
}

// discardInput reads n bytes from reader r in chunks and discards the read
// bytes. This is used to skip payloads when various errors occur and helps
// prevent rogue nodes from causing massive memory allocation through forging
// header length.
func discardInput(r io.Reader, n uint32) {
	maxSize := uint32(10 * 1024) // 10k at a time
	numReads := n / maxSize
	bytesRemaining := n % maxSize
	if n > 0 {
		buf := make([]byte, maxSize)
		for i := uint32(0); i < numReads; i++ {
			io.ReadFull(r, buf)
		}
	}
	if bytesRemaining > 0 {
		buf := make([]byte, bytesRemaining)
		io.ReadFull(r, buf)
	}
}

// WriteMessage writes a lightning Message to w including the necessary header
// information and returns the number of bytes written.
func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet wire.BitcoinNet) (int, error) {
	totalBytes := 0

	cmd := msg.Command()

	// Encode the message payload
	var bw bytes.Buffer
	err := msg.Encode(&bw, pver)
	if err != nil {
		return totalBytes, err
	}
	payload := bw.Bytes()
	lenp := len(payload)

	// Enforce maximum overall message payload
	if lenp > MaxMessagePayload {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload is %d bytes",
			lenp, MaxMessagePayload)
	}

	// Enforce maximum message payload on the message type
	mpl := msg.MaxPayloadLength(pver)
	if uint32(lenp) > mpl {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload of "+
			"type %x is %d bytes", lenp, cmd, mpl)
	}

	// Create header for the message.
	hdr := messageHeader{magic: btcnet, command: cmd, length: uint32(lenp)}

	// Encode the header for the message. This is done to a buffer
	// rather than directly to the writer since writeElements doesn't
	// return the number of bytes written.
	hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
	if err := writeElements(hw, hdr.magic, hdr.command, hdr.length); err != nil {
		return 0, nil
	}

	// Write the header first.
	n, err := w.Write(hw.Bytes())
	totalBytes += n
	if err != nil {
		return totalBytes, err
	}

	// Write payload the payload itself after the header.
	n, err = w.Write(payload)
	totalBytes += n
	return totalBytes, err
}

// ReadMessage reads, validates, and parses the next bitcoin Message from r for
// the provided protocol version and bitcoin network.  It returns the number of
// bytes read in addition to the parsed Message and raw bytes which comprise the
// message.  This function is the same as ReadMessage except it also returns the
// number of bytes read.
func ReadMessage(r io.Reader, pver uint32, btcnet wire.BitcoinNet) (int, Message, []byte, error) {
	totalBytes := 0
	n, hdr, err := readMessageHeader(r)
	totalBytes += n
	if err != nil {
		return totalBytes, nil, nil, err
	}

	// Enforce maximum message payload
	if hdr.length > MaxMessagePayload {
		return totalBytes, nil, nil, fmt.Errorf("message payload is "+
			"too large - header indicates %d bytes, but max "+
			"message payload is %d bytes.", hdr.length,
			MaxMessagePayload)
	}

	// Check for messages in the wrong network.
	if hdr.magic != btcnet {
		discardInput(r, hdr.length)
		return totalBytes, nil, nil, fmt.Errorf("message from other "+
			"network [%v]", hdr.magic)
	}

	// Create struct of appropriate message type based on the command.
	command := hdr.command
	msg, err := makeEmptyMessage(command)
	if err != nil {
		discardInput(r, hdr.length)
		return totalBytes, nil, nil, &UnknownMessage{
			messageType: command,
		}
	}

	// Check for maximum length based on the message type.
	mpl := msg.MaxPayloadLength(pver)
	if hdr.length > mpl {
		discardInput(r, hdr.length)
		return totalBytes, nil, nil, fmt.Errorf("payload exceeds max "+
			"length. indicates %v bytes, but max of message type %v is %v.",
			hdr.length, command, mpl)
	}

	// Read payload.
	payload := make([]byte, hdr.length)
	n, err = io.ReadFull(r, payload)
	totalBytes += n
	if err != nil {
		return totalBytes, nil, nil, err
	}

	// Unmarshal message.
	pr := bytes.NewBuffer(payload)
	if err = msg.Decode(pr, pver); err != nil {
		return totalBytes, nil, nil, err
	}

	// Validate the data.
	if err = msg.Validate(); err != nil {
		return totalBytes, nil, nil, err
	}

	return totalBytes, msg, payload, nil
}
<commit_msg>lnwire: reduce the max message payload to 65KB from 32MB<commit_after>package lnwire

// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go

import (
	"bytes"
	"fmt"
	"io"

	"github.com/roasbeef/btcd/wire"
)

// MessageHeaderSize is the number of bytes in a lightning message header.
// The bytes are allocated as follows: network magic 4 bytes + command 4
// bytes + payload length 4 bytes. Note that a checksum is omitted as lightning
// messages are assumed to be transmitted over an AEAD secured connection which
// provides integrity over the entire message.
const MessageHeaderSize = 12

// MaxMessagePayload is the maximum bytes a message can be regardless of other
// individual limits imposed by messages themselves.

// Commands used in lightning message headers which detail the type of message.
// TODO(roasbeef): update with latest type numbering from spec
const (
	CmdInit = uint32(1)

	// Commands for opening a channel funded by one party (single funder).
	CmdSingleFundingRequest      = uint32(100)
	CmdSingleFundingResponse     = uint32(110)
	CmdSingleFundingComplete     = uint32(120)
	CmdSingleFundingSignComplete = uint32(130)

	// Command for locking a funded channel
	CmdFundingLocked = uint32(200)
const MaxMessagePayload = 65535 // 65KB

	// Commands for the workflow of cooperatively closing an active channel.
	CmdCloseRequest  = uint32(300)
	CmdCloseComplete = uint32(310)

	// Commands for negotiating HTLCs.
	CmdUpdateAddHTLC    = uint32(1000)
	CmdUpdateFufillHTLC = uint32(1010)
	CmdUpdateFailHTLC   = uint32(1020)

	// Commands for modifying commitment transactions.
	CmdCommitSig    = uint32(2000)
	CmdRevokeAndAck = uint32(2010)

	// Commands for reporting protocol errors.
	CmdError = uint32(4000)

	// Commands for discovery service.
	CmdChannelAnnouncement       = uint32(5000)
	CmdChannelUpdateAnnouncement = uint32(5010)
	CmdNodeAnnouncement          = uint32(5020)
	CmdAnnounceSignatures        = uint32(5030)

	// Commands for connection keep-alive.
	CmdPing = uint32(6000)
	CmdPong = uint32(6010)
)

// UnknownMessage is an implementation of the error interface that allows the
// creation of an error in response to an unknown message.
type UnknownMessage struct {
	messageType uint32
}

// Error returns a human readable string describing the error.
//
// This is part of the error interface.
func (u *UnknownMessage) Error() string {
	return fmt.Sprintf("unable to parse message of unknown type: %v",
		u.messageType)
}

// Message is an interface that defines a lightning wire protocol message. The
// interface is general in order to allow implementing types full control over
// the representation of its data.
type Message interface {
	Decode(io.Reader, uint32) error
	Encode(io.Writer, uint32) error
	Command() uint32
	MaxPayloadLength(uint32) uint32
}

// makeEmptyMessage creates a new empty message of the proper concrete type
// based on the command ID.
func makeEmptyMessage(command uint32) (Message, error) {
	var msg Message

	switch command {
	case CmdInit:
		msg = &Init{}
	case CmdSingleFundingRequest:
		msg = &SingleFundingRequest{}
	case CmdSingleFundingResponse:
		msg = &SingleFundingResponse{}
	case CmdSingleFundingComplete:
		msg = &SingleFundingComplete{}
	case CmdSingleFundingSignComplete:
		msg = &SingleFundingSignComplete{}
	case CmdFundingLocked:
		msg = &FundingLocked{}
	case CmdCloseRequest:
		msg = &CloseRequest{}
	case CmdCloseComplete:
		msg = &CloseComplete{}
	case CmdUpdateAddHTLC:
		msg = &UpdateAddHTLC{}
	case CmdUpdateFailHTLC:
		msg = &UpdateFailHTLC{}
	case CmdUpdateFufillHTLC:
		msg = &UpdateFufillHTLC{}
	case CmdCommitSig:
		msg = &CommitSig{}
	case CmdRevokeAndAck:
		msg = &RevokeAndAck{}
	case CmdError:
		msg = &Error{}
	case CmdChannelAnnouncement:
		msg = &ChannelAnnouncement{}
	case CmdChannelUpdateAnnouncement:
		msg = &ChannelUpdateAnnouncement{}
	case CmdNodeAnnouncement:
		msg = &NodeAnnouncement{}
	case CmdPing:
		msg = &Ping{}
	case CmdAnnounceSignatures:
		msg = &AnnounceSignatures{}
	case CmdPong:
		msg = &Pong{}
	default:
		return nil, fmt.Errorf("unhandled command [%d]", command)
	}

	return msg, nil
}

// messageHeader represents the header structure for all lightning protocol
// messages.
type messageHeader struct {
	// magic represents Which Blockchain Technology(TM) to use.
	// NOTE(j): We don't need to worry about the magic overlapping with
	// bitcoin since this is inside encrypted comms anyway, but maybe we
	// should use the XOR (^wire.TestNet3) just in case???
	magic   wire.BitcoinNet // 4 bytes
	command uint32          // 4 bytes
	length  uint32          // 4 bytes
}

// readMessageHeader reads a lightning protocol message header from r.
func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
	// As the message header is a fixed size structure, read bytes for the
	// entire header at once.
	var headerBytes [MessageHeaderSize]byte
	n, err := io.ReadFull(r, headerBytes[:])
	if err != nil {
		return n, nil, err
	}
	hr := bytes.NewReader(headerBytes[:])

	// Create and populate the message header from the raw header bytes.
	hdr := messageHeader{}
	err = readElements(hr,
		&hdr.magic,
		&hdr.command,
		&hdr.length)
	if err != nil {
		return n, nil, err
	}

	return n, &hdr, nil
}

// discardInput reads n bytes from reader r in chunks and discards the read
// bytes. This is used to skip payloads when various errors occur and helps
// prevent rogue nodes from causing massive memory allocation through forging
// header length.
func discardInput(r io.Reader, n uint32) {
	maxSize := uint32(10 * 1024) // 10k at a time
	numReads := n / maxSize
	bytesRemaining := n % maxSize
	if n > 0 {
		buf := make([]byte, maxSize)
		for i := uint32(0); i < numReads; i++ {
			io.ReadFull(r, buf)
		}
	}
	if bytesRemaining > 0 {
		buf := make([]byte, bytesRemaining)
		io.ReadFull(r, buf)
	}
}

// WriteMessage writes a lightning Message to w including the necessary header
// information and returns the number of bytes written.
func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet wire.BitcoinNet) (int, error) {
	totalBytes := 0

	cmd := msg.Command()

	// Encode the message payload
	var bw bytes.Buffer
	err := msg.Encode(&bw, pver)
	if err != nil {
		return totalBytes, err
	}
	payload := bw.Bytes()
	lenp := len(payload)

	// Enforce maximum overall message payload
	if lenp > MaxMessagePayload {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload is %d bytes",
			lenp, MaxMessagePayload)
	}

	// Enforce maximum message payload on the message type
	mpl := msg.MaxPayloadLength(pver)
	if uint32(lenp) > mpl {
		return totalBytes, fmt.Errorf("message payload is too large - "+
			"encoded %d bytes, but maximum message payload of "+
			"type %x is %d bytes", lenp, cmd, mpl)
	}

	// Create header for the message.
	hdr := messageHeader{magic: btcnet, command: cmd, length: uint32(lenp)}

	// Encode the header for the message. This is done to a buffer
	// rather than directly to the writer since writeElements doesn't
	// return the number of bytes written.
	hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
	if err := writeElements(hw, hdr.magic, hdr.command, hdr.length); err != nil {
		return 0, nil
	}

	// Write the header first.
	n, err := w.Write(hw.Bytes())
	totalBytes += n
	if err != nil {
		return totalBytes, err
	}

	// Write payload the payload itself after the header.
	n, err = w.Write(payload)
	totalBytes += n
	return totalBytes, err
}

// ReadMessage reads, validates, and parses the next bitcoin Message from r for
// the provided protocol version and bitcoin network.  It returns the number of
// bytes read in addition to the parsed Message and raw bytes which comprise the
// message.  This function is the same as ReadMessage except it also returns the
// number of bytes read.
func ReadMessage(r io.Reader, pver uint32, btcnet wire.BitcoinNet) (int, Message, []byte, error) {
	totalBytes := 0
	n, hdr, err := readMessageHeader(r)
	totalBytes += n
	if err != nil {
		return totalBytes, nil, nil, err
	}

	// Enforce maximum message payload
	if hdr.length > MaxMessagePayload {
		return totalBytes, nil, nil, fmt.Errorf("message payload is "+
			"too large - header indicates %d bytes, but max "+
			"message payload is %d bytes.", hdr.length,
			MaxMessagePayload)
	}

	// Check for messages in the wrong network.
	if hdr.magic != btcnet {
		discardInput(r, hdr.length)
		return totalBytes, nil, nil, fmt.Errorf("message from other "+
			"network [%v]", hdr.magic)
	}

	// Create struct of appropriate message type based on the command.
	command := hdr.command
	msg, err := makeEmptyMessage(command)
	if err != nil {
		discardInput(r, hdr.length)
		return totalBytes, nil, nil, &UnknownMessage{
			messageType: command,
		}
	}

	// Check for maximum length based on the message type.
	mpl := msg.MaxPayloadLength(pver)
	if hdr.length > mpl {
		discardInput(r, hdr.length)
		return totalBytes, nil, nil, fmt.Errorf("payload exceeds max "+
			"length. indicates %v bytes, but max of message type %v is %v.",
			hdr.length, command, mpl)
	}

	// Read payload.
	payload := make([]byte, hdr.length)
	n, err = io.ReadFull(r, payload)
	totalBytes += n
	if err != nil {
		return totalBytes, nil, nil, err
	}

	// Unmarshal message.
	pr := bytes.NewBuffer(payload)
	if err = msg.Decode(pr, pver); err != nil {
		return totalBytes, nil, nil, err
	}

	// Validate the data.
	if err = msg.Validate(); err != nil {
		return totalBytes, nil, nil, err
	}

	return totalBytes, msg, payload, nil
}
<|endoftext|>


<commit_before>package datamanclient

import (
	"context"
	"time"

	"github.com/jacksontj/dataman/src/query"
)

// TODO: support per-query config?
// TODO support switching config in-flight? If so then we'll need to store a
// pointer to it in the context -- which would require implementing one ourself
type Client struct {
	Transport DatamanClientTransport
	// TODO: config
}

// TODO: add these convenience methods
/*
   Get(query.QueryArgs) *query.Result
   Set(query.QueryArgs) *query.Result
   Insert(query.QueryArgs) *query.Result
   Update(query.QueryArgs) *query.Result
   Delete(query.QueryArgs) *query.Result
*/

// DoQuery will execute a given query. This will return a (result, error) -- where the
// error is any transport level error (NOTE: any response errors due to the query will *not*
// be reported in this error, they will be in the normal Result.Error location)
func (d *Client) DoQuery(ctx context.Context, q *query.Query) (*query.Result, error) {
	// TODO: timeout should come from config
	c, cancel := context.WithTimeout(ctx, time.Second)
	defer cancel() // Cancel ctx as soon as handleSearch returns.

	results, err := d.Transport.DoQuery(c, q)
	if err != nil {
		return nil, err
	} else {
		return results, err
	}
}
<commit_msg>Remove hard-coded 1s timeout for now<commit_after>package datamanclient

import (
	"context"

	"github.com/jacksontj/dataman/src/query"
)

// TODO: support per-query config?
// TODO support switching config in-flight? If so then we'll need to store a
// pointer to it in the context -- which would require implementing one ourself
type Client struct {
	Transport DatamanClientTransport
	// TODO: config (timeout, etc).
}

// TODO: add these convenience methods
/*
   Get(query.QueryArgs) *query.Result
   Set(query.QueryArgs) *query.Result
   Insert(query.QueryArgs) *query.Result
   Update(query.QueryArgs) *query.Result
   Delete(query.QueryArgs) *query.Result
*/

// DoQuery will execute a given query. This will return a (result, error) -- where the
// error is any transport level error (NOTE: any response errors due to the query will *not*
// be reported in this error, they will be in the normal Result.Error location)
func (d *Client) DoQuery(ctx context.Context, q *query.Query) (*query.Result, error) {
	c, cancel := context.WithCancel(ctx)
	defer cancel() // Cancel ctx as soon as handleSearch returns.

	results, err := d.Transport.DoQuery(c, q)
	if err != nil {
		return nil, err
	} else {
		return results, err
	}
}
<|endoftext|>


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

// This file provides an implementation of the FileSystem
// interface based on the contents of a .zip file.
//
// Assumptions:
//
// - The file paths stored in the zip file must use a slash ('/') as path
//   separator; and they must be relative (i.e., they must not start with
//   a '/' - this is usually the case if the file was created w/o special
//   options).
// - The zip file system treats the file paths found in the zip internally
//   like absolute paths w/o a leading '/'; i.e., the paths are considered
//   relative to the root of the file system.
// - All path arguments to file system methods must be absolute paths.

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"sort"
	"strings"
)

// zipFI is the zip-file based implementation of FileInfo
type zipFI struct {
	name string    // directory-local name
	file *zip.File // nil for a directory
}

func (fi zipFI) Name() string {
	return fi.name
}

func (fi zipFI) Size() int64 {
	if f := fi.file; f != nil {
		return int64(f.UncompressedSize)
	}
	return 0 // directory
}

func (fi zipFI) Mtime_ns() int64 {
	if f := fi.file; f != nil {
		return f.Mtime_ns()
	}
	return 0 // directory has no modified time entry
}

func (fi zipFI) IsDirectory() bool {
	return fi.file == nil
}

func (fi zipFI) IsRegular() bool {
	return fi.file != nil
}

// zipFS is the zip-file based implementation of FileSystem
type zipFS struct {
	*zip.ReadCloser
	list zipList
}

func (fs *zipFS) Close() os.Error {
	fs.list = nil
	return fs.ReadCloser.Close()
}

func zipPath(name string) string {
	name = path.Clean(name)
	if !path.IsAbs(name) {
		panic(fmt.Sprintf("stat: not an absolute path: %s", name))
	}
	return name[1:] // strip leading '/'
}

func (fs *zipFS) stat(abspath string) (int, zipFI, os.Error) {
	i, exact := fs.list.lookup(abspath)
	if i < 0 {
		// abspath has leading '/' stripped - print it explicitly
		return -1, zipFI{}, fmt.Errorf("file not found: /%s", abspath)
	}
	_, name := path.Split(abspath)
	var file *zip.File
	if exact {
		file = fs.list[i] // exact match found - must be a file
	}
	return i, zipFI{name, file}, nil
}

func (fs *zipFS) Open(abspath string) (io.ReadCloser, os.Error) {
	_, fi, err := fs.stat(zipPath(abspath))
	if err != nil {
		return nil, err
	}
	if fi.IsDirectory() {
		return nil, fmt.Errorf("Open: %s is a directory", abspath)
	}
	return fi.file.Open()
}

func (fs *zipFS) Lstat(abspath string) (FileInfo, os.Error) {
	_, fi, err := fs.stat(zipPath(abspath))
	return fi, err
}

func (fs *zipFS) Stat(abspath string) (FileInfo, os.Error) {
	_, fi, err := fs.stat(zipPath(abspath))
	return fi, err
}

func (fs *zipFS) ReadDir(abspath string) ([]FileInfo, os.Error) {
	path := zipPath(abspath)
	i, fi, err := fs.stat(path)
	if err != nil {
		return nil, err
	}
	if !fi.IsDirectory() {
		return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
	}

	var list []FileInfo
	dirname := path + "/"
	prevname := ""
	for _, e := range fs.list[i:] {
		if !strings.HasPrefix(e.Name, dirname) {
			break // not in the same directory anymore
		}
		name := e.Name[len(dirname):] // local name
		file := e
		if i := strings.IndexRune(name, '/'); i >= 0 {
			// We infer directories from files in subdirectories.
			// If we have x/y, return a directory entry for x.
			name = name[0:i] // keep local directory name only
			file = nil
		}
		// If we have x/y and x/z, don't return two directory entries for x.
		// TODO(gri): It should be possible to do this more efficiently
		// by determining the (fs.list) range of local directory entries
		// (via two binary searches).
		if name != prevname {
			list = append(list, zipFI{name, file})
			prevname = name
		}
	}

	return list, nil
}

func (fs *zipFS) ReadFile(abspath string) ([]byte, os.Error) {
	rc, err := fs.Open(abspath)
	if err != nil {
		return nil, err
	}
	return ioutil.ReadAll(rc)
}

func NewZipFS(rc *zip.ReadCloser) FileSystem {
	list := make(zipList, len(rc.File))
	copy(list, rc.File) // sort a copy of rc.File
	sort.Sort(list)
	return &zipFS{rc, list}
}

type zipList []*zip.File

// zipList implements sort.Interface
func (z zipList) Len() int           { return len(z) }
func (z zipList) Less(i, j int) bool { return z[i].Name < z[j].Name }
func (z zipList) Swap(i, j int)      { z[i], z[j] = z[j], z[i] }

// lookup returns the smallest index of an entry with an exact match
// for name, or an inexact match starting with name/. If there is no
// such entry, the result is -1, false.
func (z zipList) lookup(name string) (index int, exact bool) {
	// look for exact match first (name comes before name/ in z)
	i := sort.Search(len(z), func(i int) bool {
		return name <= z[i].Name
	})
	if i < 0 {
		return -1, false
	}
	if z[i].Name == name {
		return i, true
	}

	// look for inexact match (must be in z[i:], if present)
	z = z[i:]
	name += "/"
	j := sort.Search(len(z), func(i int) bool {
		return name <= z[i].Name
	})
	if j < 0 {
		return -1, false
	}
	if strings.HasPrefix(z[j].Name, name) {
		return i + j, false
	}

	return -1, false
}
<commit_msg>godoc: fix bug in zip.go<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file provides an implementation of the FileSystem
// interface based on the contents of a .zip file.
//
// Assumptions:
//
// - The file paths stored in the zip file must use a slash ('/') as path
//   separator; and they must be relative (i.e., they must not start with
//   a '/' - this is usually the case if the file was created w/o special
//   options).
// - The zip file system treats the file paths found in the zip internally
//   like absolute paths w/o a leading '/'; i.e., the paths are considered
//   relative to the root of the file system.
// - All path arguments to file system methods must be absolute paths.

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"sort"
	"strings"
)

// zipFI is the zip-file based implementation of FileInfo
type zipFI struct {
	name string    // directory-local name
	file *zip.File // nil for a directory
}

func (fi zipFI) Name() string {
	return fi.name
}

func (fi zipFI) Size() int64 {
	if f := fi.file; f != nil {
		return int64(f.UncompressedSize)
	}
	return 0 // directory
}

func (fi zipFI) Mtime_ns() int64 {
	if f := fi.file; f != nil {
		return f.Mtime_ns()
	}
	return 0 // directory has no modified time entry
}

func (fi zipFI) IsDirectory() bool {
	return fi.file == nil
}

func (fi zipFI) IsRegular() bool {
	return fi.file != nil
}

// zipFS is the zip-file based implementation of FileSystem
type zipFS struct {
	*zip.ReadCloser
	list zipList
}

func (fs *zipFS) Close() os.Error {
	fs.list = nil
	return fs.ReadCloser.Close()
}

func zipPath(name string) string {
	name = path.Clean(name)
	if !path.IsAbs(name) {
		panic(fmt.Sprintf("stat: not an absolute path: %s", name))
	}
	return name[1:] // strip leading '/'
}

func (fs *zipFS) stat(abspath string) (int, zipFI, os.Error) {
	i, exact := fs.list.lookup(abspath)
	if i < 0 {
		// abspath has leading '/' stripped - print it explicitly
		return -1, zipFI{}, fmt.Errorf("file not found: /%s", abspath)
	}
	_, name := path.Split(abspath)
	var file *zip.File
	if exact {
		file = fs.list[i] // exact match found - must be a file
	}
	return i, zipFI{name, file}, nil
}

func (fs *zipFS) Open(abspath string) (io.ReadCloser, os.Error) {
	_, fi, err := fs.stat(zipPath(abspath))
	if err != nil {
		return nil, err
	}
	if fi.IsDirectory() {
		return nil, fmt.Errorf("Open: %s is a directory", abspath)
	}
	return fi.file.Open()
}

func (fs *zipFS) Lstat(abspath string) (FileInfo, os.Error) {
	_, fi, err := fs.stat(zipPath(abspath))
	return fi, err
}

func (fs *zipFS) Stat(abspath string) (FileInfo, os.Error) {
	_, fi, err := fs.stat(zipPath(abspath))
	return fi, err
}

func (fs *zipFS) ReadDir(abspath string) ([]FileInfo, os.Error) {
	path := zipPath(abspath)
	i, fi, err := fs.stat(path)
	if err != nil {
		return nil, err
	}
	if !fi.IsDirectory() {
		return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
	}

	var list []FileInfo
	dirname := path + "/"
	prevname := ""
	for _, e := range fs.list[i:] {
		if !strings.HasPrefix(e.Name, dirname) {
			break // not in the same directory anymore
		}
		name := e.Name[len(dirname):] // local name
		file := e
		if i := strings.IndexRune(name, '/'); i >= 0 {
			// We infer directories from files in subdirectories.
			// If we have x/y, return a directory entry for x.
			name = name[0:i] // keep local directory name only
			file = nil
		}
		// If we have x/y and x/z, don't return two directory entries for x.
		// TODO(gri): It should be possible to do this more efficiently
		// by determining the (fs.list) range of local directory entries
		// (via two binary searches).
		if name != prevname {
			list = append(list, zipFI{name, file})
			prevname = name
		}
	}

	return list, nil
}

func (fs *zipFS) ReadFile(abspath string) ([]byte, os.Error) {
	rc, err := fs.Open(abspath)
	if err != nil {
		return nil, err
	}
	return ioutil.ReadAll(rc)
}

func NewZipFS(rc *zip.ReadCloser) FileSystem {
	list := make(zipList, len(rc.File))
	copy(list, rc.File) // sort a copy of rc.File
	sort.Sort(list)
	return &zipFS{rc, list}
}

type zipList []*zip.File

// zipList implements sort.Interface
func (z zipList) Len() int           { return len(z) }
func (z zipList) Less(i, j int) bool { return z[i].Name < z[j].Name }
func (z zipList) Swap(i, j int)      { z[i], z[j] = z[j], z[i] }

// lookup returns the smallest index of an entry with an exact match
// for name, or an inexact match starting with name/. If there is no
// such entry, the result is -1, false.
func (z zipList) lookup(name string) (index int, exact bool) {
	// look for exact match first (name comes before name/ in z)
	i := sort.Search(len(z), func(i int) bool {
		return name <= z[i].Name
	})
	if i >= len(z) {
		return -1, false
	}
	// 0 <= i < len(z)
	if z[i].Name == name {
		return i, true
	}

	// look for inexact match (must be in z[i:], if present)
	z = z[i:]
	name += "/"
	j := sort.Search(len(z), func(i int) bool {
		return name <= z[i].Name
	})
	if j >= len(z) {
		return -1, false
	}
	// 0 <= j < len(z)
	if strings.HasPrefix(z[j].Name, name) {
		return i + j, false
	}

	return -1, false
}
<|endoftext|>


<commit_before>package perceptron

import (
	"github.com/mitsuse/perceptron-go/trie"
)

type Indexer struct {
	trie *trie.SimpleTrie
	size int
}

func NewIndexer() *Indexer {
	i := &Indexer{
		trie: trie.NewSimpleTrie(),
		size: 0,
	}

	return i
}

func (i *Indexer) Size() int {
	return i.size
}

func (i *Indexer) Index(identifier []int32, indexed bool) int {
	var index int

	if indexed {
		node, inserted := i.trie.Update(identifier)
		if inserted {
			i.size++
			node.SetValue(i.size)
		}

		index = node.Value()
	} else {
		node, exist := i.trie.Get(identifier)
		if exist {
			index = node.Value()
		}
	}

	return index
}
<commit_msg>Fix: "(Trie).Update" returns "true" if the key already exists.<commit_after>package perceptron

import (
	"github.com/mitsuse/perceptron-go/trie"
)

type Indexer struct {
	trie *trie.SimpleTrie
	size int
}

func NewIndexer() *Indexer {
	i := &Indexer{
		trie: trie.NewSimpleTrie(),
		size: 0,
	}

	return i
}

func (i *Indexer) Size() int {
	return i.size
}

func (i *Indexer) Index(identifier []int32, indexed bool) int {
	var index int

	if indexed {
		node, exist := i.trie.Update(identifier)
		if !exist {
			i.size++
			node.SetValue(i.size)
		}

		index = node.Value()
	} else {
		node, exist := i.trie.Get(identifier)
		if exist {
			index = node.Value()
		}
	}

	return index
}
<|endoftext|>


<commit_before>package logd

import (
	"bytes"
	"errors"
	"strings"
	"testing"

	"github.com/ArdanStudios/aggserver/testUtils"
)

func TestLevelSwitch(t *testing.T) {
	var buff bytes.Buffer
	var dev = New("app", &buff)
	SwitchTestModeOn(dev)

	dev.Log("4021", InfoLevel, "LoadConfig", "Configuratio Loaded")

	dev.SwitchLevel(ErrorLevel)

	// this will be ignored if its level is below the current set log level
	dev.Log("4021", InfoLevel, "LoadConfig", "loading app.config file from disk")

	dev.SwitchLevel(DataTraceLevel)
	dev.Log("4021", InfoLevel, "LoadConfig", "loading app.config file errored out", errors.New("File Not Found!"))
}

func TestDefaultLogger(t *testing.T) {
	var buff bytes.Buffer
	useTestModeLog(&buff)

	User("4021", InfoLevel, "LoadConfig#40", "Configuratio Loaded")

	if !strings.Contains(buff.String(), "Context: 4021") {
		testUtils.Fail(t, "Invalid Context in log message")
	}

	if strings.Contains(buff.String(), "Func: LoadConfig#40") {
		testUtils.Fail(t, "log in user mode should not contain functiona")
	}

	buff.Reset()
	Dev("3041", InfoLevel, "LoadConfig#20", "loading app.config file from disk")

	if !strings.Contains(buff.String(), "Message: loading app.config file from disk") {
		testUtils.Fail(t, "Invalid message value in log")
	}

	Dev("3041", InfoLevel, "LoadConfig#20", "loading app.config file from disk")

	if !strings.Contains(buff.String(), "Func: LoadConfig#20") {
		testUtils.Fail(t, "Invalid functiona name value in log")
	}

}

// TestBasicLogging tests the output response from using the log api
func TestBasicLogging(t *testing.T) {
	var buff bytes.Buffer
	var dev = New("boss", &buff)

	ctx := "3432"
	lvl := InfoLevel
	funcName := "CallRouters#300:36"
	Message := "Initializing Routing Stats"

	// dev.SwitchMode(User)
	dev.Log(ctx, lvl, funcName, Message)
	testRes := basicFormatter(dev, ctx, funcName, Message, nil)

	if buff.String() != testRes {
		t.Fatalf("Invalid response with expected output: Expected %s got %s", testRes, buff.String())
	}

	t.Log("Basic Log format passed")
}

// Switch logLevel to DataTrace and send out some data to include in the trace lines
func TestModeLogging(t *testing.T) {
	var buff bytes.Buffer
	var dev = New("boss", &buff)

	ctx := "go.4321"
	funcName := "Agg.WriteResponse#30:3"
	Message := "Sending Response Body"

	// ByteFormatter turns bytes into readable format using hex notation:
	/*<Data
			   0x000: 00 01 03 05 10 ...
	  Data>\n\r
	*/

	var bo = ByteFormatter([]byte(`Thunder routers`))

	//test in dev mode first
	dev.Log(ctx, DataTraceLevel, funcName, Message, bo)
	devtestRes := basicFormatter(dev, ctx, funcName, Message, bo)

	if buff.String() != devtestRes {
		t.Fatalf("Invalid response with expected output in dev mode: Expected %s got %s", devtestRes, buff.String())
	}

	buff.Reset()
	//switch into user mode
	dev.SwitchMode(UserMode)

	dev.Log(ctx, DataTraceLevel, funcName, Message, bo)
	usertestRes := basicFormatter(dev, ctx, funcName, Message+bo.Format(), nil)

	if buff.String() != usertestRes {
		t.Fatalf("Invalid response with expected output in user mode: Expected %s got %s", usertestRes, buff.String())
	}

}
<commit_msg>reupdated log to use modes<commit_after>package logd

import (
	"bytes"
	"errors"
	"strings"
	"testing"

	"github.com/ArdanStudios/aggserver/testUtils"
)

func TestLevelSwitch(t *testing.T) {
	var buff bytes.Buffer
	var dev = New("app", &buff)
	SwitchTestModeOn(dev)

	dev.Log("4021", InfoLevel, "LoadConfig", "Configuratio Loaded")

	dev.SwitchLevel(ErrorLevel)

	// this will be ignored if its level is below the current set log level
	dev.Log("4021", InfoLevel, "LoadConfig", "loading app.config file from disk")

	dev.SwitchLevel(DataTraceLevel)
	dev.Log("4021", InfoLevel, "LoadConfig", "loading app.config file errored out", errors.New("File Not Found!"))
}

func TestDefaultLogger(t *testing.T) {
	var buff bytes.Buffer
	useTestModeLog(&buff)

	User("4021", InfoLevel, "LoadConfig#40", "Configuratio Loaded")

	if !strings.Contains(buff.String(), "Context: 4021") {
		testUtils.Fail(t, "Invalid Context in log message")
	}

	if strings.Contains(buff.String(), "Func: LoadConfig#40") {
		testUtils.Fail(t, "log in user mode should not contain functiona")
	}

	buff.Reset()
	Dev("3041", InfoLevel, "LoadConfig#20", "loading app.config file from disk")

	if !strings.Contains(buff.String(), "Message: loading app.config file from disk") {
		testUtils.Fail(t, "Invalid message value in log")
	}

	Dev("3041", InfoLevel, "LoadConfig#20", "loading app.config file from disk")

	if !strings.Contains(buff.String(), "Func: LoadConfig#20") {
		testUtils.Fail(t, "Invalid functiona name value in log")
	}

}

// TestBasicLogging tests the output response from using the log api
func TestBasicLogging(t *testing.T) {
	var buff bytes.Buffer
	var dev = New("boss", &buff)

	ctx := "3432"
	lvl := InfoLevel
	funcName := "CallRouters#300:36"
	Message := "Initializing Routing Stats"

	// dev.SwitchMode(User)
	dev.Log(ctx, lvl, funcName, Message)
	testRes := basicFormatter(dev, ctx, funcName, Message, nil)

	if buff.String() != testRes {
		t.Fatalf("Invalid response with expected output: Expected %s got %s", testRes, buff.String())
	}

	t.Log("Basic Log format passed")
}

// Switch logLevel to DataTrace and send out some data to include in the trace lines
func TestModeLogging(t *testing.T) {
	var buff bytes.Buffer
	var dev = New("boss", &buff)

	ctx := "go.4321"
	funcName := "Agg.WriteResponse#30:3"
	Message := "Sending Response Body"

	// ByteFormatter turns bytes into readable format using hex notation:
	/*<Data
			   0x000: 00 01 03 05 10 ...
	  Data>\n\r
	*/

	var bo = ByteFormatter([]byte(`Thunder routers`))

	//test in dev mode first
	// I believe trace data dumps will print out any formaters when in dev modes
	dev.Log(ctx, DataTraceLevel, funcName, Message, bo)
	devtestRes := basicFormatter(dev, ctx, funcName, Message, bo)

	if buff.String() != devtestRes {
		t.Fatalf("Invalid response with expected output in dev mode: Expected %s got %s", devtestRes, buff.String())
	}

	buff.Reset()

	//switch into user mode
	dev.SwitchMode(UserMode)

	// I believe trace data dumps will ignore any formaters when in user modes
	dev.Log(ctx, DataTraceLevel, funcName, Message, bo)
	usertestRes := basicFormatter(dev, ctx, funcName, Message, bo)

	if buff.String() != usertestRes {
		t.Fatalf("Invalid response with expected output in user mode: Expected %s got %s", usertestRes, buff.String())
	}

}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"strings"
	"time"

	"github.com/slugalisk/overrustlelogs/common"
)

// DestinyLogger logger
type DestinyLogger struct {
	logs *ChatLogs
}

// NewDestinyLogger instantiates destiny chat logger
func NewDestinyLogger(logs *ChatLogs) *DestinyLogger {
	return &DestinyLogger{
		logs: logs,
	}
}

// Log starts logging loop
func (d *DestinyLogger) Log(mc <-chan *common.Message) {
	for {
		m := <-mc

		switch m.Command {
		case "BAN":
			d.writeLine(m.Time, "Ban", m.Data+" banned by "+m.Nick)
		case "UNBAN":
			d.writeLine(m.Time, "Ban", m.Data+" unbanned by "+m.Nick)
		case "MUTE":
			d.writeLine(m.Time, "Ban", m.Data+" muted by "+m.Nick)
		case "UNMUTE":
			d.writeLine(m.Time, "Ban", m.Data+" unmuted by "+m.Nick)
		case "BROADCAST":
			if strings.Contains(m.Data, "subscriber!") || strings.Contains(m.Data, "subscribed on Twitch!") {
				d.writeLine(m.Time, "Subscriber", m.Data)
			}
		case "MSG":
			d.writeLine(m.Time, m.Nick, m.Data)
		}
	}
}

func (d *DestinyLogger) writeLine(timestamp time.Time, nick string, message string) {
	l, err := d.logs.Get(common.GetConfig().LogPath + "/Destinygg chatlog/" + timestamp.Format("January 2006") + "/" + timestamp.Format("2006-01-02") + ".txt")
	if err != nil {
		log.Printf("error opening log %s", err)
		return
	}
	l.Write(timestamp, nick, message)
}
<commit_msg>new subscriber message<commit_after>package main

import (
	"log"
	"strings"
	"time"

	"github.com/slugalisk/overrustlelogs/common"
)

// DestinyLogger logger
type DestinyLogger struct {
	logs *ChatLogs
}

// NewDestinyLogger instantiates destiny chat logger
func NewDestinyLogger(logs *ChatLogs) *DestinyLogger {
	return &DestinyLogger{
		logs: logs,
	}
}

// Log starts logging loop
func (d *DestinyLogger) Log(mc <-chan *common.Message) {
	for {
		m := <-mc

		switch m.Command {
		case "BAN":
			d.writeLine(m.Time, "Ban", m.Data+" banned by "+m.Nick)
		case "UNBAN":
			d.writeLine(m.Time, "Ban", m.Data+" unbanned by "+m.Nick)
		case "MUTE":
			d.writeLine(m.Time, "Ban", m.Data+" muted by "+m.Nick)
		case "UNMUTE":
			d.writeLine(m.Time, "Ban", m.Data+" unmuted by "+m.Nick)
		case "BROADCAST":
			if strings.Contains(m.Data, "subscriber!") || strings.Contains(m.Data, "subscribed on Twitch!") || strings.Contains(m.Data, "has resubscribed! Active for") {
				d.writeLine(m.Time, "Subscriber", m.Data)
			}
		case "MSG":
			d.writeLine(m.Time, m.Nick, m.Data)
		}
	}
}

func (d *DestinyLogger) writeLine(timestamp time.Time, nick string, message string) {
	l, err := d.logs.Get(common.GetConfig().LogPath + "/Destinygg chatlog/" + timestamp.Format("January 2006") + "/" + timestamp.Format("2006-01-02") + ".txt")
	if err != nil {
		log.Printf("error opening log %s", err)
		return
	}
	l.Write(timestamp, nick, message)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"sync"
	"syscall"
	"time"

	"gopkg.in/lxc/go-lxc.v2"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

var containersCmd = Command{
	name: "containers",
	get:  containersGet,
	post: containersPost,
}

var containerCmd = Command{
	name:   "containers/{name}",
	get:    containerGet,
	put:    containerPut,
	delete: containerDelete,
	post:   containerPost,
}

var containerStateCmd = Command{
	name: "containers/{name}/state",
	get:  containerState,
	put:  containerStatePut,
}

var containerFileCmd = Command{
	name: "containers/{name}/files",
	get:  containerFileHandler,
	post: containerFileHandler,
}

var containerSnapshotsCmd = Command{
	name: "containers/{name}/snapshots",
	get:  containerSnapshotsGet,
	post: containerSnapshotsPost,
}

var containerSnapshotCmd = Command{
	name:   "containers/{name}/snapshots/{snapshotName}",
	get:    snapshotHandler,
	post:   snapshotHandler,
	delete: snapshotHandler,
}

var containerExecCmd = Command{
	name: "containers/{name}/exec",
	post: containerExecPost,
}

func containersRestart(d *Daemon) error {
	containers, err := doContainersGet(d, true)

	if err != nil {
		return err
	}

	containerInfo := containers.(shared.ContainerInfoList)
	sort.Sort(containerInfo)

	for _, container := range containerInfo {
		lastState := container.State.Config["volatile.last_state.power"]

		autoStart := container.State.ExpandedConfig["boot.autostart"]
		autoStartDelay := container.State.ExpandedConfig["boot.autostart.delay"]

		if lastState == "RUNNING" || autoStart == "true" {
			c, err := containerLoadByName(d, container.State.Name)
			if err != nil {
				return err
			}

			if c.IsRunning() {
				continue
			}

			c.Start()

			autoStartDelayInt, err := strconv.Atoi(autoStartDelay)
			if err == nil {
				time.Sleep(time.Duration(autoStartDelayInt) * time.Second)
			}
		}
	}

	_, err = dbExec(d.db, "DELETE FROM containers_config WHERE key='volatile.last_state.power'")
	if err != nil {
		return err
	}

	return nil
}

func containersShutdown(d *Daemon) error {
	results, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	var wg sync.WaitGroup

	for _, r := range results {
		c, err := containerLoadByName(d, r)
		if err != nil {
			return err
		}

		err = c.ConfigKeySet("volatile.last_state.power", c.State())

		if err != nil {
			return err
		}

		if c.IsRunning() {
			wg.Add(1)
			go func() {
				c.Shutdown(time.Second * 30)
				c.Stop()
				wg.Done()
			}()
		}
		wg.Wait()
	}

	return nil
}

func containerDeleteSnapshots(d *Daemon, cname string) error {
	shared.Log.Debug("containerDeleteSnapshots",
		log.Ctx{"container": cname})

	results, err := dbContainerGetSnapshots(d.db, cname)
	if err != nil {
		return err
	}

	for _, sname := range results {
		sc, err := containerLoadByName(d, sname)
		if err != nil {
			shared.Log.Error(
				"containerDeleteSnapshots: Failed to load the snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname})

			continue
		}

		if err := sc.Delete(); err != nil {
			shared.Log.Error(
				"containerDeleteSnapshots: Failed to delete a snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname, "err": err})
		}
	}

	return nil
}

/*
 * This is called by lxd when called as "lxd forkstart <container>"
 * 'forkstart' is used instead of just 'start' in the hopes that people
 * do not accidentally type 'lxd start' instead of 'lxc start'
 *
 * We expect to read the lxcconfig over fd 3.
 */
func startContainer(args []string) error {
	if len(args) != 4 {
		return fmt.Errorf("Bad arguments: %q", args)
	}

	name := args[1]
	lxcpath := args[2]
	configPath := args[3]

	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		return fmt.Errorf("Error initializing container for start: %q", err)
	}

	err = c.LoadConfigFile(configPath)
	if err != nil {
		return fmt.Errorf("Error opening startup config file: %q", err)
	}

	/* due to https://github.com/golang/go/issues/13155 and the
	 * CollectOutput call we make for the forkstart process, we need to
	 * close our stdin/stdout/stderr here. Collecting some of the logs is
	 * better than collecting no logs, though.
	 */
	os.Stdin.Close()
	os.Stderr.Close()
	os.Stdout.Close()

	// Redirect stdout and stderr to a log file
	logPath := shared.LogPath(name, "forkstart.log")
	if shared.PathExists(logPath) {
		os.Remove(logPath)
	}

	logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err == nil {
		syscall.Dup2(int(logFile.Fd()), 1)
		syscall.Dup2(int(logFile.Fd()), 2)
	}

	// Move the config so we can inspect it on failure
	shared.FileMove(configPath, shared.LogPath(name, "lxc.conf"))

	return c.Start()
}
<commit_msg>Fix arm64 build<commit_after>package main

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"sync"
	"syscall"
	"time"

	"gopkg.in/lxc/go-lxc.v2"

	"github.com/lxc/lxd/shared"

	log "gopkg.in/inconshreveable/log15.v2"
)

var containersCmd = Command{
	name: "containers",
	get:  containersGet,
	post: containersPost,
}

var containerCmd = Command{
	name:   "containers/{name}",
	get:    containerGet,
	put:    containerPut,
	delete: containerDelete,
	post:   containerPost,
}

var containerStateCmd = Command{
	name: "containers/{name}/state",
	get:  containerState,
	put:  containerStatePut,
}

var containerFileCmd = Command{
	name: "containers/{name}/files",
	get:  containerFileHandler,
	post: containerFileHandler,
}

var containerSnapshotsCmd = Command{
	name: "containers/{name}/snapshots",
	get:  containerSnapshotsGet,
	post: containerSnapshotsPost,
}

var containerSnapshotCmd = Command{
	name:   "containers/{name}/snapshots/{snapshotName}",
	get:    snapshotHandler,
	post:   snapshotHandler,
	delete: snapshotHandler,
}

var containerExecCmd = Command{
	name: "containers/{name}/exec",
	post: containerExecPost,
}

func containersRestart(d *Daemon) error {
	containers, err := doContainersGet(d, true)

	if err != nil {
		return err
	}

	containerInfo := containers.(shared.ContainerInfoList)
	sort.Sort(containerInfo)

	for _, container := range containerInfo {
		lastState := container.State.Config["volatile.last_state.power"]

		autoStart := container.State.ExpandedConfig["boot.autostart"]
		autoStartDelay := container.State.ExpandedConfig["boot.autostart.delay"]

		if lastState == "RUNNING" || autoStart == "true" {
			c, err := containerLoadByName(d, container.State.Name)
			if err != nil {
				return err
			}

			if c.IsRunning() {
				continue
			}

			c.Start()

			autoStartDelayInt, err := strconv.Atoi(autoStartDelay)
			if err == nil {
				time.Sleep(time.Duration(autoStartDelayInt) * time.Second)
			}
		}
	}

	_, err = dbExec(d.db, "DELETE FROM containers_config WHERE key='volatile.last_state.power'")
	if err != nil {
		return err
	}

	return nil
}

func containersShutdown(d *Daemon) error {
	results, err := dbContainersList(d.db, cTypeRegular)
	if err != nil {
		return err
	}

	var wg sync.WaitGroup

	for _, r := range results {
		c, err := containerLoadByName(d, r)
		if err != nil {
			return err
		}

		err = c.ConfigKeySet("volatile.last_state.power", c.State())

		if err != nil {
			return err
		}

		if c.IsRunning() {
			wg.Add(1)
			go func() {
				c.Shutdown(time.Second * 30)
				c.Stop()
				wg.Done()
			}()
		}
		wg.Wait()
	}

	return nil
}

func containerDeleteSnapshots(d *Daemon, cname string) error {
	shared.Log.Debug("containerDeleteSnapshots",
		log.Ctx{"container": cname})

	results, err := dbContainerGetSnapshots(d.db, cname)
	if err != nil {
		return err
	}

	for _, sname := range results {
		sc, err := containerLoadByName(d, sname)
		if err != nil {
			shared.Log.Error(
				"containerDeleteSnapshots: Failed to load the snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname})

			continue
		}

		if err := sc.Delete(); err != nil {
			shared.Log.Error(
				"containerDeleteSnapshots: Failed to delete a snapshotcontainer",
				log.Ctx{"container": cname, "snapshot": sname, "err": err})
		}
	}

	return nil
}

/*
 * This is called by lxd when called as "lxd forkstart <container>"
 * 'forkstart' is used instead of just 'start' in the hopes that people
 * do not accidentally type 'lxd start' instead of 'lxc start'
 *
 * We expect to read the lxcconfig over fd 3.
 */
func startContainer(args []string) error {
	if len(args) != 4 {
		return fmt.Errorf("Bad arguments: %q", args)
	}

	name := args[1]
	lxcpath := args[2]
	configPath := args[3]

	c, err := lxc.NewContainer(name, lxcpath)
	if err != nil {
		return fmt.Errorf("Error initializing container for start: %q", err)
	}

	err = c.LoadConfigFile(configPath)
	if err != nil {
		return fmt.Errorf("Error opening startup config file: %q", err)
	}

	/* due to https://github.com/golang/go/issues/13155 and the
	 * CollectOutput call we make for the forkstart process, we need to
	 * close our stdin/stdout/stderr here. Collecting some of the logs is
	 * better than collecting no logs, though.
	 */
	os.Stdin.Close()
	os.Stderr.Close()
	os.Stdout.Close()

	// Redirect stdout and stderr to a log file
	logPath := shared.LogPath(name, "forkstart.log")
	if shared.PathExists(logPath) {
		os.Remove(logPath)
	}

	logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_SYNC, 0644)
	if err == nil {
		syscall.Dup3(int(logFile.Fd()), 1, 0)
		syscall.Dup3(int(logFile.Fd()), 2, 0)
	}

	// Move the config so we can inspect it on failure
	shared.FileMove(configPath, shared.LogPath(name, "lxc.conf"))

	return c.Start()
}
<|endoftext|>


<commit_before>package parser

import (
	"errors"
	"fmt"
	//"go/ast"
	"log"
	"regexp"
	"strconv"
	"strings"
)

type Operation struct {
	HttpMethod       string            `json:"httpMethod"`
	Nickname         string            `json:"nickname"`
	Type             string            `json:"type"`
	Items            OperationItems    `json:"items,omitempty"`
	Summary          string            `json:"summary,omitempty"`
	Notes            string            `json:"notes,omitempty"`
	Parameters       []Parameter       `json:"parameters,omitempty"`
	ResponseMessages []ResponseMessage `json:"responseMessages,omitempty"`
	Consumes         []string          `json:"-"`
	Produces         []string          `json:"produces,omitempty"`
	Authorizations   []Authorization   `json:"authorizations,omitempty"`
	Protocols        []Protocol        `json:"protocols,omitempty"`
	Path             string            `json:"-"`
	ForceResource    string            `json:"-"`
	parser           *Parser
	Models           []*Model `json:"-"`
	packageName      string
}
type OperationItems struct {
	Ref  string `json:"$ref,omitempty"`
	Type string `json:"type,omitempty"`
}

func NewOperation(p *Parser, packageName string) *Operation {
	return &Operation{
		parser:      p,
		Models:      make([]*Model, 0),
		packageName: packageName,
	}
}

func (operation *Operation) SetItemsType(itemsType string) {
	operation.Items = OperationItems{}
	if IsBasicType(itemsType) {
		operation.Items.Type = itemsType
	} else {
		operation.Items.Ref = itemsType
	}
}

func (operation *Operation) ParseComment(comment string) error {
	commentLine := strings.TrimSpace(strings.TrimLeft(comment, "//"))
	attribute := strings.ToLower(strings.Fields(commentLine)[0])
	switch attribute {
	case "@router":
		if err := operation.ParseRouterComment(commentLine); err != nil {
			return err
		}
	case "@resource":
		resource := strings.TrimSpace(commentLine[len("@Resource"):])
		if resource[0:1] == "/" {
			resource = resource[1:]
		}
		operation.ForceResource = resource
	case "@title":
		operation.Nickname = strings.TrimSpace(commentLine[len("@Title"):])
	case "@description":
		operation.Summary = strings.TrimSpace(commentLine[len("@Description"):])
	case "@success":
		sourceString := strings.TrimSpace(commentLine[len("@Success"):])
		if err := operation.ParseResponseComment(sourceString); err != nil {
			return err
		}
	case "@param":
		if err := operation.ParseParamComment(commentLine); err != nil {
			return err
		}
	case "@failure":
		sourceString := strings.TrimSpace(commentLine[len("@Failure"):])
		if err := operation.ParseResponseComment(sourceString); err != nil {
			return err
		}
	case "@accept":
		if err := operation.ParseAcceptComment(commentLine); err != nil {
			return err
		}
	}

	operation.Models = operation.getUniqueModels()

	return nil
}

func (operation *Operation) getUniqueModels() []*Model {

	uniqueModels := make([]*Model, 0, len(operation.Models))
	modelIds := map[string]bool{}

	for _, model := range operation.Models {
		if _, exists := modelIds[model.Id]; exists {
			continue
		}
		uniqueModels = append(uniqueModels, model)
		modelIds[model.Id] = true
	}

	return uniqueModels
}

func (operation *Operation) registerType(typeName string) (string, error) {
	registerType := ""

	if translation, ok := typeDefTranslations[typeName]; ok {
		registerType = translation
	} else if IsBasicType(typeName) {
		registerType = typeName
	} else {
		model := NewModel(operation.parser)
		knownModelNames := map[string]bool{}

		err, innerModels := model.ParseModel(typeName, operation.parser.CurrentPackage, knownModelNames)
		if err != nil {
			return registerType, err
		}
		if translation, ok := typeDefTranslations[typeName]; ok {
			registerType = translation
		} else {
			registerType = model.Id

			operation.Models = append(operation.Models, model)
			operation.Models = append(operation.Models, innerModels...)
		}
	}

	return registerType, nil
}

// Parse params return []string of param properties
// @Param	queryText		form	      string	  true		        "The email for login"
// 			[param name]    [param type] [data type]  [is mandatory?]   [Comment]
func (operation *Operation) ParseParamComment(commentLine string) error {
	swaggerParameter := Parameter{}
	paramString := strings.TrimSpace(commentLine[len("@Param "):])

	re := regexp.MustCompile(`([\w]+)[\s]+([\w]+)[\s]+([\w.]+)[\s]+([\w]+)[\s]+"([^"]+)"`)

	if matches := re.FindStringSubmatch(paramString); len(matches) != 6 {
		return fmt.Errorf("Can not parse param comment \"%s\", skipped.", paramString)
	} else {
		typeName, err := operation.registerType(matches[3])
		if err != nil {
			return err
		}

		swaggerParameter.Name = matches[1]
		swaggerParameter.ParamType = matches[2]
		swaggerParameter.Type = typeName
		swaggerParameter.DataType = typeName
		swaggerParameter.Required = strings.ToLower(matches[4]) == "true"
		swaggerParameter.Description = matches[5]

		operation.Parameters = append(operation.Parameters, swaggerParameter)
	}

	return nil
}

// @Accept  json
func (operation *Operation) ParseAcceptComment(commentLine string) error {
	accepts := strings.Split(strings.TrimSpace(strings.TrimSpace(commentLine[len("@Accept"):])), ",")
	for _, a := range accepts {
		switch a {
		case "json", "application/json":
			operation.Consumes = append(operation.Consumes, ContentTypeJson)
			operation.Produces = append(operation.Produces, ContentTypeJson)
		case "xml", "text/xml":
			operation.Consumes = append(operation.Consumes, ContentTypeXml)
			operation.Produces = append(operation.Produces, ContentTypeXml)
		case "plain", "text/plain":
			operation.Consumes = append(operation.Consumes, ContentTypePlain)
			operation.Produces = append(operation.Produces, ContentTypePlain)
		case "html", "text/html":
			operation.Consumes = append(operation.Consumes, ContentTypeHtml)
			operation.Produces = append(operation.Produces, ContentTypeHtml)
		}
	}
	return nil
}

// @Router /customer/get-wishlist/{wishlist_id} [get]
func (operation *Operation) ParseRouterComment(commentLine string) error {
	sourceString := strings.TrimSpace(commentLine[len("@Router"):])

	re := regexp.MustCompile(`([\w\.\/\-{}]+)[^\[]+\[([^\]]+)`)
	var matches []string

	if matches = re.FindStringSubmatch(sourceString); len(matches) != 3 {
		return fmt.Errorf("Can not parse router comment \"%s\", skipped.", commentLine)
	}

	operation.Path = matches[1]
	operation.HttpMethod = strings.ToUpper(matches[2])
	return nil
}

// @Success 200 {object} model.OrderRow "Error message, if code != 200"
func (operation *Operation) ParseResponseComment(commentLine string) error {
	re := regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 5 {
		return fmt.Errorf("Can not parse response comment \"%s\", skipped.", commentLine)
	}

	response := ResponseMessage{}
	if code, err := strconv.Atoi(matches[1]); err != nil {
		return errors.New("Success http code must be int")
	} else {
		response.Code = code
	}
	response.Message = strings.Trim(matches[4], "\"")

	typeName, err := operation.registerType(matches[3])
	if err != nil {
		return err
	}

	response.ResponseModel = typeName
	if response.Code == 200 {
		if matches[2] == "{array}" {
			operation.SetItemsType(typeName)
			operation.Type = "array"
		} else {
			operation.Type = typeName
		}
	}

	operation.ResponseMessages = append(operation.ResponseMessages, response)
	return nil
}
<commit_msg>remove log from imports<commit_after>package parser

import (
	"errors"
	"fmt"
	//"go/ast"
	"regexp"
	"strconv"
	"strings"
)

type Operation struct {
	HttpMethod       string            `json:"httpMethod"`
	Nickname         string            `json:"nickname"`
	Type             string            `json:"type"`
	Items            OperationItems    `json:"items,omitempty"`
	Summary          string            `json:"summary,omitempty"`
	Notes            string            `json:"notes,omitempty"`
	Parameters       []Parameter       `json:"parameters,omitempty"`
	ResponseMessages []ResponseMessage `json:"responseMessages,omitempty"`
	Consumes         []string          `json:"-"`
	Produces         []string          `json:"produces,omitempty"`
	Authorizations   []Authorization   `json:"authorizations,omitempty"`
	Protocols        []Protocol        `json:"protocols,omitempty"`
	Path             string            `json:"-"`
	ForceResource    string            `json:"-"`
	parser           *Parser
	Models           []*Model `json:"-"`
	packageName      string
}
type OperationItems struct {
	Ref  string `json:"$ref,omitempty"`
	Type string `json:"type,omitempty"`
}

func NewOperation(p *Parser, packageName string) *Operation {
	return &Operation{
		parser:      p,
		Models:      make([]*Model, 0),
		packageName: packageName,
	}
}

func (operation *Operation) SetItemsType(itemsType string) {
	operation.Items = OperationItems{}
	if IsBasicType(itemsType) {
		operation.Items.Type = itemsType
	} else {
		operation.Items.Ref = itemsType
	}
}

func (operation *Operation) ParseComment(comment string) error {
	commentLine := strings.TrimSpace(strings.TrimLeft(comment, "//"))
	attribute := strings.ToLower(strings.Fields(commentLine)[0])
	switch attribute {
	case "@router":
		if err := operation.ParseRouterComment(commentLine); err != nil {
			return err
		}
	case "@resource":
		resource := strings.TrimSpace(commentLine[len("@Resource"):])
		if resource[0:1] == "/" {
			resource = resource[1:]
		}
		operation.ForceResource = resource
	case "@title":
		operation.Nickname = strings.TrimSpace(commentLine[len("@Title"):])
	case "@description":
		operation.Summary = strings.TrimSpace(commentLine[len("@Description"):])
	case "@success":
		sourceString := strings.TrimSpace(commentLine[len("@Success"):])
		if err := operation.ParseResponseComment(sourceString); err != nil {
			return err
		}
	case "@param":
		if err := operation.ParseParamComment(commentLine); err != nil {
			return err
		}
	case "@failure":
		sourceString := strings.TrimSpace(commentLine[len("@Failure"):])
		if err := operation.ParseResponseComment(sourceString); err != nil {
			return err
		}
	case "@accept":
		if err := operation.ParseAcceptComment(commentLine); err != nil {
			return err
		}
	}

	operation.Models = operation.getUniqueModels()

	return nil
}

func (operation *Operation) getUniqueModels() []*Model {

	uniqueModels := make([]*Model, 0, len(operation.Models))
	modelIds := map[string]bool{}

	for _, model := range operation.Models {
		if _, exists := modelIds[model.Id]; exists {
			continue
		}
		uniqueModels = append(uniqueModels, model)
		modelIds[model.Id] = true
	}

	return uniqueModels
}

func (operation *Operation) registerType(typeName string) (string, error) {
	registerType := ""

	if translation, ok := typeDefTranslations[typeName]; ok {
		registerType = translation
	} else if IsBasicType(typeName) {
		registerType = typeName
	} else {
		model := NewModel(operation.parser)
		knownModelNames := map[string]bool{}

		err, innerModels := model.ParseModel(typeName, operation.parser.CurrentPackage, knownModelNames)
		if err != nil {
			return registerType, err
		}
		if translation, ok := typeDefTranslations[typeName]; ok {
			registerType = translation
		} else {
			registerType = model.Id

			operation.Models = append(operation.Models, model)
			operation.Models = append(operation.Models, innerModels...)
		}
	}

	return registerType, nil
}

// Parse params return []string of param properties
// @Param	queryText		form	      string	  true		        "The email for login"
// 			[param name]    [param type] [data type]  [is mandatory?]   [Comment]
func (operation *Operation) ParseParamComment(commentLine string) error {
	swaggerParameter := Parameter{}
	paramString := strings.TrimSpace(commentLine[len("@Param "):])

	re := regexp.MustCompile(`([\w]+)[\s]+([\w]+)[\s]+([\w.]+)[\s]+([\w]+)[\s]+"([^"]+)"`)

	if matches := re.FindStringSubmatch(paramString); len(matches) != 6 {
		return fmt.Errorf("Can not parse param comment \"%s\", skipped.", paramString)
	} else {
		typeName, err := operation.registerType(matches[3])
		if err != nil {
			return err
		}

		swaggerParameter.Name = matches[1]
		swaggerParameter.ParamType = matches[2]
		swaggerParameter.Type = typeName
		swaggerParameter.DataType = typeName
		swaggerParameter.Required = strings.ToLower(matches[4]) == "true"
		swaggerParameter.Description = matches[5]

		operation.Parameters = append(operation.Parameters, swaggerParameter)
	}

	return nil
}

// @Accept  json
func (operation *Operation) ParseAcceptComment(commentLine string) error {
	accepts := strings.Split(strings.TrimSpace(strings.TrimSpace(commentLine[len("@Accept"):])), ",")
	for _, a := range accepts {
		switch a {
		case "json", "application/json":
			operation.Consumes = append(operation.Consumes, ContentTypeJson)
			operation.Produces = append(operation.Produces, ContentTypeJson)
		case "xml", "text/xml":
			operation.Consumes = append(operation.Consumes, ContentTypeXml)
			operation.Produces = append(operation.Produces, ContentTypeXml)
		case "plain", "text/plain":
			operation.Consumes = append(operation.Consumes, ContentTypePlain)
			operation.Produces = append(operation.Produces, ContentTypePlain)
		case "html", "text/html":
			operation.Consumes = append(operation.Consumes, ContentTypeHtml)
			operation.Produces = append(operation.Produces, ContentTypeHtml)
		}
	}
	return nil
}

// @Router /customer/get-wishlist/{wishlist_id} [get]
func (operation *Operation) ParseRouterComment(commentLine string) error {
	sourceString := strings.TrimSpace(commentLine[len("@Router"):])

	re := regexp.MustCompile(`([\w\.\/\-{}]+)[^\[]+\[([^\]]+)`)
	var matches []string

	if matches = re.FindStringSubmatch(sourceString); len(matches) != 3 {
		return fmt.Errorf("Can not parse router comment \"%s\", skipped.", commentLine)
	}

	operation.Path = matches[1]
	operation.HttpMethod = strings.ToUpper(matches[2])
	return nil
}

// @Success 200 {object} model.OrderRow "Error message, if code != 200"
func (operation *Operation) ParseResponseComment(commentLine string) error {
	re := regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/]+)[^"]*(.*)?`)
	var matches []string

	if matches = re.FindStringSubmatch(commentLine); len(matches) != 5 {
		return fmt.Errorf("Can not parse response comment \"%s\", skipped.", commentLine)
	}

	response := ResponseMessage{}
	if code, err := strconv.Atoi(matches[1]); err != nil {
		return errors.New("Success http code must be int")
	} else {
		response.Code = code
	}
	response.Message = strings.Trim(matches[4], "\"")

	typeName, err := operation.registerType(matches[3])
	if err != nil {
		return err
	}

	response.ResponseModel = typeName
	if response.Code == 200 {
		if matches[2] == "{array}" {
			operation.SetItemsType(typeName)
			operation.Type = "array"
		} else {
			operation.Type = typeName
		}
	}

	operation.ResponseMessages = append(operation.ResponseMessages, response)
	return nil
}
<|endoftext|>


<commit_before>//  This Source Code Form is subject to the terms of the Mozilla Public
//  License, v. 2.0. If a copy of the MPL was not distributed with this
//  file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"math"
)

// A three component cartesian vector
type Vector []float64

// Create new zero vector
func NewZeroVector() Vector {

	return Vector(make([]float64, 3))
}

// Create new vector
func NewVector(x, y, z float64) Vector {

	v := NewZeroVector()

	v[0], v[1], v[2] = x, y, z

	return v
}

// Add two vectors
func (a Vector) Plus(b Vector) (c Vector) {

	c = NewZeroVector()

	for i, _ := range a {

		c[i] = a[i] + b[i]
	}

	return c
}

// Invert a vector's direction
func (a Vector) Negate() (minusA Vector) {

	minusA = NewZeroVector()

	for i, aComponent := range a {

		minusA[i] = -aComponent
	}

	return minusA
}

// Subtract two vectors
func (a Vector) Minus(b Vector) Vector {

	return a.Plus(b.Negate())
}

// Take the dot product of two vectors
func (a Vector) Dot(b Vector) float64 {

	sum := 0.0

	for i, _ := range a {

		sum += a[i] * b[i]
	}

	return sum
}

// Calculate the norm of a vector
func (a Vector) Norm() float64 {

	return math.Sqrt(a.Dot(a))
}

// Scale a vector by s
func (a Vector) Scale(s float64) (b Vector) {

	b = a.Copy()

	for i, _ := range a {

		b[i] *= s
	}

	return b
}

// Produce the unit vector oriented the same as a
func (a Vector) Unit() Vector {

	return a.Scale(1 / a.Norm())
}

// Take the cross product of two vectors
func (a Vector) Cross(b Vector) (c Vector) {

	c = NewZeroVector()

	for i, _ := range a {

		c[i] += a[(i+1)%3] * b[(i+2)%3]

		c[i] -= a[(i+2)%3] * b[(i+1)%3]
	}

	return c
}
<commit_msg>Add missing dacart.Vector.Copy<commit_after>//  This Source Code Form is subject to the terms of the Mozilla Public
//  License, v. 2.0. If a copy of the MPL was not distributed with this
//  file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"math"
)

// A three component cartesian vector
type Vector []float64

// Create new zero vector
func NewZeroVector() Vector {

	return Vector(make([]float64, 3))
}

// Create new vector
func NewVector(x, y, z float64) Vector {

	v := NewZeroVector()

	v[0], v[1], v[2] = x, y, z

	return v
}

// Copy the vector
func (v Vector) Copy() (u Vector) {

	u = NewZeroVector()

	for i, vComp := range v {

		u[i] = vComp
	}

	return u
}

// Add two vectors
func (a Vector) Plus(b Vector) (c Vector) {

	c = NewZeroVector()

	for i, _ := range a {

		c[i] = a[i] + b[i]
	}

	return c
}

// Invert a vector's direction
func (a Vector) Negate() (minusA Vector) {

	minusA = NewZeroVector()

	for i, aComponent := range a {

		minusA[i] = -aComponent
	}

	return minusA
}

// Subtract two vectors
func (a Vector) Minus(b Vector) Vector {

	return a.Plus(b.Negate())
}

// Take the dot product of two vectors
func (a Vector) Dot(b Vector) float64 {

	sum := 0.0

	for i, _ := range a {

		sum += a[i] * b[i]
	}

	return sum
}

// Calculate the norm of a vector
func (a Vector) Norm() float64 {

	return math.Sqrt(a.Dot(a))
}

// Scale a vector by s
func (a Vector) Scale(s float64) (b Vector) {

	b = a.Copy()

	for i, _ := range a {

		b[i] *= s
	}

	return b
}

// Produce the unit vector oriented the same as a
func (a Vector) Unit() Vector {

	return a.Scale(1 / a.Norm())
}

// Take the cross product of two vectors
func (a Vector) Cross(b Vector) (c Vector) {

	c = NewZeroVector()

	for i, _ := range a {

		c[i] += a[(i+1)%3] * b[(i+2)%3]

		c[i] -= a[(i+2)%3] * b[(i+1)%3]
	}

	return c
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/MJKWoolnough/gopherjs/style"
	"github.com/MJKWoolnough/gopherjs/tabs"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket"

	"honnef.co/go/js/dom"
)

const css = `label {
	display : block;
	float : left;
	text-align : right;
	width : 200px;
}

label:after {
	content : ':';
}
`

func init() {
	style.Add(css)
}

func closeOnExit(conn *websocket.Conn) func(*js.Object) {
	return dom.GetWindow().AddEventListener("beforeunload", false, func(_ dom.Event) {
		switch conn.ReadyState {
		case websocket.Connecting, websocket.Open:
			conn.Close()
		}
	})
}

func removeCloser(l func(*js.Object)) {
	dom.GetWindow().RemoveEventListener("beforeunload", false, l)
}

func main() {
	dom.GetWindow().AddEventListener("load", false, func(_ dom.Event) {
		go func() {
			err := rpcInit()
			if err != nil {
				dom.GetWindow().Alert("Error connection to RPC server: " + err.Error())
				return
			}
			body := dom.GetWindow().Document().(dom.HTMLDocument).Body()
			xjs.RemoveChildren(body)
			title, err := ServerName()
			if err != nil {
				dom.GetWindow().Alert(err.Error())
				return
			}
			body.AppendChild(xjs.SetInnerText(xjs.CreateElement("h1"), title+" Server"))
			body.AppendChild(tabs.MakeTabs([]tabs.Tab{
				{"Servers", servers},
				{"Maps", maps},
				{"Add", add},
			}))
		}()
	})
}
<commit_msg>Set window title to server name<commit_after>package main

import (
	"github.com/MJKWoolnough/gopherjs/style"
	"github.com/MJKWoolnough/gopherjs/tabs"
	"github.com/MJKWoolnough/gopherjs/xjs"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/websocket"

	"honnef.co/go/js/dom"
)

const css = `label {
	display : block;
	float : left;
	text-align : right;
	width : 200px;
}

label:after {
	content : ':';
}
`

func init() {
	style.Add(css)
}

func closeOnExit(conn *websocket.Conn) func(*js.Object) {
	return dom.GetWindow().AddEventListener("beforeunload", false, func(_ dom.Event) {
		switch conn.ReadyState {
		case websocket.Connecting, websocket.Open:
			conn.Close()
		}
	})
}

func removeCloser(l func(*js.Object)) {
	dom.GetWindow().RemoveEventListener("beforeunload", false, l)
}

func main() {
	dom.GetWindow().AddEventListener("load", false, func(_ dom.Event) {
		go func() {
			err := rpcInit()
			if err != nil {
				dom.GetWindow().Alert("Error connection to RPC server: " + err.Error())
				return
			}
			body := dom.GetWindow().Document().(dom.HTMLDocument).Body()
			xjs.RemoveChildren(body)
			title, err := ServerName()
			if err != nil {
				dom.GetWindow().Alert(err.Error())
				return
			}
			body.AppendChild(xjs.SetInnerText(xjs.CreateElement("h1"), title+" Server"))
			tDoc, ok := dom.GetWindow().Document().(dom.HTMLDocument)
			if ok {
				tDoc.SetTitle(title + " Server")
			}
			body.AppendChild(tabs.MakeTabs([]tabs.Tab{
				{"Servers", servers},
				{"Maps", maps},
				{"Add", add},
			}))
		}()
	})
}
<|endoftext|>