<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed under the MIT license that can be found in the LICENSE file.

package logger

import (
	"bytes"
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"
)

func TestFileEventWriter(t *testing.T) {
	file := strconv.FormatInt(time.Now().UnixNano(), 10)
	path := filepath.Join(os.TempDir(), "logger_"+file+".log")

	ew, err := NewFileEventWriter(path, InfoEvent)
	if err != nil {
		t.Fatal("Unexpected error creating new file event writer: " + err.Error())
	}
	defer os.Remove(path)

	event := Event{
		Type:      InfoEvent,
		Timestamp: now(),
		Tags:      Tags{"TestFileEventWriter"},
		Message:   "Log message",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to FileEventWriter: " + err.Error())
	}

	event = Event{
		Type:      DebugEvent,
		Timestamp: now(),
		Tags:      Tags{"TestFileEventWriter"},
		Message:   "Never shows up",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to FileEventWriter: " + err.Error())
	}

	ew.HandleError(errors.New("writing error"))

	if err := ew.Close(); err != nil {
		t.Fatal("Unexpected error closing: " + err.Error())
	}

	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		t.Fatal("Unexpected error reading file: " + err.Error())
	}

	expected := "2015-09-01 14:22:36 [Info] TestFileEventWriter: Log message\n" +
		"2015-09-01 14:22:36 [Error] FileEventWriter: Error writing to file: writing error\n"

	if got := string(bytes); got != expected {
		t.Fatalf("Expected file to contain:\n%s\nBut got:\n%s", expected, got)
	}
}

func TestConsoleEventWriter(t *testing.T) {
	var buf bytes.Buffer
	var errBuf bytes.Buffer
	ew := NewConsoleEventWriter(InfoEvent)

	cew := ew.(*consoleEventWriter)
	cew.w = &buf
	cew.errW = &errBuf

	event := Event{
		Type:      InfoEvent,
		Timestamp: now(),
		Tags:      Tags{"TestConsoleEventWriter"},
		Message:   "Log message",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to ConsoleEventWriter: " + err.Error())
	}

	event = Event{
		Type:      DebugEvent,
		Timestamp: now(),
		Tags:      Tags{"TestConsoleEventWriter"},
		Message:   "Never gets written",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to ConsoleEventWriter: " + err.Error())
	}

	ew.HandleError(errors.New("writing error"))

	if err := ew.Close(); err != nil {
		t.Fatal("Unexpected error closing: " + err.Error())
	}

	bytes, err := ioutil.ReadAll(&buf)
	if err != nil {
		t.Fatal("Unexpected error reading output buffer: " + err.Error())
	}

	expected := "2015-09-01 14:22:36 [Info] TestConsoleEventWriter: Log message\n"

	if got := string(bytes); got != expected {
		t.Fatalf("Expected buffer to contain:\n%s\nBut got:\n%s", expected, got)
	}

	errBytes, err := ioutil.ReadAll(&errBuf)
	if err != nil {
		t.Fatal("Unexpected error reading error buffer: " + err.Error())
	}

	expectedErr := "2015-09-01 14:22:36 [Error] ConsoleEventWriter: Error writing to console: writing error\n"

	if got := string(errBytes); got != expectedErr {
		t.Fatalf("Expected buffer to contain:\n%s\nBut got:\n%s", expectedErr, got)
	}
}

func TestJSONEventWriter(t *testing.T) {
	var buf bytes.Buffer
	var errBuf bytes.Buffer
	errorHandler := func(err error) {
		errBuf.WriteString(err.Error())
	}
	ew := NewJSONEventWriter(&buf, errorHandler, InfoEvent)

	event := Event{
		Type:      InfoEvent,
		Timestamp: now(),
		Tags:      Tags{"TestJSONEventWriter"},
		Message:   "Log message",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to JSONEventWriter: " + err.Error())
	}

	event = Event{
		Type:      DebugEvent,
		Timestamp: now(),
		Tags:      Tags{"TestJSONEventWriter"},
		Message:   "Never gets logged",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to JSONEventWriter: " + err.Error())
	}

	ew.HandleError(errors.New("some error"))

	if err := ew.Close(); err != nil {
		t.Fatal("Unexpected error closing: " + err.Error())
	}

	bytes, err := ioutil.ReadAll(&buf)
	if err != nil {
		t.Fatal("Unexpected error reading output buffer: " + err.Error())
	}

	expected := `{"type":"Info","timestamp":"2015-09-01T14:22:36Z","tags":` +
		`["TestJSONEventWriter"],"message":"Log message"}` + "\n"

	if got := string(bytes); got != expected {
		t.Fatalf("Expected buffer to contain:\n%s\nBut got:\n%s", expected, got)
	}
}
<commit_msg>Add test for not existing directory<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed under the MIT license that can be found in the LICENSE file.

package logger

import (
	"bytes"
	"errors"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"testing"
	"time"
)

func TestFileEventWriter(t *testing.T) {
	file := strconv.FormatInt(time.Now().UnixNano(), 10)
	path := filepath.Join(os.TempDir(), "logger_"+file+".log")

	ew, err := NewFileEventWriter(path, InfoEvent)
	if err != nil {
		t.Fatal("Unexpected error creating new file event writer: " + err.Error())
	}
	defer os.Remove(path)

	event := Event{
		Type:      InfoEvent,
		Timestamp: now(),
		Tags:      Tags{"TestFileEventWriter"},
		Message:   "Log message",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to FileEventWriter: " + err.Error())
	}

	event = Event{
		Type:      DebugEvent,
		Timestamp: now(),
		Tags:      Tags{"TestFileEventWriter"},
		Message:   "Never shows up",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to FileEventWriter: " + err.Error())
	}

	ew.HandleError(errors.New("writing error"))

	if err := ew.Close(); err != nil {
		t.Fatal("Unexpected error closing: " + err.Error())
	}

	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		t.Fatal("Unexpected error reading file: " + err.Error())
	}

	expected := "2015-09-01 14:22:36 [Info] TestFileEventWriter: Log message\n" +
		"2015-09-01 14:22:36 [Error] FileEventWriter: Error writing to file: writing error\n"

	if got := string(bytes); got != expected {
		t.Fatalf("Expected file to contain:\n%s\nBut got:\n%s", expected, got)
	}
}

func TestNewFileEventWriter(t *testing.T) {
	path := filepath.Clean("/a/path/to/a/file/that/should/not/be/here")
	_, err := NewFileEventWriter(path, InfoEvent)
	if err == nil {
		os.Remove(path)
		t.Fatal("Expected an error when creating a file", err.Error())
	}

	if !os.IsNotExist(err) {
		t.Fatal("Expected an file doesn't exist error, but got", err.Error())
	}
}

func TestConsoleEventWriter(t *testing.T) {
	var buf bytes.Buffer
	var errBuf bytes.Buffer
	ew := NewConsoleEventWriter(InfoEvent)

	cew := ew.(*consoleEventWriter)
	cew.w = &buf
	cew.errW = &errBuf

	event := Event{
		Type:      InfoEvent,
		Timestamp: now(),
		Tags:      Tags{"TestConsoleEventWriter"},
		Message:   "Log message",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to ConsoleEventWriter: " + err.Error())
	}

	event = Event{
		Type:      DebugEvent,
		Timestamp: now(),
		Tags:      Tags{"TestConsoleEventWriter"},
		Message:   "Never gets written",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to ConsoleEventWriter: " + err.Error())
	}

	ew.HandleError(errors.New("writing error"))

	if err := ew.Close(); err != nil {
		t.Fatal("Unexpected error closing: " + err.Error())
	}

	bytes, err := ioutil.ReadAll(&buf)
	if err != nil {
		t.Fatal("Unexpected error reading output buffer: " + err.Error())
	}

	expected := "2015-09-01 14:22:36 [Info] TestConsoleEventWriter: Log message\n"

	if got := string(bytes); got != expected {
		t.Fatalf("Expected buffer to contain:\n%s\nBut got:\n%s", expected, got)
	}

	errBytes, err := ioutil.ReadAll(&errBuf)
	if err != nil {
		t.Fatal("Unexpected error reading error buffer: " + err.Error())
	}

	expectedErr := "2015-09-01 14:22:36 [Error] ConsoleEventWriter: Error writing to console: writing error\n"

	if got := string(errBytes); got != expectedErr {
		t.Fatalf("Expected buffer to contain:\n%s\nBut got:\n%s", expectedErr, got)
	}
}

func TestJSONEventWriter(t *testing.T) {
	var buf bytes.Buffer
	var errBuf bytes.Buffer
	errorHandler := func(err error) {
		errBuf.WriteString(err.Error())
	}
	ew := NewJSONEventWriter(&buf, errorHandler, InfoEvent)

	event := Event{
		Type:      InfoEvent,
		Timestamp: now(),
		Tags:      Tags{"TestJSONEventWriter"},
		Message:   "Log message",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to JSONEventWriter: " + err.Error())
	}

	event = Event{
		Type:      DebugEvent,
		Timestamp: now(),
		Tags:      Tags{"TestJSONEventWriter"},
		Message:   "Never gets logged",
	}

	if err := ew.Write(event); err != nil {
		t.Fatal("Unexpected error writing to JSONEventWriter: " + err.Error())
	}

	ew.HandleError(errors.New("some error"))

	if err := ew.Close(); err != nil {
		t.Fatal("Unexpected error closing: " + err.Error())
	}

	bytes, err := ioutil.ReadAll(&buf)
	if err != nil {
		t.Fatal("Unexpected error reading output buffer: " + err.Error())
	}

	expected := `{"type":"Info","timestamp":"2015-09-01T14:22:36Z","tags":` +
		`["TestJSONEventWriter"],"message":"Log message"}` + "\n"

	if got := string(bytes); got != expected {
		t.Fatalf("Expected buffer to contain:\n%s\nBut got:\n%s", expected, got)
	}
}
<|endoftext|>


<commit_before>package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
)

type Server struct {
	withId
	withName
	withDescription
	Password string        `json:"first_password"`
	Status   Status        `json:"status"`
	Hardware Hardware      `json:"hardware"`
	Image    ImageInServer `json:"image"`
	withApi
}

type Hardware struct {
	Vcores            int   `json:"vcore"`
	CoresPerProcessor int   `json:"cores_per_processor"`
	Ram               int   `json:"ram"`
	Hdds              []Hdd `json:"hdds"`
}

type Hdd struct {
	withId
	Size   int  `json:"size"`
	IsMain bool `json:"is_main"`
}

type ImageInServer struct {
	withId
	withName
}

type IpInServer struct {
	withId
	withType
	Ip         string `json:"ip"`
	ReverseDns string `json:"reverse_dns"`
	FirewallId string `json:"firewall"`
}

type ServerCreateData struct {
	Name               string   `json:"name"`
	Description        string   `json:"description"`
	Hardware           Hardware `json:"hardware"`
	ApplianceId        string   `json:"appliance_id"`
	Password           string   `json:"password"`
	PowerOn            bool     `json:"power_on"`
	FirewallPolicyId   string   `json:"firewall_policy_id"`
	IpId               string   `json:"ip_id"`
	LoadBalancerId     string   `json:"load_balancer_id"`
	MonitoringPolicyId string   `json:"monitoring_policy_id"`
	PrivateNetworkId   string   `json:"private_network_id"`
}

// GET /servers
func (api *API) GetServers() ([]Server, error) {
	log.Debug("requesting information about servers")
	result := []Server{}
	err := api.Client.Get(createUrl(api, "servers"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].api = api
	}
	return result, nil
}

// POST /servers
func (api *API) CreateServer(configuration ServerCreateData) (*Server, error) {
	log.Debug("requesting to create a new server")
	result := new(Server)
	err := api.Client.Post(createUrl(api, "servers"), configuration, result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// GET /servers/{id}
func (api *API) GetServer(Id string) (*Server, error) {
	log.Debug("requesting to about server ", Id)
	result := new(Server)
	err := api.Client.Get(createUrl(api, "servers", Id), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// DELETE /servers/{id}
func (s *Server) Delete() (*Server, error) {
	log.Debug("Requested to delete VM ", s.Id)
	result := new(Server)
	err := s.api.Client.Delete(createUrl(s.api, "servers", s.Id), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = s.api
	return result, nil
}

// PUT /servers/{id}

// GET /servers/{id}/size

// PUT /servers/{id}/size

// GET /servers/{id}/size/hdds

// POST /servers/{id}/size/hdds

// GET /servers/{id}/size/hdds/{id}

// DELETE /servers/{id}/size/hdds/{id}

// PUT /servers/{id}/size/hdds/{id}

// GET /servers/{id}/image

// PUT /servers/{id}/image

// GET /servers/{id}/ips

// POST /servers/{id}/ips

// GET /servers/{id}/ips/{id}

// DELETE /servers/{id}/ips/{id}

// PUT /servers/{id}/ips/{id}

// GET /servers/{id}/status

// PUT /servers/{id}/status

// GET /servers/{id}/dvd

// DELETE /servers/{id}/dvd

// PUT /servers/{id}/dvd

// GET /servers/{id}/private_networks

// PUT /servers/{id}/private_networks

// GET /servers/{id}/private_networks/{id}

// DELETE /servers/{id}/private_networks/{id}

// GET /servers/{id}/snapshots

// POST /servers/{id}/snapshots

// GET /servers/{id}/snapshots/{id}

// DELETE /servers/{id}/snapshots/{id}

// PUT /servers/{id}/snapshots/{id}

// POST /servers/{server_id}/clone
func (server *Server) Clone(NewName string) Server {
	return Server{}
}
<commit_msg>Add IPs the properties of a server.<commit_after>package oneandone_cloudserver_api

import (
	"github.com/docker/machine/log"
	"net/http"
)

type Server struct {
	withId
	withName
	withDescription
	Password string        `json:"first_password"`
	Status   Status        `json:"status"`
	Hardware Hardware      `json:"hardware"`
	Image    ImageInServer `json:"image"`
	Ips      []IpInServer  `json:"ips"`
	withApi
}

type Hardware struct {
	Vcores            int   `json:"vcore"`
	CoresPerProcessor int   `json:"cores_per_processor"`
	Ram               int   `json:"ram"`
	Hdds              []Hdd `json:"hdds"`
}

type Hdd struct {
	withId
	Size   int  `json:"size"`
	IsMain bool `json:"is_main"`
}

type ImageInServer struct {
	withId
	withName
}

type IpInServer struct {
	withId
	withType
	Ip         string `json:"ip"`
	ReverseDns string `json:"reverse_dns"`
	FirewallId string `json:"firewall"`
}

type ServerCreateData struct {
	Name               string   `json:"name"`
	Description        string   `json:"description"`
	Hardware           Hardware `json:"hardware"`
	ApplianceId        string   `json:"appliance_id"`
	Password           string   `json:"password"`
	PowerOn            bool     `json:"power_on"`
	FirewallPolicyId   string   `json:"firewall_policy_id"`
	IpId               string   `json:"ip_id"`
	LoadBalancerId     string   `json:"load_balancer_id"`
	MonitoringPolicyId string   `json:"monitoring_policy_id"`
	PrivateNetworkId   string   `json:"private_network_id"`
}

// GET /servers
func (api *API) GetServers() ([]Server, error) {
	log.Debug("requesting information about servers")
	result := []Server{}
	err := api.Client.Get(createUrl(api, "servers"), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	for index, _ := range result {
		result[index].api = api
	}
	return result, nil
}

// POST /servers
func (api *API) CreateServer(configuration ServerCreateData) (*Server, error) {
	log.Debug("requesting to create a new server")
	result := new(Server)
	err := api.Client.Post(createUrl(api, "servers"), configuration, result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// GET /servers/{id}
func (api *API) GetServer(Id string) (*Server, error) {
	log.Debug("requesting to about server ", Id)
	result := new(Server)
	err := api.Client.Get(createUrl(api, "servers", Id), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = api
	return result, nil
}

// DELETE /servers/{id}
func (s *Server) Delete() (*Server, error) {
	log.Debug("Requested to delete VM ", s.Id)
	result := new(Server)
	err := s.api.Client.Delete(createUrl(s.api, "servers", s.Id), &result, http.StatusOK)
	if err != nil {
		return nil, err
	}
	result.api = s.api
	return result, nil
}

// PUT /servers/{id}

// GET /servers/{id}/size

// PUT /servers/{id}/size

// GET /servers/{id}/size/hdds

// POST /servers/{id}/size/hdds

// GET /servers/{id}/size/hdds/{id}

// DELETE /servers/{id}/size/hdds/{id}

// PUT /servers/{id}/size/hdds/{id}

// GET /servers/{id}/image

// PUT /servers/{id}/image

// GET /servers/{id}/ips

// POST /servers/{id}/ips

// GET /servers/{id}/ips/{id}

// DELETE /servers/{id}/ips/{id}

// PUT /servers/{id}/ips/{id}

// GET /servers/{id}/status

// PUT /servers/{id}/status

// GET /servers/{id}/dvd

// DELETE /servers/{id}/dvd

// PUT /servers/{id}/dvd

// GET /servers/{id}/private_networks

// PUT /servers/{id}/private_networks

// GET /servers/{id}/private_networks/{id}

// DELETE /servers/{id}/private_networks/{id}

// GET /servers/{id}/snapshots

// POST /servers/{id}/snapshots

// GET /servers/{id}/snapshots/{id}

// DELETE /servers/{id}/snapshots/{id}

// PUT /servers/{id}/snapshots/{id}

// POST /servers/{server_id}/clone
func (server *Server) Clone(NewName string) Server {
	return Server{}
}
<|endoftext|>


<commit_before>package goa

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"

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

const (
	// ErrorMediaIdentifier is the media type identifier used for error responses.
	ErrorMediaIdentifier = "application/vnd.api.error+json"
)

var (
	// MaxRequestBodyLength is the maximum length read from request bodies.
	// Set to 0 to remove the limit altogether.
	MaxRequestBodyLength int64 = 1073741824 // 1 GB
)

type (
	// Service is the data structure supporting goa services.
	// It provides methods for configuring a service and running it.
	// At the basic level a service consists of a set of controllers, each implementing a given
	// resource actions. goagen generates global functions - one per resource - that make it
	// possible to mount the corresponding controller onto a service. A service contains the
	// middleware, not found handler, encoders and muxes shared by all its controllers.
	Service struct {
		// Name of service used for logging, tracing etc.
		Name string
		// Mux is the service request mux
		Mux ServeMux
		// Context is the root context from which all request contexts are derived.
		// Set values in the root context prior to starting the server to make these values
		// available to all request handlers.
		Context context.Context

		finalized             bool                    // Whether controllers have been mounted
		middleware            []Middleware            // Middleware chain
		notFound              Handler                 // Handler of requests that don't match registered mux handlers
		cancel                context.CancelFunc      // Service context cancel signal trigger
		decoderPools          map[string]*decoderPool // Registered decoders for the service
		encoderPools          map[string]*encoderPool // Registered encoders for the service
		encodableContentTypes []string                // List of contentTypes for response negotiation
	}

	// Controller defines the common fields and behavior of generated controllers.
	Controller struct {
		Name    string          // Controller resource name
		Service *Service        // Service that exposes the controller
		Context context.Context // Controller root context

		middleware []Middleware // Controller specific middleware if any
	}

	// FileServer is the interface implemented by controllers that can serve static files.
	FileServer interface {
		// FileHandler returns a handler that serves files under the given request path.
		FileHandler(path, filename string) Handler
	}

	// Handler defines the request handler signatures.
	Handler func(context.Context, http.ResponseWriter, *http.Request) error

	// Unmarshaler defines the request payload unmarshaler signatures.
	Unmarshaler func(context.Context, *Service, *http.Request) error

	// DecodeFunc is the function that initialize the unmarshaled payload from the request body.
	DecodeFunc func(context.Context, io.ReadCloser, interface{}) error
)

// New instantiates a service with the given name.
func New(name string) *Service {
	var (
		stdlog       = log.New(os.Stderr, "", log.LstdFlags)
		ctx          = WithLogger(context.Background(), NewLogger(stdlog))
		cctx, cancel = context.WithCancel(ctx)
		mux          = NewMux()
		service      = &Service{
			Name:    name,
			Context: cctx,
			Mux:     mux,

			cancel:                cancel,
			decoderPools:          map[string]*decoderPool{},
			encoderPools:          map[string]*encoderPool{},
			encodableContentTypes: []string{},
			notFound: func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
				return ErrNotFound(req.URL.Path)
			},
		}
	)

	mux.HandleNotFound(func(rw http.ResponseWriter, req *http.Request, params url.Values) {
		ctx := NewContext(service.Context, rw, req, params)
		err := service.notFound(ctx, rw, req)
		if !ContextResponse(ctx).Written() {
			service.Send(ctx, 404, err)
		}
	})

	return service
}

// CancelAll sends a cancel signals to all request handlers via the context.
// See https://godoc.org/golang.org/x/net/context for details on how to handle the signal.
func (service *Service) CancelAll() {
	service.cancel()
}

// Use adds a middleware to the service wide middleware chain.
// goa comes with a set of commonly used middleware, see the middleware package.
// Controller specific middleware should be mounted using the Controller struct Use method instead.
func (service *Service) Use(m Middleware) {
	if service.finalized {
		panic("goa: cannot mount middleware after controller")
	}
	service.middleware = append(service.middleware, m)
}

// WithLogger sets the logger used internally by the service and by Log.
func (service *Service) WithLogger(logger LogAdapter) {
	service.Context = WithLogger(service.Context, logger)
}

// LogInfo logs the message and values at odd indeces using the keys at even indeces of the keyvals slice.
func (service *Service) LogInfo(msg string, keyvals ...interface{}) {
	LogInfo(service.Context, msg, keyvals...)
}

// LogError logs the error and values at odd indeces using the keys at even indeces of the keyvals slice.
func (service *Service) LogError(msg string, keyvals ...interface{}) {
	LogError(service.Context, msg, keyvals...)
}

// ListenAndServe starts a HTTP server and sets up a listener on the given host/port.
func (service *Service) ListenAndServe(addr string) error {
	service.LogInfo("listen", "transport", "http", "addr", addr)
	return http.ListenAndServe(addr, service.Mux)
}

// ListenAndServeTLS starts a HTTPS server and sets up a listener on the given host/port.
func (service *Service) ListenAndServeTLS(addr, certFile, keyFile string) error {
	service.LogInfo("listen", "transport", "https", "addr", addr)
	return http.ListenAndServeTLS(addr, certFile, keyFile, service.Mux)
}

// NewController returns a controller for the given resource. This method is mainly intended for
// use by the generated code. User code shouldn't have to call it directly.
func (service *Service) NewController(name string) *Controller {
	return &Controller{
		Name:    name,
		Service: service,
		Context: context.WithValue(service.Context, ctrlKey, name),
	}
}

// Send serializes the given body matching the request Accept header against the service
// encoders. It uses the default service encoder if no match is found.
func (service *Service) Send(ctx context.Context, code int, body interface{}) error {
	r := ContextResponse(ctx)
	if r == nil {
		return fmt.Errorf("no response data in context")
	}
	r.WriteHeader(code)
	return service.EncodeResponse(ctx, body)
}

// ServeFiles create a "FileServer" controller and calls ServerFiles on it.
func (service *Service) ServeFiles(path, filename string) error {
	ctrl := service.NewController("FileServer")
	return ctrl.ServeFiles(path, filename)
}

// finalize wraps the NotFound handler with the final middleware chain.
// Use cannot be called after finalize has.
func (service *Service) finalize() {
	if service.finalized {
		return
	}
	notFound := service.notFound
	handler := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		if !ContextResponse(ctx).Written() {
			return notFound(ctx, rw, req)
		}
		return nil
	}
	ml := len(service.middleware)
	for i := range service.middleware {
		handler = service.middleware[ml-i-1](handler)
	}
	service.notFound = handler
	service.finalized = true
}

// ServeFiles replies to the request with the contents of the named file or directory. See
// FileHandler for details.
func (ctrl *Controller) ServeFiles(path, filename string) error {
	if strings.Contains(path, ":") {
		return fmt.Errorf("path may only include wildcards that match the entire end of the URL (e.g. *filepath)")
	}
	LogInfo(ctrl.Context, "mount file", "name", filename, "route", fmt.Sprintf("GET %s", path))
	handler := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		if !ContextResponse(ctx).Written() {
			return ctrl.FileHandler(filename, path)(ctx, rw, req)
		}
		return nil
	}
	ctrl.Service.Mux.Handle("GET", path, ctrl.MuxHandler("serve", handler, nil))
	return nil
}

// Use adds a middleware to the controller.
// Service-wide middleware should be added via the Service Use method instead.
func (ctrl *Controller) Use(m Middleware) {
	if ctrl.Service.finalized {
		panic("goa: cannot mount middleware after controller")
	}
	ctrl.middleware = append(ctrl.middleware, m)
}

// MuxHandler wraps a request handler into a MuxHandler. The MuxHandler initializes the request
// context by loading the request state, invokes the handler and in case of error invokes the
// controller (if there is one) or Service error handler.
// This function is intended for the controller generated code. User code should not need to call
// it directly.
func (ctrl *Controller) MuxHandler(name string, hdlr Handler, unm Unmarshaler) MuxHandler {
	// Make sure middleware doesn't get mounted later
	ctrl.Service.finalize()

	// Setup middleware outside of closure
	middleware := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		if !ContextResponse(ctx).Written() {
			return hdlr(ctx, rw, req)
		}
		return nil
	}
	chain := append(ctrl.Service.middleware, ctrl.middleware...)
	ml := len(chain)
	for i := range chain {
		middleware = chain[ml-i-1](middleware)
	}
	return func(rw http.ResponseWriter, req *http.Request, params url.Values) {
		// Build context
		ctx := NewContext(WithAction(ctrl.Context, name), rw, req, params)

		// Protect against request bodies with unreasonable length
		if MaxRequestBodyLength > 0 {
			req.Body = http.MaxBytesReader(rw, req.Body, MaxRequestBodyLength)
		}

		// Load body if any
		var err error
		if req.ContentLength > 0 && unm != nil {
			err = unm(ctx, ctrl.Service, req)
		}

		// Handle invalid payload
		handler := middleware
		if err != nil {
			handler = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
				rw.Header().Set("Content-Type", ErrorMediaIdentifier)
				status := 400
				body := ErrInvalidEncoding(err)
				if err.Error() == "http: request body too large" {
					status = 413
					body = ErrRequestBodyTooLarge("body length exceeds %d bytes", MaxRequestBodyLength)
				}
				return ctrl.Service.Send(ctx, status, body)
			}
			for i := range chain {
				handler = chain[ml-i-1](handler)
			}
		}

		// Invoke middleware chain, errors should be caught earlier, e.g. by ErrorHandler middleware
		if err := handler(ctx, ContextResponse(ctx), req); err != nil {
			LogError(ctx, "uncaught error", "err", err)
			respBody := fmt.Sprintf("Internal error: %s", err) // Sprintf catches panics
			ctrl.Service.Send(ctx, 500, respBody)
		}
	}
}

// FileHandler returns a handler that serves files under the given filename for the given route path.
// The logic for what to do when the filename points to a file vs. a directory is the same as the
// standard http package ServeFile function. The path may end with a wildcard that matches the rest
// of the URL (e.g. *filepath). If it does the matching path is appended to filename to form the
// full file path, so:
//
// 	c.FileHandler("/index.html", "/www/data/index.html")
//
// Returns the content of the file "/www/data/index.html" when requests are sent to "/index.html"
// and:
//
//	c.FileHandler("/assets/*filepath", "/www/data/assets")
//
// returns the content of the file "/www/data/assets/x/y/z" when requests are sent to
// "/assets/x/y/z".
func (ctrl *Controller) FileHandler(path, filename string) Handler {
	var wc string
	if idx := strings.Index(path, "*"); idx > -1 && idx < len(path)-1 {
		wc = path[idx+1:]
	}
	return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		fname := filename
		if len(wc) > 0 {
			if m, ok := ContextRequest(ctx).Params[wc]; ok {
				fname = filepath.Join(filename, m[0])
			}
		}
		LogInfo(ctrl.Context, "serve file", "name", fname, "route", req.URL.Path)
		dir, name := filepath.Split(fname)
		fs := http.Dir(dir)
		f, err := fs.Open(name)
		if err != nil {
			return ErrInvalidFile(err)
		}
		defer f.Close()
		d, err := f.Stat()
		if err != nil {
			return ErrInvalidFile(err)
		}
		// use contents of index.html for directory, if present
		if d.IsDir() {
			index := strings.TrimSuffix(name, "/") + "/index.html"
			ff, err := fs.Open(index)
			if err == nil {
				defer ff.Close()
				dd, err := ff.Stat()
				if err == nil {
					name = index
					d = dd
					f = ff
				}
			}
		}

		// serveContent will check modification time
		// Still a directory? (we didn't find an index.html file)
		if d.IsDir() {
			return dirList(rw, f)
		}
		http.ServeContent(rw, req, d.Name(), d.ModTime(), f)
		return nil
	}
}

var replacer = strings.NewReplacer(
	"&", "&",
	"<", "<",
	">", ">",
	// """ is shorter than """.
	`"`, """,
	// "'" is shorter than "'" and apos was not in HTML until HTML5.
	"'", "'",
)

func dirList(w http.ResponseWriter, f http.File) error {
	dirs, err := f.Readdir(-1)
	if err != nil {
		return err
	}
	sort.Sort(byName(dirs))

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, "
\n")
	for _, d := range dirs {
		name := d.Name()
		if d.IsDir() {
			name += "/"
		}
		// name may contain '?' or '#', which must be escaped to remain
		// part of the URL path, and not indicate the start of a query
		// string or fragment.
		url := url.URL{Path: name}
		fmt.Fprintf(w, "%s\n", url.String(), replacer.Replace(name))
	}
	fmt.Fprintf(w, "
\n")
	return nil
}

type byName []os.FileInfo

func (s byName) Len() int           { return len(s) }
func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
func (s byName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
<commit_msg>fix serve file (#492)<commit_after>package goa

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"

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

const (
	// ErrorMediaIdentifier is the media type identifier used for error responses.
	ErrorMediaIdentifier = "application/vnd.api.error+json"
)

var (
	// MaxRequestBodyLength is the maximum length read from request bodies.
	// Set to 0 to remove the limit altogether.
	MaxRequestBodyLength int64 = 1073741824 // 1 GB
)

type (
	// Service is the data structure supporting goa services.
	// It provides methods for configuring a service and running it.
	// At the basic level a service consists of a set of controllers, each implementing a given
	// resource actions. goagen generates global functions - one per resource - that make it
	// possible to mount the corresponding controller onto a service. A service contains the
	// middleware, not found handler, encoders and muxes shared by all its controllers.
	Service struct {
		// Name of service used for logging, tracing etc.
		Name string
		// Mux is the service request mux
		Mux ServeMux
		// Context is the root context from which all request contexts are derived.
		// Set values in the root context prior to starting the server to make these values
		// available to all request handlers.
		Context context.Context

		finalized             bool                    // Whether controllers have been mounted
		middleware            []Middleware            // Middleware chain
		notFound              Handler                 // Handler of requests that don't match registered mux handlers
		cancel                context.CancelFunc      // Service context cancel signal trigger
		decoderPools          map[string]*decoderPool // Registered decoders for the service
		encoderPools          map[string]*encoderPool // Registered encoders for the service
		encodableContentTypes []string                // List of contentTypes for response negotiation
	}

	// Controller defines the common fields and behavior of generated controllers.
	Controller struct {
		Name    string          // Controller resource name
		Service *Service        // Service that exposes the controller
		Context context.Context // Controller root context

		middleware []Middleware // Controller specific middleware if any
	}

	// FileServer is the interface implemented by controllers that can serve static files.
	FileServer interface {
		// FileHandler returns a handler that serves files under the given request path.
		FileHandler(path, filename string) Handler
	}

	// Handler defines the request handler signatures.
	Handler func(context.Context, http.ResponseWriter, *http.Request) error

	// Unmarshaler defines the request payload unmarshaler signatures.
	Unmarshaler func(context.Context, *Service, *http.Request) error

	// DecodeFunc is the function that initialize the unmarshaled payload from the request body.
	DecodeFunc func(context.Context, io.ReadCloser, interface{}) error
)

// New instantiates a service with the given name.
func New(name string) *Service {
	var (
		stdlog       = log.New(os.Stderr, "", log.LstdFlags)
		ctx          = WithLogger(context.Background(), NewLogger(stdlog))
		cctx, cancel = context.WithCancel(ctx)
		mux          = NewMux()
		service      = &Service{
			Name:    name,
			Context: cctx,
			Mux:     mux,

			cancel:                cancel,
			decoderPools:          map[string]*decoderPool{},
			encoderPools:          map[string]*encoderPool{},
			encodableContentTypes: []string{},
			notFound: func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
				return ErrNotFound(req.URL.Path)
			},
		}
	)

	mux.HandleNotFound(func(rw http.ResponseWriter, req *http.Request, params url.Values) {
		ctx := NewContext(service.Context, rw, req, params)
		err := service.notFound(ctx, rw, req)
		if !ContextResponse(ctx).Written() {
			service.Send(ctx, 404, err)
		}
	})

	return service
}

// CancelAll sends a cancel signals to all request handlers via the context.
// See https://godoc.org/golang.org/x/net/context for details on how to handle the signal.
func (service *Service) CancelAll() {
	service.cancel()
}

// Use adds a middleware to the service wide middleware chain.
// goa comes with a set of commonly used middleware, see the middleware package.
// Controller specific middleware should be mounted using the Controller struct Use method instead.
func (service *Service) Use(m Middleware) {
	if service.finalized {
		panic("goa: cannot mount middleware after controller")
	}
	service.middleware = append(service.middleware, m)
}

// WithLogger sets the logger used internally by the service and by Log.
func (service *Service) WithLogger(logger LogAdapter) {
	service.Context = WithLogger(service.Context, logger)
}

// LogInfo logs the message and values at odd indeces using the keys at even indeces of the keyvals slice.
func (service *Service) LogInfo(msg string, keyvals ...interface{}) {
	LogInfo(service.Context, msg, keyvals...)
}

// LogError logs the error and values at odd indeces using the keys at even indeces of the keyvals slice.
func (service *Service) LogError(msg string, keyvals ...interface{}) {
	LogError(service.Context, msg, keyvals...)
}

// ListenAndServe starts a HTTP server and sets up a listener on the given host/port.
func (service *Service) ListenAndServe(addr string) error {
	service.LogInfo("listen", "transport", "http", "addr", addr)
	return http.ListenAndServe(addr, service.Mux)
}

// ListenAndServeTLS starts a HTTPS server and sets up a listener on the given host/port.
func (service *Service) ListenAndServeTLS(addr, certFile, keyFile string) error {
	service.LogInfo("listen", "transport", "https", "addr", addr)
	return http.ListenAndServeTLS(addr, certFile, keyFile, service.Mux)
}

// NewController returns a controller for the given resource. This method is mainly intended for
// use by the generated code. User code shouldn't have to call it directly.
func (service *Service) NewController(name string) *Controller {
	return &Controller{
		Name:    name,
		Service: service,
		Context: context.WithValue(service.Context, ctrlKey, name),
	}
}

// Send serializes the given body matching the request Accept header against the service
// encoders. It uses the default service encoder if no match is found.
func (service *Service) Send(ctx context.Context, code int, body interface{}) error {
	r := ContextResponse(ctx)
	if r == nil {
		return fmt.Errorf("no response data in context")
	}
	r.WriteHeader(code)
	return service.EncodeResponse(ctx, body)
}

// ServeFiles create a "FileServer" controller and calls ServerFiles on it.
func (service *Service) ServeFiles(path, filename string) error {
	ctrl := service.NewController("FileServer")
	return ctrl.ServeFiles(path, filename)
}

// finalize wraps the NotFound handler with the final middleware chain.
// Use cannot be called after finalize has.
func (service *Service) finalize() {
	if service.finalized {
		return
	}
	notFound := service.notFound
	handler := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		if !ContextResponse(ctx).Written() {
			return notFound(ctx, rw, req)
		}
		return nil
	}
	ml := len(service.middleware)
	for i := range service.middleware {
		handler = service.middleware[ml-i-1](handler)
	}
	service.notFound = handler
	service.finalized = true
}

// ServeFiles replies to the request with the contents of the named file or directory. See
// FileHandler for details.
func (ctrl *Controller) ServeFiles(path, filename string) error {
	if strings.Contains(path, ":") {
		return fmt.Errorf("path may only include wildcards that match the entire end of the URL (e.g. *filepath)")
	}
	LogInfo(ctrl.Context, "mount file", "name", filename, "route", fmt.Sprintf("GET %s", path))
	handler := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		if !ContextResponse(ctx).Written() {
			return ctrl.FileHandler(path, filename)(ctx, rw, req)
		}
		return nil
	}
	ctrl.Service.Mux.Handle("GET", path, ctrl.MuxHandler("serve", handler, nil))
	return nil
}

// Use adds a middleware to the controller.
// Service-wide middleware should be added via the Service Use method instead.
func (ctrl *Controller) Use(m Middleware) {
	if ctrl.Service.finalized {
		panic("goa: cannot mount middleware after controller")
	}
	ctrl.middleware = append(ctrl.middleware, m)
}

// MuxHandler wraps a request handler into a MuxHandler. The MuxHandler initializes the request
// context by loading the request state, invokes the handler and in case of error invokes the
// controller (if there is one) or Service error handler.
// This function is intended for the controller generated code. User code should not need to call
// it directly.
func (ctrl *Controller) MuxHandler(name string, hdlr Handler, unm Unmarshaler) MuxHandler {
	// Make sure middleware doesn't get mounted later
	ctrl.Service.finalize()

	// Setup middleware outside of closure
	middleware := func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		if !ContextResponse(ctx).Written() {
			return hdlr(ctx, rw, req)
		}
		return nil
	}
	chain := append(ctrl.Service.middleware, ctrl.middleware...)
	ml := len(chain)
	for i := range chain {
		middleware = chain[ml-i-1](middleware)
	}
	return func(rw http.ResponseWriter, req *http.Request, params url.Values) {
		// Build context
		ctx := NewContext(WithAction(ctrl.Context, name), rw, req, params)

		// Protect against request bodies with unreasonable length
		if MaxRequestBodyLength > 0 {
			req.Body = http.MaxBytesReader(rw, req.Body, MaxRequestBodyLength)
		}

		// Load body if any
		var err error
		if req.ContentLength > 0 && unm != nil {
			err = unm(ctx, ctrl.Service, req)
		}

		// Handle invalid payload
		handler := middleware
		if err != nil {
			handler = func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
				rw.Header().Set("Content-Type", ErrorMediaIdentifier)
				status := 400
				body := ErrInvalidEncoding(err)
				if err.Error() == "http: request body too large" {
					status = 413
					body = ErrRequestBodyTooLarge("body length exceeds %d bytes", MaxRequestBodyLength)
				}
				return ctrl.Service.Send(ctx, status, body)
			}
			for i := range chain {
				handler = chain[ml-i-1](handler)
			}
		}

		// Invoke middleware chain, errors should be caught earlier, e.g. by ErrorHandler middleware
		if err := handler(ctx, ContextResponse(ctx), req); err != nil {
			LogError(ctx, "uncaught error", "err", err)
			respBody := fmt.Sprintf("Internal error: %s", err) // Sprintf catches panics
			ctrl.Service.Send(ctx, 500, respBody)
		}
	}
}

// FileHandler returns a handler that serves files under the given filename for the given route path.
// The logic for what to do when the filename points to a file vs. a directory is the same as the
// standard http package ServeFile function. The path may end with a wildcard that matches the rest
// of the URL (e.g. *filepath). If it does the matching path is appended to filename to form the
// full file path, so:
//
// 	c.FileHandler("/index.html", "/www/data/index.html")
//
// Returns the content of the file "/www/data/index.html" when requests are sent to "/index.html"
// and:
//
//	c.FileHandler("/assets/*filepath", "/www/data/assets")
//
// returns the content of the file "/www/data/assets/x/y/z" when requests are sent to
// "/assets/x/y/z".
func (ctrl *Controller) FileHandler(path, filename string) Handler {
	var wc string
	if idx := strings.Index(path, "*"); idx > -1 && idx < len(path)-1 {
		wc = path[idx+1:]
	}
	return func(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
		fname := filename
		if len(wc) > 0 {
			if m, ok := ContextRequest(ctx).Params[wc]; ok {
				fname = filepath.Join(filename, m[0])
			}
		}
		LogInfo(ctrl.Context, "serve file", "name", fname, "route", req.URL.Path)
		dir, name := filepath.Split(fname)
		fs := http.Dir(dir)
		f, err := fs.Open(name)
		if err != nil {
			return ErrInvalidFile(err)
		}
		defer f.Close()
		d, err := f.Stat()
		if err != nil {
			return ErrInvalidFile(err)
		}
		// use contents of index.html for directory, if present
		if d.IsDir() {
			index := strings.TrimSuffix(name, "/") + "/index.html"
			ff, err := fs.Open(index)
			if err == nil {
				defer ff.Close()
				dd, err := ff.Stat()
				if err == nil {
					name = index
					d = dd
					f = ff
				}
			}
		}

		// serveContent will check modification time
		// Still a directory? (we didn't find an index.html file)
		if d.IsDir() {
			return dirList(rw, f)
		}
		http.ServeContent(rw, req, d.Name(), d.ModTime(), f)
		return nil
	}
}

var replacer = strings.NewReplacer(
	"&", "&",
	"<", "<",
	">", ">",
	// """ is shorter than """.
	`"`, """,
	// "'" is shorter than "'" and apos was not in HTML until HTML5.
	"'", "'",
)

func dirList(w http.ResponseWriter, f http.File) error {
	dirs, err := f.Readdir(-1)
	if err != nil {
		return err
	}
	sort.Sort(byName(dirs))

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprintf(w, "
\n")
	for _, d := range dirs {
		name := d.Name()
		if d.IsDir() {
			name += "/"
		}
		// name may contain '?' or '#', which must be escaped to remain
		// part of the URL path, and not indicate the start of a query
		// string or fragment.
		url := url.URL{Path: name}
		fmt.Fprintf(w, "%s\n", url.String(), replacer.Replace(name))
	}
	fmt.Fprintf(w, "
\n")
	return nil
}

type byName []os.FileInfo

func (s byName) Len() int           { return len(s) }
func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
func (s byName) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
<|endoftext|>


<commit_before>package cloudinary

import (
	"bytes"
	"crypto/sha1"
	"errors"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const (
	baseUploadUrl = "http://api.cloudinary.com/v1_1"
	imageType     = "image"
	rawType       = "raw"
)

type Service struct {
	cloudName string
	apiKey    string
	apiSecret string
	uploadURI *url.URL
}

// Dial will use the url to connect to the cloudinary service.
// The uri parameter must be a valid URI with the cloudinary:// scheme,
// i.e. cloudinary://api_key:api_secret@clound_name.
func Dial(uri string) (*Service, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return nil, err
	}
	if u.Scheme != "cloudinary" {
		return nil, errors.New("Missing cloudinary:// scheme in URI")
	}
	secret, exists := u.User.Password()
	if !exists {
		return nil, errors.New("No API secret provided in URI.")
	}
	s := &Service{
		cloudName: u.Host,
		apiKey:    u.User.Username(),
		apiSecret: secret,
	}
	// Default upload URI to the service. Can change at runtime in the
	// Upload() function for raw file uploading.
	up, err := url.Parse(fmt.Sprintf("%s/%s/image/upload/", baseUploadUrl, s.cloudName))
	if err != nil {
		return nil, err
	}
	s.uploadURI = up
	return s, nil
}

// CloudName returns the cloud name used to access the Cloudinary service.
func (s *Service) CloudName() string {
	return s.cloudName
}

// ApiKey returns the API key used to access the Cloudinary service.
func (s *Service) ApiKey() string {
	return s.apiKey
}

// DefaultUploadURI returns the default URI used to upload images to the Cloudinary service.
func (s *Service) DefaultUploadURI() *url.URL {
	return s.uploadURI
}

// cleanAssetName returns an asset name from the parent dirname and
// the file name without extension. The path /tmp/css/default.css will
// return css/default.
func cleanAssetName(path string) string {
	idx := strings.LastIndex(path, string(os.PathSeparator))
	if idx != -1 {
		idx = strings.LastIndex(path[:idx], string(os.PathSeparator))
	}
	publicId := path[idx+1:]
	return publicId[:len(publicId)-len(filepath.Ext(publicId))]
}

func (s *Service) walkIt(path string, info os.FileInfo, err error) error {
	if info.IsDir() {
		return nil
	}
	if err := s.uploadFile(path, false); err != nil {
		return err
	}
	return nil
}

// Upload file to the service. See Upload().
func (s *Service) uploadFile(path string, randomPublicId bool) error {
	buf := new(bytes.Buffer)
	w := multipart.NewWriter(buf)

	// Write public ID
	var publicId string
	if !randomPublicId {
		publicId = cleanAssetName(path)
		pi, err := w.CreateFormField("public_id")
		if err != nil {
			return err
		}
		pi.Write([]byte(publicId))
	}

	// Write API key
	ak, err := w.CreateFormField("api_key")
	if err != nil {
		return err
	}
	ak.Write([]byte(s.apiKey))

	// Write timestamp
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	ts, err := w.CreateFormField("timestamp")
	if err != nil {
		return err
	}
	ts.Write([]byte(timestamp))

	// Write signature
	hash := sha1.New()
	part := fmt.Sprintf("timestamp=%s%s", timestamp, s.apiSecret)
	if !randomPublicId {
		part = fmt.Sprintf("public_id=%s&%s", publicId, part)
	}
	io.WriteString(hash, part)
	signature := fmt.Sprintf("%x", hash.Sum(nil))

	si, err := w.CreateFormField("signature")
	if err != nil {
		return err
	}
	si.Write([]byte(signature))

	// Write file field
	fw, err := w.CreateFormFile("file", path)
	if err != nil {
		return err
	}
	fd, err := os.Open(path)
	if err != nil {
		return err
	}
	defer fd.Close()

	_, err = io.Copy(fw, fd)
	if err != nil {
		return err
	}
	// Don't forget to close the multipart writer to get a terminating boundary
	w.Close()

	upURI := s.uploadURI.String()
	ftype := mime.TypeByExtension(filepath.Ext(path))
	// Different URL for raw data upload
	if !strings.HasPrefix(ftype, imageType) {
		upURI = strings.Replace(upURI, imageType, rawType, 1)
	}
	req, err := http.NewRequest("POST", upURI, buf)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", w.FormDataContentType())
	resp, err := http.DefaultClient.Do(req)

	if err != nil {
		return err
	}
	fmt.Println(resp.Status, upURI)
	io.Copy(os.Stderr, resp.Body)

	return nil
}

// Upload a file or a set of files in the cloud. Set ramdomPublicId to true
// to let the service generate a unique random public id. If set to false,
// the ressource's // public id is computed using the absolute path to the file.
//
// For example, a raw file /tmp/css/default.css will be stored with a public
// name of css/default.css (raw file keeps its extension), but an image file
// /tmp/images/logo.png will be stored as images/logo.
//
// If the source path is a directory, all files are recursively uploaded to
// the cloud service.
func (s *Service) Upload(path string, randomPublicId bool) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	fmt.Println("Uploading...")
	if info.IsDir() {
		if err := filepath.Walk(path, s.walkIt); err != nil {
			return err
		}
	} else {
		if err := s.uploadFile(path, randomPublicId); err != nil {
			return err
		}
	}
	return nil
}

// Url returns the complete access path in the cloud to the
// ressource designed by publicId or the empty string if
// no match.
func (s *Service) Url(publicId string) string {
	return ""
}
<commit_msg>Doc typos<commit_after>package cloudinary

import (
	"bytes"
	"crypto/sha1"
	"errors"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const (
	baseUploadUrl = "http://api.cloudinary.com/v1_1"
	imageType     = "image"
	rawType       = "raw"
)

type Service struct {
	cloudName string
	apiKey    string
	apiSecret string
	uploadURI *url.URL
}

// Dial will use the url to connect to the Cloudinary service.
// The uri parameter must be a valid URI with the cloudinary:// scheme,
// e.g. cloudinary://api_key:api_secret@cloud_name.
func Dial(uri string) (*Service, error) {
	u, err := url.Parse(uri)
	if err != nil {
		return nil, err
	}
	if u.Scheme != "cloudinary" {
		return nil, errors.New("Missing cloudinary:// scheme in URI")
	}
	secret, exists := u.User.Password()
	if !exists {
		return nil, errors.New("No API secret provided in URI.")
	}
	s := &Service{
		cloudName: u.Host,
		apiKey:    u.User.Username(),
		apiSecret: secret,
	}
	// Default upload URI to the service. Can change at runtime in the
	// Upload() function for raw file uploading.
	up, err := url.Parse(fmt.Sprintf("%s/%s/image/upload/", baseUploadUrl, s.cloudName))
	if err != nil {
		return nil, err
	}
	s.uploadURI = up
	return s, nil
}

// CloudName returns the cloud name used to access the Cloudinary service.
func (s *Service) CloudName() string {
	return s.cloudName
}

// ApiKey returns the API key used to access the Cloudinary service.
func (s *Service) ApiKey() string {
	return s.apiKey
}

// DefaultUploadURI returns the default URI used to upload images to the Cloudinary service.
func (s *Service) DefaultUploadURI() *url.URL {
	return s.uploadURI
}

// cleanAssetName returns an asset name from the parent dirname and
// the file name without extension. The path /tmp/css/default.css will
// return css/default.
func cleanAssetName(path string) string {
	idx := strings.LastIndex(path, string(os.PathSeparator))
	if idx != -1 {
		idx = strings.LastIndex(path[:idx], string(os.PathSeparator))
	}
	publicId := path[idx+1:]
	return publicId[:len(publicId)-len(filepath.Ext(publicId))]
}

func (s *Service) walkIt(path string, info os.FileInfo, err error) error {
	if info.IsDir() {
		return nil
	}
	if err := s.uploadFile(path, false); err != nil {
		return err
	}
	return nil
}

// Upload file to the service. See Upload().
func (s *Service) uploadFile(path string, randomPublicId bool) error {
	buf := new(bytes.Buffer)
	w := multipart.NewWriter(buf)

	// Write public ID
	var publicId string
	if !randomPublicId {
		publicId = cleanAssetName(path)
		pi, err := w.CreateFormField("public_id")
		if err != nil {
			return err
		}
		pi.Write([]byte(publicId))
	}

	// Write API key
	ak, err := w.CreateFormField("api_key")
	if err != nil {
		return err
	}
	ak.Write([]byte(s.apiKey))

	// Write timestamp
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	ts, err := w.CreateFormField("timestamp")
	if err != nil {
		return err
	}
	ts.Write([]byte(timestamp))

	// Write signature
	hash := sha1.New()
	part := fmt.Sprintf("timestamp=%s%s", timestamp, s.apiSecret)
	if !randomPublicId {
		part = fmt.Sprintf("public_id=%s&%s", publicId, part)
	}
	io.WriteString(hash, part)
	signature := fmt.Sprintf("%x", hash.Sum(nil))

	si, err := w.CreateFormField("signature")
	if err != nil {
		return err
	}
	si.Write([]byte(signature))

	// Write file field
	fw, err := w.CreateFormFile("file", path)
	if err != nil {
		return err
	}
	fd, err := os.Open(path)
	if err != nil {
		return err
	}
	defer fd.Close()

	_, err = io.Copy(fw, fd)
	if err != nil {
		return err
	}
	// Don't forget to close the multipart writer to get a terminating boundary
	w.Close()

	upURI := s.uploadURI.String()
	ftype := mime.TypeByExtension(filepath.Ext(path))
	// Different URL for raw data upload
	if !strings.HasPrefix(ftype, imageType) {
		upURI = strings.Replace(upURI, imageType, rawType, 1)
	}
	req, err := http.NewRequest("POST", upURI, buf)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", w.FormDataContentType())
	resp, err := http.DefaultClient.Do(req)

	if err != nil {
		return err
	}
	fmt.Println(resp.Status, upURI)
	io.Copy(os.Stderr, resp.Body)

	return nil
}

// Upload a file or a set of files in the cloud. Set ramdomPublicId to true
// to let the service generate a unique random public id. If set to false,
// the ressource's public id is computed using the absolute path to the file.
//
// For example, a raw file /tmp/css/default.css will be stored with a public
// name of css/default.css (raw file keeps its extension), but an image file
// /tmp/images/logo.png will be stored as images/logo.
//
// If the source path is a directory, all files are recursively uploaded to
// the cloud service.
func (s *Service) Upload(path string, randomPublicId bool) error {
	info, err := os.Stat(path)
	if err != nil {
		return err
	}
	fmt.Println("Uploading...")
	if info.IsDir() {
		if err := filepath.Walk(path, s.walkIt); err != nil {
			return err
		}
	} else {
		if err := s.uploadFile(path, randomPublicId); err != nil {
			return err
		}
	}
	return nil
}

// Url returns the complete access path in the cloud to the
// ressource designed by publicId or the empty string if
// no match.
func (s *Service) Url(publicId string) string {
	return ""
}
<|endoftext|>


<commit_before>package penny

import (
	"errors"
	"github.com/BurntSushi/toml"
	"github.com/coreos/go-etcd/etcd"
	"io/ioutil"
	"log"
	"net"
	"os"
	"reflect"
	"sync"
	"sync/atomic"
	"bytes"
	"time"
	proto "./proto"
	capn "github.com/glycerine/go-capnproto"
)

type Config struct {
	machines []string
	log      string
	addr     string
}

func parse(file string) (*Config, error) {
	content, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}
	var conf Config
	if _, parse_err := toml.Decode(string(content), &conf); parse_err != nil {
		return nil, parse_err
	}
	return &conf, nil
}

type Service interface {
	Name() string
	Init() error
	Call(m proto.Msg) error
	Close()
}

type Entry struct {
	name      string
	item_type reflect.Type
	items     []reflect.Value
	reqn      int64
	mq        chan proto.Msg
	mutex     sync.Mutex
}

type Dock struct {
	storage map[string]Entry
	gmq     chan proto.Msg
	client  *etcd.Client
	harbor  *net.TCPAddr
	handle  *net.TCPListener
}

func NewDock(conf *Config) (*Dock, error) {
	file, err := os.Open(conf.log)
	if err != nil {
		return nil, err
	}
	etcd.SetLogger(log.New(file, "[test]", log.LstdFlags|log.Lshortfile))

	client := etcd.NewClient(conf.machines)
	res, err := client.Get("services", true, true)
	if err != nil {
		if _, cerr := client.CreateDir("services", 0); cerr != nil {
			return nil, err
		}
		res, err = client.Get("services", true, true)
		if err != nil {
			return nil, err
		}
	}
	if !res.Node.Dir {
		return nil, errors.New("service is not a dir")
	}

	addr, err := net.ResolveTCPAddr("tcp", conf.addr)
	if err != nil {
		return nil, err
	}
	handle, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return nil, err
	}
	return &Dock{storage: make(map[string]Entry, 32), gmq: make(chan proto.Msg, 100), client: client, harbor: addr, handle: handle }, nil
}

//TODO two suggested length is two verbose.
func (c *Dock) addService(name string, t reflect.Type, mqlen, instance_num int) {
	if _, ok := c.storage[name]; ok {
		panic("service exists")
	}

	c.storage[name] = Entry{mq: make(chan proto.Msg, mqlen), items: make([]reflect.Value, instance_num), item_type: t, name: name}
	go c.run(name)
}

// run service
func (c *Dock) run(name string) {
	serv, ok := c.storage[name]
	if !ok {
		panic("service not exists")
	}
	for {
		//TODO better load balance
		cur := atomic.AddInt64(&serv.reqn, 1)
		idx := cur % int64(len(serv.items))
		rv := serv.items[idx]
		if rv.IsNil() {
			rv = c.setup(name)
			serv.items[idx] = rv
		}

		m := <-serv.mq
		go callService(serv, idx, rv, m)
	}
}

func callService(serv Entry, idx int64, rv reflect.Value, m proto.Msg) {
	//TODO mutex while calling the service instance
	callMethod := rv.MethodByName("Call")
	param := []reflect.Value{reflect.ValueOf(m)}
	ret := callMethod.Call(param)

	//if call return error,then close and remove the instance
	//if close failed,panic
	if !ret[0].IsNil() {
		closeMethod := rv.MethodByName("Close")
		param = []reflect.Value{}
		closeRet := closeMethod.Call(param)
		if !closeRet[0].IsNil() {
			panic("close failed")
		}
		//TODO nicer remove instance
		serv.items[int(idx)] = reflect.ValueOf(nil)
	}
}

func (c *Dock) setup(name string) reflect.Value {
	if cell, ok := c.storage[name]; !ok {
		panic("service not exists")
	} else {
		cell.mutex.Lock()
		defer cell.mutex.Unlock()

		instance := reflect.New(cell.item_type)
		initMethod := instance.MethodByName("Init")
		if initMethod.IsValid() {
			param := make([]reflect.Value, 0)
			ret := initMethod.Call(param)
			if !ret[0].IsNil() {
				panic("setup failed")
			}
		} else {
			panic("Init Method invalid")
		}
		return instance
	}
}

func (c *Dock) dispatch() {
	for {
		m := <-c.gmq
		if serv, ok := c.storage[m.From()]; ok {
			serv.mq <- m
		}
		//TODO have no service named m.dest
	}
}

func (c *Dock) accept() {
	for {
		conn,err := c.handle.AcceptTCP()
		if err != nil {
			continue
		}
		go c.readMsg(conn)
	}
}

func (c *Dock) readMsg(conn *net.TCPConn) {
	conn.SetKeepAlivePeriod(time.Hour)
	defer conn.Close()

	buf := bytes.NewBuffer(make([]byte,1024*10))
	for {
		seg,err := capn.ReadFromStream(conn,buf)
		if err != nil {
			panic(err)
		}
		msg := proto.NewMsg(seg)
		msg.SetPass( msg.Pass() + 1 )
		c.gmq <- msg
	}
}

var defaultDock Dock

func init() {
	conf, err := parse("./conf.toml")
	if err != nil {
		panic(err)
	}
	defaultDock, err := NewDock(conf)
	if err != nil {
		panic(err)
	}
	slog := new(Slog)
	slua := new(Slua)
	defaultDock.addService("slog", reflect.TypeOf(*slog), 10, 1)
	defaultDock.addService("slua", reflect.TypeOf(*slua), 100, 10)
	go defaultDock.accept()
	go defaultDock.dispatch()
}
<commit_msg>add msg check<commit_after>package penny

import (
	"errors"
	"github.com/BurntSushi/toml"
	"github.com/coreos/go-etcd/etcd"
	"io/ioutil"
	"log"
	"net"
	"os"
	"reflect"
	"sync"
	"sync/atomic"
	"bytes"
	"time"
	proto "./proto"
	capn "github.com/glycerine/go-capnproto"
)

type Config struct {
	machines []string
	log      string
	addr     string
}

func parse(file string) (*Config, error) {
	content, err := ioutil.ReadFile(file)
	if err != nil {
		return nil, err
	}
	var conf Config
	if _, parse_err := toml.Decode(string(content), &conf); parse_err != nil {
		return nil, parse_err
	}
	return &conf, nil
}

type Service interface {
	Name() string
	Init() error
	Call(m proto.Msg) error
	Close()
}

type Entry struct {
	name      string
	item_type reflect.Type
	items     []reflect.Value
	reqn      int64
	mq        chan proto.Msg
	mutex     sync.Mutex
}

type Dock struct {
	storage map[string]Entry
	gmq     chan proto.Msg
	client  *etcd.Client
	harbor  *net.TCPAddr
	handle  *net.TCPListener
}

func NewDock(conf *Config) (*Dock, error) {
	file, err := os.Open(conf.log)
	if err != nil {
		return nil, err
	}
	etcd.SetLogger(log.New(file, "[test]", log.LstdFlags|log.Lshortfile))

	client := etcd.NewClient(conf.machines)
	res, err := client.Get("services", true, true)
	if err != nil {
		if _, cerr := client.CreateDir("services", 0); cerr != nil {
			return nil, err
		}
		res, err = client.Get("services", true, true)
		if err != nil {
			return nil, err
		}
	}
	if !res.Node.Dir {
		return nil, errors.New("service is not a dir")
	}

	addr, err := net.ResolveTCPAddr("tcp", conf.addr)
	if err != nil {
		return nil, err
	}
	handle, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return nil, err
	}
	return &Dock{storage: make(map[string]Entry, 32), gmq: make(chan proto.Msg, 100), client: client, harbor: addr, handle: handle }, nil
}

//TODO two suggested length is two verbose.
func (c *Dock) AddService(name string, t reflect.Type, mqlen, instance_num int) {
	if _, ok := c.storage[name]; ok {
		panic("service exists")
	}

	c.storage[name] = Entry{mq: make(chan proto.Msg, mqlen), items: make([]reflect.Value, instance_num), item_type: t, name: name}
	go c.start(name)
}

// start service
func (c *Dock) start(name string) {
	serv, ok := c.storage[name]
	if !ok {
		panic("service not exists")
	}
	for {
		//TODO better load balance
		cur := atomic.AddInt64(&serv.reqn, 1)
		idx := cur % int64(len(serv.items))
		rv := serv.items[idx]
		if rv.IsNil() {
			rv = c.setup(name)
			serv.items[idx] = rv
		}

		m := <-serv.mq
		go callService(serv, idx, rv, m)
	}
}

func callService(serv Entry, idx int64, rv reflect.Value, m proto.Msg) {
	//TODO mutex while calling the service instance
	callMethod := rv.MethodByName("Call")
	param := []reflect.Value{reflect.ValueOf(m)}
	ret := callMethod.Call(param)

	//if call return error,then close and remove the instance
	//if close failed,panic
	if !ret[0].IsNil() {
		closeMethod := rv.MethodByName("Close")
		param = []reflect.Value{}
		closeRet := closeMethod.Call(param)
		if !closeRet[0].IsNil() {
			panic("close failed")
		}
		//TODO nicer remove instance
		serv.items[int(idx)] = reflect.ValueOf(nil)
	}
}

func (c *Dock) setup(name string) reflect.Value {
	if cell, ok := c.storage[name]; !ok {
		panic("service not exists")
	} else {
		cell.mutex.Lock()
		defer cell.mutex.Unlock()

		instance := reflect.New(cell.item_type)
		initMethod := instance.MethodByName("Init")
		if initMethod.IsValid() {
			param := make([]reflect.Value, 0)
			ret := initMethod.Call(param)
			if !ret[0].IsNil() {
				panic("setup failed")
			}
		} else {
			panic("Init Method invalid")
		}
		return instance
	}
}

func (c *Dock) dispatch() {
	for {
		m := <-c.gmq
		if serv, ok := c.storage[m.From()]; ok {
			serv.mq <- m
		}
		//TODO have no service named m.dest
	}
}

func (c *Dock) accept() {
	for {
		conn,err := c.handle.AcceptTCP()
		if err != nil {
			//TODO log the handing error
			continue
		}
		go c.readMsg(conn)
	}
}

// Read msg from other dock instance.
func (c *Dock) readMsg(conn *net.TCPConn) {
	defer conn.Close()

	err := conn.SetKeepAlivePeriod(time.Hour)
	if err != nil {
		panic(err)
	}

	// 10k read buffer
	buf := bytes.NewBuffer(make([]byte,1024*10))
	for {
		seg,err := capn.ReadFromStream(conn,buf)
		if err != nil {
			panic(err)
		}
		msg := proto.ReadRootMsg(seg)
		// since readRootMsg doesn't return error,we need test it
		if len(msg.Method()) == 0 {
			continue
		}

		// inc pass by 1.so we know if some pkg transfer how many times
		msg.SetPass( msg.Pass() + 1 )
		c.gmq <- msg
	}
}

func (c *Dock) Run() {
	go defaultDock.accept()
	go defaultDock.dispatch()
}

var defaultDock Dock

func init() {
	conf, err := parse("./conf.toml")
	if err != nil {
		panic(err)
	}
	defaultDock, err := NewDock(conf)
	if err != nil {
		panic(err)
	}
	slog := new(Slog)
	slua := new(Slua)
	defaultDock.AddService("slog", reflect.TypeOf(*slog), 10, 1)
	defaultDock.AddService("slua", reflect.TypeOf(*slua), 100, 10)
	defaultDock.Run()
}
<|endoftext|>


<commit_before>package panos

import (
	"encoding/xml"
	"fmt"
	"github.com/scottdware/go-rested"
)

// ServiceObjects contains a slice of all service objects.
type ServiceObjects struct {
	XMLName  xml.Name  `xml:"response"`
	Services []Service `xml:"result>service>entry"`
}

// Service contains information about each individual service object.
type Service struct {
	Name        string `xml:"name,attr"`
	TCPPort     string `xml:"protocol>tcp>port,omitempty"`
	UDPPort     string `xml:"protocol>udp>port,omitempty"`
	Description string `xml:"description,omitempty"`
}

// ServiceGroups contains a slice of all service groups.
type ServiceGroups struct {
	XMLName xml.Name       `xml:"response"`
	Groups  []ServiceGroup `xml:"result>service-group>entry"`
}

// ServiceGroup contains information about each individual service group.
type ServiceGroup struct {
	Name        string   `xml:"name,attr"`
	Members     []string `xml:"members>member,omitempty"`
	Description string   `xml:"description,omitempty"`
}

// Services returns information about all of the address objects.
func (p *PaloAlto) Services() *ServiceObjects {
	var svcs ServiceObjects
	r := rested.NewRequest()

	// xpath := "/config/devices/entry/vsys/entry/address"
	xpath := "/config/devices/entry//service"

	if p.DeviceType == "panorama" {
		// xpath = "/config/devices/entry/device-group/entry/address"
		xpath = "/config/devices/entry//service"
	}

	query := map[string]string{
		"type":   "config",
		"action": "get",
		"xpath":  xpath,
		"key":    p.Key,
	}
	svcData := r.Send("get", p.URI, nil, headers, query)

	if err := xml.Unmarshal(svcData.Body, &svcs); err != nil {
		fmt.Println(err)
	}

	return &svcs
}

// ServiceGroups returns information about all of the service groups.
func (p *PaloAlto) ServiceGroups() *ServiceGroups {
	var groups ServiceGroups
	r := rested.NewRequest()

	// xpath := "/config/devices/entry/vsys/entry/address-group"
	xpath := "/config/devices/entry//service-group"

	if p.DeviceType == "panorama" {
		// xpath = "/config/devices/entry/device-group/entry/address-group"
		xpath = "/config/devices/entry//service-group"
	}

	query := map[string]string{
		"type":   "config",
		"action": "get",
		"xpath":  xpath,
		"key":    p.Key,
	}
	groupData := r.Send("get", p.URI, nil, headers, query)

	if err := xml.Unmarshal(groupData.Body, &groups); err != nil {
		fmt.Println(err)
	}

	return &groups
}
<commit_msg>Added device verification<commit_after>package panos

import (
	"encoding/xml"
	"fmt"
	"github.com/scottdware/go-rested"
)

// ServiceObjects contains a slice of all service objects.
type ServiceObjects struct {
	XMLName  xml.Name  `xml:"response"`
	Services []Service `xml:"result>service>entry"`
}

// Service contains information about each individual service object.
type Service struct {
	Name        string `xml:"name,attr"`
	TCPPort     string `xml:"protocol>tcp>port,omitempty"`
	UDPPort     string `xml:"protocol>udp>port,omitempty"`
	Description string `xml:"description,omitempty"`
}

// ServiceGroups contains a slice of all service groups.
type ServiceGroups struct {
	XMLName xml.Name       `xml:"response"`
	Groups  []ServiceGroup `xml:"result>service-group>entry"`
}

// ServiceGroup contains information about each individual service group.
type ServiceGroup struct {
	Name        string   `xml:"name,attr"`
	Members     []string `xml:"members>member,omitempty"`
	Description string   `xml:"description,omitempty"`
}

// Services returns information about all of the address objects.
func (p *PaloAlto) Services() *ServiceObjects {
	var svcs ServiceObjects
	xpath := "/config/devices/entry//service"
	// xpath := "/config/devices/entry/vsys/entry/address"
	r := rested.NewRequest()

	if p.DeviceType == "panos" && p.Panorama == true {
		xpath = "/config/panorama//service"
	}

	if p.DeviceType == "panorama" {
		// xpath = "/config/devices/entry/device-group/entry/address"
		xpath = "/config/devices/entry//service"
	}

	query := map[string]string{
		"type":   "config",
		"action": "get",
		"xpath":  xpath,
		"key":    p.Key,
	}
	svcData := r.Send("get", p.URI, nil, headers, query)

	if err := xml.Unmarshal(svcData.Body, &svcs); err != nil {
		fmt.Println(err)
	}

	return &svcs
}

// ServiceGroups returns information about all of the service groups.
func (p *PaloAlto) ServiceGroups() *ServiceGroups {
	var groups ServiceGroups
	xpath := "/config/devices/entry//service-group"
	// xpath := "/config/devices/entry/vsys/entry/address-group"
	r := rested.NewRequest()

	if p.DeviceType == "panos" && p.Panorama == true {
		xpath = "/config/panorama//service-group"
	}

	if p.DeviceType == "panorama" {
		// xpath = "/config/devices/entry/device-group/entry/address-group"
		xpath = "/config/devices/entry//service-group"
	}

	query := map[string]string{
		"type":   "config",
		"action": "get",
		"xpath":  xpath,
		"key":    p.Key,
	}
	groupData := r.Send("get", p.URI, nil, headers, query)

	if err := xml.Unmarshal(groupData.Body, &groups); err != nil {
		fmt.Println(err)
	}

	return &groups
}
<|endoftext|>


<commit_before>// session.go - mixnet client session
// Copyright (C) 2018  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package client

import (
	"context"
	"encoding/hex"
	"errors"
	"fmt"
	mrand "math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/katzenpost/client/config"
	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/client/internal/pkiclient"
	"github.com/katzenpost/client/utils"
	coreConstants "github.com/katzenpost/core/constants"
	"github.com/katzenpost/core/crypto/ecdh"
	"github.com/katzenpost/core/log"
	"github.com/katzenpost/core/pki"
	"github.com/katzenpost/core/sphinx"
	sConstants "github.com/katzenpost/core/sphinx/constants"
	"github.com/katzenpost/core/worker"
	"github.com/katzenpost/minclient"
	"gopkg.in/eapache/channels.v1"
	"gopkg.in/op/go-logging.v1"
)

// Session is the struct type that keeps state for a given session.
type Session struct {
	worker.Worker

	cfg       *config.Config
	pkiClient pki.Client
	minclient *minclient.Client
	log       *logging.Logger

	fatalErrCh chan error
	opCh       chan workerOp

	eventCh   channels.Channel
	EventSink chan Event

	linkKey   *ecdh.PrivateKey
	onlineAt  time.Time
	hasPKIDoc bool

	egressQueue EgressQueue

	surbIDMap        sync.Map // [sConstants.SURBIDLength]byte -> *Message
	sentWaitChanMap  sync.Map // MessageID -> chan *Message
	replyWaitChanMap sync.Map // MessageID -> chan []byte

	decoyLoopTally uint64
}

// New establishes a session with provider using key.
// This method will block until session is connected to the Provider.
func NewSession(
	ctx context.Context,
	fatalErrCh chan error,
	logBackend *log.Backend,
	cfg *config.Config,
	linkKey *ecdh.PrivateKey) (*Session, error) {
	var err error

	// create a pkiclient for our own client lookups
	// AND create a pkiclient for minclient's use
	proxyCfg := cfg.UpstreamProxyConfig()
	pkiClient, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}

	// create a pkiclient for minclient's use
	pkiClient2, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}
	pkiCacheClient := pkiclient.New(pkiClient2)

	clientLog := logBackend.GetLogger(fmt.Sprintf("%s@%s_client", cfg.Account.User, cfg.Account.Provider))

	s := &Session{
		cfg:         cfg,
		linkKey:     linkKey,
		pkiClient:   pkiClient,
		log:         clientLog,
		fatalErrCh:  fatalErrCh,
		eventCh:     channels.NewInfiniteChannel(),
		EventSink:   make(chan Event),
		opCh:        make(chan workerOp, 8),
		egressQueue: new(Queue),
	}
	// Configure and bring up the minclient instance.
	clientCfg := &minclient.ClientConfig{
		User:                cfg.Account.User,
		Provider:            cfg.Account.Provider,
		ProviderKeyPin:      cfg.Account.ProviderKeyPin,
		LinkKey:             s.linkKey,
		LogBackend:          logBackend,
		PKIClient:           pkiCacheClient,
		OnConnFn:            s.onConnection,
		OnMessageFn:         s.onMessage,
		OnACKFn:             s.onACK,
		OnDocumentFn:        s.onDocument,
		DialContextFn:       proxyCfg.ToDialContext("authority"),
		PreferedTransports:  pki.Transport("onion"), // XXX
		MessagePollInterval: 1 * time.Second,
		EnableTimeSync:      false, // Be explicit about it.
	}

	s.Go(s.eventSinkWorker)
	s.Go(s.garbageCollectionWorker)

	s.minclient, err = minclient.New(clientCfg)
	if err != nil {
		return nil, err
	}

	// block until we get the first PKI document
	// and then set our timers accordingly
	err = s.awaitFirstPKIDoc(ctx)
	if err != nil {
		return nil, err
	}
	s.Go(s.worker)
	return s, nil
}

func (s *Session) eventSinkWorker() {
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Event sink worker terminating gracefully.")
			return
		case e := <-s.eventCh.Out():
			select {
			case s.EventSink <- e.(Event):
			case <-s.HaltCh():
				s.log.Debugf("Event sink worker terminating gracefully.")
				return
			}
		}
	}
}

func (s *Session) garbageCollectionWorker() {
	timer := time.NewTimer(cConstants.GarbageCollectionInterval)
	defer timer.Stop()
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Garbage collection worker terminating gracefully.")
			return
		case <-timer.C:
			s.garbageCollect()
			timer.Reset(cConstants.GarbageCollectionInterval)
		}
	}
}

func (s *Session) garbageCollect() {
	s.log.Debug("Running garbage collection process.")
	// [sConstants.SURBIDLength]byte -> *Message
	surbIDMapRange := func(rawSurbID, rawMessage interface{}) bool {
		surbID := rawSurbID.([sConstants.SURBIDLength]byte)
		message := rawMessage.(*Message)
		if message.IsBlocking {
			// Blocking sends don't need this garbage collection mechanism
			// because the BlockingSendUnreliableMessage method will clean up
			// after itself.
			return true
		}
		if time.Now().After(message.SentAt.Add(message.ReplyETA).Add(cConstants.RoundTripTimeSlop)) {
			s.log.Debug("Garbage collecting SURB ID Map entry for Message ID %x", message.ID)
			s.surbIDMap.Delete(surbID)
			s.eventCh.In() <- &MessageIDGarbageCollected{
				MessageID: message.ID,
			}
		}
		return true
	}
	s.surbIDMap.Range(surbIDMapRange)
}

func (s *Session) awaitFirstPKIDoc(ctx context.Context) error {
	for {
		var qo workerOp
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-s.HaltCh():
			s.log.Debugf("Await first pki doc worker terminating gracefully")
			return errors.New("terminating gracefully")
		case <-time.After(time.Duration(s.cfg.Debug.InitialMaxPKIRetrievalDelay) * time.Second):
			return errors.New("timeout failure awaiting first PKI document")
		case qo = <-s.opCh:
		}
		switch op := qo.(type) {
		case opNewDocument:
			// Determine if PKI doc is valid. If not then abort.
			err := s.isDocValid(op.doc)
			if err != nil {
				s.fatalErrCh <- fmt.Errorf("aborting, PKI doc is not valid for our decoy traffic use case: %v", err)
				return err
			}
			return nil
		default:
			continue
		}
	}
	// NOT REACHED
}

// GetService returns a randomly selected service
// matching the specified service name
func (s *Session) GetService(serviceName string) (*utils.ServiceDescriptor, error) {
	doc := s.minclient.CurrentDocument()
	if doc == nil {
		return nil, errors.New("pki doc is nil")
	}
	serviceDescriptors := utils.FindServices(serviceName, doc)
	if len(serviceDescriptors) == 0 {
		return nil, errors.New("error, GetService failure, service not found in pki doc")
	}
	return &serviceDescriptors[mrand.Intn(len(serviceDescriptors))], nil
}

// OnConnection will be called by the minclient api
// upon connection change status to the Provider
func (s *Session) onConnection(err error) {
	s.log.Debugf("onConnection %v", err)
	s.eventCh.In() <- &ConnectionStatusEvent{
		IsConnected: err == nil,
		Err:         err,
	}
	s.opCh <- opConnStatusChanged{
		isConnected: err == nil,
	}
}

// OnMessage will be called by the minclient api
// upon receiving a message
func (s *Session) onMessage(ciphertextBlock []byte) error {
	s.log.Debugf("OnMessage")
	return nil
}

func (s *Session) incrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, 1)
}

func (s *Session) decrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, ^uint64(0))
}

// OnACK is called by the minclient api when we receive a SURB reply message.
func (s *Session) onACK(surbID *[sConstants.SURBIDLength]byte, ciphertext []byte) error {
	idStr := fmt.Sprintf("[%v]", hex.EncodeToString(surbID[:]))
	s.log.Infof("OnACK with SURBID %x", idStr)

	rawMessage, ok := s.surbIDMap.Load(*surbID)
	if !ok {
		s.log.Debug("Strange, received reply with unexpected SURBID")
		return nil
	}
	s.surbIDMap.Delete(*surbID)
	msg := rawMessage.(*Message)
	plaintext, err := sphinx.DecryptSURBPayload(ciphertext, msg.Key)
	if err != nil {
		s.log.Infof("Discarding SURB Reply, decryption failure: %s", err)
		return nil
	}
	if len(plaintext) != coreConstants.ForwardPayloadLength {
		s.log.Warningf("Discarding SURB %v: Invalid payload size: %v", idStr, len(plaintext))
		return nil
	}
	if msg.WithSURB && msg.IsDecoy {
		s.decrementDecoyLoopTally()
		return nil
	}

	if msg.IsBlocking {
		replyWaitChanRaw, ok := s.replyWaitChanMap.Load(*msg.ID)
		if !ok {
			err := fmt.Errorf("BUG, failure to acquire replyWaitChan for message ID %x", msg.ID)
			s.fatalErrCh <- err
			return err
		}
		replyWaitChan := replyWaitChanRaw.(chan []byte)
		replyWaitChan <- plaintext[2:]
	} else {
		s.eventCh.In() <- &MessageReplyEvent{
			MessageID: msg.ID,
			Payload:   plaintext[2:],
			Err:       nil,
		}
	}
	return nil
}

func (s *Session) onDocument(doc *pki.Document) {
	s.log.Debugf("onDocument(): Epoch %v", doc.Epoch)
	s.hasPKIDoc = true
	s.opCh <- opNewDocument{
		doc: doc,
	}
	s.eventCh.In() <- &NewDocumentEvent{
		Document: doc,
	}
}

func (s *Session) CurrentDocument() *pki.Document {
	return s.minclient.CurrentDocument()
}

func (s *Session) GetPandaConfig() *config.Panda {
	return s.cfg.Panda
}

func (s *Session) Shutdown() {
	s.Halt()
	s.minclient.Shutdown()
	s.minclient.Wait()
}
<commit_msg>fix minclient preferred transports config field<commit_after>// session.go - mixnet client session
// Copyright (C) 2018  David Stainton.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package client

import (
	"context"
	"encoding/hex"
	"errors"
	"fmt"
	mrand "math/rand"
	"sync"
	"sync/atomic"
	"time"

	"github.com/katzenpost/client/config"
	cConstants "github.com/katzenpost/client/constants"
	"github.com/katzenpost/client/internal/pkiclient"
	"github.com/katzenpost/client/utils"
	coreConstants "github.com/katzenpost/core/constants"
	"github.com/katzenpost/core/crypto/ecdh"
	"github.com/katzenpost/core/log"
	"github.com/katzenpost/core/pki"
	"github.com/katzenpost/core/sphinx"
	sConstants "github.com/katzenpost/core/sphinx/constants"
	"github.com/katzenpost/core/worker"
	"github.com/katzenpost/minclient"
	"gopkg.in/eapache/channels.v1"
	"gopkg.in/op/go-logging.v1"
)

// Session is the struct type that keeps state for a given session.
type Session struct {
	worker.Worker

	cfg       *config.Config
	pkiClient pki.Client
	minclient *minclient.Client
	log       *logging.Logger

	fatalErrCh chan error
	opCh       chan workerOp

	eventCh   channels.Channel
	EventSink chan Event

	linkKey   *ecdh.PrivateKey
	onlineAt  time.Time
	hasPKIDoc bool

	egressQueue EgressQueue

	surbIDMap        sync.Map // [sConstants.SURBIDLength]byte -> *Message
	sentWaitChanMap  sync.Map // MessageID -> chan *Message
	replyWaitChanMap sync.Map // MessageID -> chan []byte

	decoyLoopTally uint64
}

// New establishes a session with provider using key.
// This method will block until session is connected to the Provider.
func NewSession(
	ctx context.Context,
	fatalErrCh chan error,
	logBackend *log.Backend,
	cfg *config.Config,
	linkKey *ecdh.PrivateKey) (*Session, error) {
	var err error

	// create a pkiclient for our own client lookups
	// AND create a pkiclient for minclient's use
	proxyCfg := cfg.UpstreamProxyConfig()
	pkiClient, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}

	// create a pkiclient for minclient's use
	pkiClient2, err := cfg.NewPKIClient(logBackend, proxyCfg)
	if err != nil {
		return nil, err
	}
	pkiCacheClient := pkiclient.New(pkiClient2)

	clientLog := logBackend.GetLogger(fmt.Sprintf("%s@%s_client", cfg.Account.User, cfg.Account.Provider))

	s := &Session{
		cfg:         cfg,
		linkKey:     linkKey,
		pkiClient:   pkiClient,
		log:         clientLog,
		fatalErrCh:  fatalErrCh,
		eventCh:     channels.NewInfiniteChannel(),
		EventSink:   make(chan Event),
		opCh:        make(chan workerOp, 8),
		egressQueue: new(Queue),
	}
	// Configure and bring up the minclient instance.
	clientCfg := &minclient.ClientConfig{
		User:                cfg.Account.User,
		Provider:            cfg.Account.Provider,
		ProviderKeyPin:      cfg.Account.ProviderKeyPin,
		LinkKey:             s.linkKey,
		LogBackend:          logBackend,
		PKIClient:           pkiCacheClient,
		OnConnFn:            s.onConnection,
		OnMessageFn:         s.onMessage,
		OnACKFn:             s.onACK,
		OnDocumentFn:        s.onDocument,
		DialContextFn:       proxyCfg.ToDialContext("authority"),
		PreferedTransports:  []pki.Transport{"onion"}, // XXX
		MessagePollInterval: 1 * time.Second,
		EnableTimeSync:      false, // Be explicit about it.
	}

	s.Go(s.eventSinkWorker)
	s.Go(s.garbageCollectionWorker)

	s.minclient, err = minclient.New(clientCfg)
	if err != nil {
		return nil, err
	}

	// block until we get the first PKI document
	// and then set our timers accordingly
	err = s.awaitFirstPKIDoc(ctx)
	if err != nil {
		return nil, err
	}
	s.Go(s.worker)
	return s, nil
}

func (s *Session) eventSinkWorker() {
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Event sink worker terminating gracefully.")
			return
		case e := <-s.eventCh.Out():
			select {
			case s.EventSink <- e.(Event):
			case <-s.HaltCh():
				s.log.Debugf("Event sink worker terminating gracefully.")
				return
			}
		}
	}
}

func (s *Session) garbageCollectionWorker() {
	timer := time.NewTimer(cConstants.GarbageCollectionInterval)
	defer timer.Stop()
	for {
		select {
		case <-s.HaltCh():
			s.log.Debugf("Garbage collection worker terminating gracefully.")
			return
		case <-timer.C:
			s.garbageCollect()
			timer.Reset(cConstants.GarbageCollectionInterval)
		}
	}
}

func (s *Session) garbageCollect() {
	s.log.Debug("Running garbage collection process.")
	// [sConstants.SURBIDLength]byte -> *Message
	surbIDMapRange := func(rawSurbID, rawMessage interface{}) bool {
		surbID := rawSurbID.([sConstants.SURBIDLength]byte)
		message := rawMessage.(*Message)
		if message.IsBlocking {
			// Blocking sends don't need this garbage collection mechanism
			// because the BlockingSendUnreliableMessage method will clean up
			// after itself.
			return true
		}
		if time.Now().After(message.SentAt.Add(message.ReplyETA).Add(cConstants.RoundTripTimeSlop)) {
			s.log.Debug("Garbage collecting SURB ID Map entry for Message ID %x", message.ID)
			s.surbIDMap.Delete(surbID)
			s.eventCh.In() <- &MessageIDGarbageCollected{
				MessageID: message.ID,
			}
		}
		return true
	}
	s.surbIDMap.Range(surbIDMapRange)
}

func (s *Session) awaitFirstPKIDoc(ctx context.Context) error {
	for {
		var qo workerOp
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-s.HaltCh():
			s.log.Debugf("Await first pki doc worker terminating gracefully")
			return errors.New("terminating gracefully")
		case <-time.After(time.Duration(s.cfg.Debug.InitialMaxPKIRetrievalDelay) * time.Second):
			return errors.New("timeout failure awaiting first PKI document")
		case qo = <-s.opCh:
		}
		switch op := qo.(type) {
		case opNewDocument:
			// Determine if PKI doc is valid. If not then abort.
			err := s.isDocValid(op.doc)
			if err != nil {
				s.fatalErrCh <- fmt.Errorf("aborting, PKI doc is not valid for our decoy traffic use case: %v", err)
				return err
			}
			return nil
		default:
			continue
		}
	}
	// NOT REACHED
}

// GetService returns a randomly selected service
// matching the specified service name
func (s *Session) GetService(serviceName string) (*utils.ServiceDescriptor, error) {
	doc := s.minclient.CurrentDocument()
	if doc == nil {
		return nil, errors.New("pki doc is nil")
	}
	serviceDescriptors := utils.FindServices(serviceName, doc)
	if len(serviceDescriptors) == 0 {
		return nil, errors.New("error, GetService failure, service not found in pki doc")
	}
	return &serviceDescriptors[mrand.Intn(len(serviceDescriptors))], nil
}

// OnConnection will be called by the minclient api
// upon connection change status to the Provider
func (s *Session) onConnection(err error) {
	s.log.Debugf("onConnection %v", err)
	s.eventCh.In() <- &ConnectionStatusEvent{
		IsConnected: err == nil,
		Err:         err,
	}
	s.opCh <- opConnStatusChanged{
		isConnected: err == nil,
	}
}

// OnMessage will be called by the minclient api
// upon receiving a message
func (s *Session) onMessage(ciphertextBlock []byte) error {
	s.log.Debugf("OnMessage")
	return nil
}

func (s *Session) incrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, 1)
}

func (s *Session) decrementDecoyLoopTally() {
	atomic.AddUint64(&s.decoyLoopTally, ^uint64(0))
}

// OnACK is called by the minclient api when we receive a SURB reply message.
func (s *Session) onACK(surbID *[sConstants.SURBIDLength]byte, ciphertext []byte) error {
	idStr := fmt.Sprintf("[%v]", hex.EncodeToString(surbID[:]))
	s.log.Infof("OnACK with SURBID %x", idStr)

	rawMessage, ok := s.surbIDMap.Load(*surbID)
	if !ok {
		s.log.Debug("Strange, received reply with unexpected SURBID")
		return nil
	}
	s.surbIDMap.Delete(*surbID)
	msg := rawMessage.(*Message)
	plaintext, err := sphinx.DecryptSURBPayload(ciphertext, msg.Key)
	if err != nil {
		s.log.Infof("Discarding SURB Reply, decryption failure: %s", err)
		return nil
	}
	if len(plaintext) != coreConstants.ForwardPayloadLength {
		s.log.Warningf("Discarding SURB %v: Invalid payload size: %v", idStr, len(plaintext))
		return nil
	}
	if msg.WithSURB && msg.IsDecoy {
		s.decrementDecoyLoopTally()
		return nil
	}

	if msg.IsBlocking {
		replyWaitChanRaw, ok := s.replyWaitChanMap.Load(*msg.ID)
		if !ok {
			err := fmt.Errorf("BUG, failure to acquire replyWaitChan for message ID %x", msg.ID)
			s.fatalErrCh <- err
			return err
		}
		replyWaitChan := replyWaitChanRaw.(chan []byte)
		replyWaitChan <- plaintext[2:]
	} else {
		s.eventCh.In() <- &MessageReplyEvent{
			MessageID: msg.ID,
			Payload:   plaintext[2:],
			Err:       nil,
		}
	}
	return nil
}

func (s *Session) onDocument(doc *pki.Document) {
	s.log.Debugf("onDocument(): Epoch %v", doc.Epoch)
	s.hasPKIDoc = true
	s.opCh <- opNewDocument{
		doc: doc,
	}
	s.eventCh.In() <- &NewDocumentEvent{
		Document: doc,
	}
}

func (s *Session) CurrentDocument() *pki.Document {
	return s.minclient.CurrentDocument()
}

func (s *Session) GetPandaConfig() *config.Panda {
	return s.cfg.Panda
}

func (s *Session) Shutdown() {
	s.Halt()
	s.minclient.Shutdown()
	s.minclient.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var cmdFix = &Command{
	UsageLine: "fix",
	Short:     "fix the beego application to compatibel with beego 1.6",
	Long: `
As from beego1.6, there's some incompatible code with the old version.

bee fix help to upgrade the application to beego 1.6
`,
}

func init() {
	cmdFix.Run = runFix
}

func runFix(cmd *Command, args []string) int {
	dir, err := os.Getwd()
	if err != nil {
		ColorLog("GetCurrent Path:%s\n", err)
	}
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if strings.HasPrefix(info.Name(), ".") {
				return filepath.SkipDir
			}
			return nil
		}
		if err != nil {
			return err
		}
		ColorLog("%s\n", path)
		err = fixFile(path)
		if err != nil {
			ColorLog("fixFile:%s\n", err)
		}
		return err
	})
	return 0
}

var rules = []string{
	"beego.AppName", "beego.BConfig.AppName",
	"beego.RunMode", "beego.BConfig.RunMode",
	"beego.RecoverPanic", "beego.BConfig.RecoverPanic",
	"beego.RouterCaseSensitive", "beego.BConfig.RouterCaseSensitive",
	"beego.BeegoServerName", "beego.BConfig.ServerName",
	"beego.EnableGzip", "beego.BConfig.EnableGzip",
	"beego.ErrorsShow", "beego.BConfig.EnableErrorsShow",
	"beego.CopyRequestBody", "beego.BConfig.CopyRequestBody",
	"beego.MaxMemory", "beego.BConfig.MaxMemory",
	"beego.Graceful", "beego.BConfig.Listen.Graceful",
	"beego.HttpAddr", "beego.BConfig.Listen.HTTPAddr",
	"beego.HttpPort", "beego.BConfig.Listen.HTTPPort",
	"beego.ListenTCP4", "beego.BConfig.Listen.ListenTCP4",
	"beego.EnableHttpListen", "beego.BConfig.Listen.HTTPEnable",
	"beego.EnableHttpTLS", "beego.BConfig.Listen.HTTPSEnable",
	"beego.HttpsAddr", "beego.BConfig.Listen.HTTPSAddr",
	"beego.HttpsPort", "beego.BConfig.Listen.HTTPSPort",
	"beego.HttpCertFile", "beego.BConfig.Listen.HTTPSCertFile",
	"beego.HttpKeyFile", "beego.BConfig.Listen.HTTPSKeyFile",
	"beego.EnableAdmin", "beego.BConfig.Listen.AdminEnable",
	"beego.AdminHttpAddr", "beego.BConfig.Listen.AdminAddr",
	"beego.AdminHttpPort", "beego.BConfig.Listen.AdminPort",
	"beego.UseFcgi", "beego.BConfig.Listen.EnableFcgi",
	"beego.HttpServerTimeOut", "beego.BConfig.Listen.ServerTimeOut",
	"beego.AutoRender", "beego.BConfig.WebConfig.AutoRender",
	"beego.ViewsPath", "beego.BConfig.WebConfig.ViewsPath",
	"beego.DirectoryIndex", "beego.BConfig.WebConfig.DirectoryIndex",
	"beego.FlashName", "beego.BConfig.WebConfig.FlashName",
	"beego.FlashSeperator", "beego.BConfig.WebConfig.FlashSeperator",
	"beego.EnableDocs", "beego.BConfig.WebConfig.EnableDocs",
	"beego.XSRFKEY", "beego.BConfig.WebConfig.XSRFKEY",
	"beego.EnableXSRF", "beego.BConfig.WebConfig.EnableXSRF",
	"beego.XSRFExpire", "beego.BConfig.WebConfig.XSRFExpire",
	"beego.TemplateLeft", "beego.BConfig.WebConfig.TemplateLeft",
	"beego.TemplateRight", "beego.BConfig.WebConfig.TemplateRight",
	"beego.SessionOn", "beego.BConfig.WebConfig.Session.SessionOn",
	"beego.SessionProvider", "beego.BConfig.WebConfig.Session.SessionProvider",
	"beego.SessionName", "beego.BConfig.WebConfig.Session.SessionName",
	"beego.SessionGCMaxLifetime", "beego.BConfig.WebConfig.Session.SessionGCMaxLifetime",
	"beego.SessionSavePath", "beego.BConfig.WebConfig.Session.SessionProviderConfig",
	"beego.SessionCookieLifeTime", "beego.BConfig.WebConfig.Session.SessionCookieLifeTime",
	"beego.SessionAutoSetCookie", "beego.BConfig.WebConfig.Session.SessionAutoSetCookie",
	"beego.SessionDomain", "beego.BConfig.WebConfig.Session.SessionDomain",
	"Ctx.Input.CopyBody(", "Ctx.Input.CopyBody(beego.BConfig.MaxMemory",
	".UrlFor(", ".URLFor(",
	".ServeJson(", ".ServeJSON(",
	".ServeXml(", ".ServeXML(",
	".XsrfToken(", ".XSRFToken(",
	".CheckXsrfCookie(", ".CheckXSRFCookie(",
	".XsrfFormHtml(", ".XSRFFormHTML(",
	"beego.UrlFor(", "beego.URLFor(",
	"beego.GlobalDocApi", "beego.GlobalDocAPI",
	"beego.Errorhandler", "beego.ErrorHandler",
	"Output.Jsonp(", "Output.JSONP",
	"Output.Json(", "Output.JSON",
	"Output.Xml(", "Output.XML",
	"Input.Uri()", "Input.URI()",
	"Input.Url()", "Input.URL()",
	"Input.AcceptsHtml()", "Input.AcceptsHTML()",
	"Input.AcceptsXml()", "Input.AcceptsXML()",
	"Input.AcceptsJson()", "Input.AcceptsJSON()",
	"Ctx.XsrfToken()", "Ctx.XSRFToken()",
	"Ctx.CheckXsrfCookie()", "Ctx.CheckXSRFCookie()",
	"session.SessionStore", "session.Store",
	".TplNames", ".TplName",
	"swagger.ApiRef", "swagger.APIRef",
	"swagger.ApiDeclaration", "swagger.APIDeclaration",
	"swagger.Api", "swagger.API",
	"swagger.ApiRef", "swagger.APIRef",
	"toolbox.UrlMap", "toolbox.URLMap",
}

func fixFile(file string) error {
	rp := strings.NewReplacer(rules...)
	content, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	fixed := rp.Replace(string(content))
	pareg := regexp.MustCompile(`(Ctx.Input.Params\[")(.*)("])`)
	fixed = pareg.ReplaceAllString(fixed, "Ctx.Input.Param(\"$2\")")
	pareg = regexp.MustCompile(`Ctx.Input.Params\)`)
	fixed = pareg.ReplaceAllString(fixed, "Ctx.Input.Params())")
	err = os.Truncate(file, 0)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(file, []byte(fixed), 0666)
}
<commit_msg>fix the params rules<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var cmdFix = &Command{
	UsageLine: "fix",
	Short:     "fix the beego application to compatibel with beego 1.6",
	Long: `
As from beego1.6, there's some incompatible code with the old version.

bee fix help to upgrade the application to beego 1.6
`,
}

func init() {
	cmdFix.Run = runFix
}

func runFix(cmd *Command, args []string) int {
	dir, err := os.Getwd()
	if err != nil {
		ColorLog("GetCurrent Path:%s\n", err)
	}
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			if strings.HasPrefix(info.Name(), ".") {
				return filepath.SkipDir
			}
			return nil
		}
		if err != nil {
			return err
		}
		ColorLog("%s\n", path)
		err = fixFile(path)
		if err != nil {
			ColorLog("fixFile:%s\n", err)
		}
		return err
	})
	return 0
}

var rules = []string{
	"beego.AppName", "beego.BConfig.AppName",
	"beego.RunMode", "beego.BConfig.RunMode",
	"beego.RecoverPanic", "beego.BConfig.RecoverPanic",
	"beego.RouterCaseSensitive", "beego.BConfig.RouterCaseSensitive",
	"beego.BeegoServerName", "beego.BConfig.ServerName",
	"beego.EnableGzip", "beego.BConfig.EnableGzip",
	"beego.ErrorsShow", "beego.BConfig.EnableErrorsShow",
	"beego.CopyRequestBody", "beego.BConfig.CopyRequestBody",
	"beego.MaxMemory", "beego.BConfig.MaxMemory",
	"beego.Graceful", "beego.BConfig.Listen.Graceful",
	"beego.HttpAddr", "beego.BConfig.Listen.HTTPAddr",
	"beego.HttpPort", "beego.BConfig.Listen.HTTPPort",
	"beego.ListenTCP4", "beego.BConfig.Listen.ListenTCP4",
	"beego.EnableHttpListen", "beego.BConfig.Listen.HTTPEnable",
	"beego.EnableHttpTLS", "beego.BConfig.Listen.HTTPSEnable",
	"beego.HttpsAddr", "beego.BConfig.Listen.HTTPSAddr",
	"beego.HttpsPort", "beego.BConfig.Listen.HTTPSPort",
	"beego.HttpCertFile", "beego.BConfig.Listen.HTTPSCertFile",
	"beego.HttpKeyFile", "beego.BConfig.Listen.HTTPSKeyFile",
	"beego.EnableAdmin", "beego.BConfig.Listen.AdminEnable",
	"beego.AdminHttpAddr", "beego.BConfig.Listen.AdminAddr",
	"beego.AdminHttpPort", "beego.BConfig.Listen.AdminPort",
	"beego.UseFcgi", "beego.BConfig.Listen.EnableFcgi",
	"beego.HttpServerTimeOut", "beego.BConfig.Listen.ServerTimeOut",
	"beego.AutoRender", "beego.BConfig.WebConfig.AutoRender",
	"beego.ViewsPath", "beego.BConfig.WebConfig.ViewsPath",
	"beego.DirectoryIndex", "beego.BConfig.WebConfig.DirectoryIndex",
	"beego.FlashName", "beego.BConfig.WebConfig.FlashName",
	"beego.FlashSeperator", "beego.BConfig.WebConfig.FlashSeperator",
	"beego.EnableDocs", "beego.BConfig.WebConfig.EnableDocs",
	"beego.XSRFKEY", "beego.BConfig.WebConfig.XSRFKEY",
	"beego.EnableXSRF", "beego.BConfig.WebConfig.EnableXSRF",
	"beego.XSRFExpire", "beego.BConfig.WebConfig.XSRFExpire",
	"beego.TemplateLeft", "beego.BConfig.WebConfig.TemplateLeft",
	"beego.TemplateRight", "beego.BConfig.WebConfig.TemplateRight",
	"beego.SessionOn", "beego.BConfig.WebConfig.Session.SessionOn",
	"beego.SessionProvider", "beego.BConfig.WebConfig.Session.SessionProvider",
	"beego.SessionName", "beego.BConfig.WebConfig.Session.SessionName",
	"beego.SessionGCMaxLifetime", "beego.BConfig.WebConfig.Session.SessionGCMaxLifetime",
	"beego.SessionSavePath", "beego.BConfig.WebConfig.Session.SessionProviderConfig",
	"beego.SessionCookieLifeTime", "beego.BConfig.WebConfig.Session.SessionCookieLifeTime",
	"beego.SessionAutoSetCookie", "beego.BConfig.WebConfig.Session.SessionAutoSetCookie",
	"beego.SessionDomain", "beego.BConfig.WebConfig.Session.SessionDomain",
	"Ctx.Input.CopyBody(", "Ctx.Input.CopyBody(beego.BConfig.MaxMemory",
	".UrlFor(", ".URLFor(",
	".ServeJson(", ".ServeJSON(",
	".ServeXml(", ".ServeXML(",
	".XsrfToken(", ".XSRFToken(",
	".CheckXsrfCookie(", ".CheckXSRFCookie(",
	".XsrfFormHtml(", ".XSRFFormHTML(",
	"beego.UrlFor(", "beego.URLFor(",
	"beego.GlobalDocApi", "beego.GlobalDocAPI",
	"beego.Errorhandler", "beego.ErrorHandler",
	"Output.Jsonp(", "Output.JSONP",
	"Output.Json(", "Output.JSON",
	"Output.Xml(", "Output.XML",
	"Input.Uri()", "Input.URI()",
	"Input.Url()", "Input.URL()",
	"Input.AcceptsHtml()", "Input.AcceptsHTML()",
	"Input.AcceptsXml()", "Input.AcceptsXML()",
	"Input.AcceptsJson()", "Input.AcceptsJSON()",
	"Ctx.XsrfToken()", "Ctx.XSRFToken()",
	"Ctx.CheckXsrfCookie()", "Ctx.CheckXSRFCookie()",
	"session.SessionStore", "session.Store",
	".TplNames", ".TplName",
	"swagger.ApiRef", "swagger.APIRef",
	"swagger.ApiDeclaration", "swagger.APIDeclaration",
	"swagger.Api", "swagger.API",
	"swagger.ApiRef", "swagger.APIRef",
	"toolbox.UrlMap", "toolbox.URLMap",
}

func fixFile(file string) error {
	rp := strings.NewReplacer(rules...)
	content, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	fixed := rp.Replace(string(content))
	pareg := regexp.MustCompile(`(Input.Params\[")(.*)("])`)
	fixed = pareg.ReplaceAllString(fixed, "Input.Param(\"$2\")")
	pareg = regexp.MustCompile(`Input.Params\)`)
	fixed = pareg.ReplaceAllString(fixed, "Input.Params())")
	err = os.Truncate(file, 0)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(file, []byte(fixed), 0666)
}
<|endoftext|>