<commit_before>package main

import (
	"github.com/madcowfred/simplenntp"
	"os"
	"path/filepath"
	"sync"
	"time"
)

type FileData struct {
	path string
	size int64
}

type Totals struct {
	start time.Time
	end   time.Time
	bytes int64
}

func Spawner(filenames []string) {
	var wg sync.WaitGroup
	files := make([]FileData, 0)

	log.Debug("Spawner started")

	// Walk any directories and collect files
	for _, filename := range filenames {
		err := filepath.Walk(filename, func(path string, fi os.FileInfo, err error) error {
			if !fi.IsDir() && fi.Size() > 0 {
				files = append(files, FileData{path: path, size: fi.Size()})
			}
			return err
		})
		if err != nil {
			log.Fatalf("Spawner walk error: %s", err)
		}
	}
	for _, fd := range files {
		log.Debug("%+v", fd)
	}

	for name, server := range Config.Server {
		log.Info("[%s] Starting %d connections", name, server.Connections)

		// Make a channel to stuff Articles into
		achan := make(chan *Article, server.Connections)

		// Make a channel to stuff Totals into
		tchan := make(chan *Totals, server.Connections)

		// Start a goroutine to generate articles
		wg.Add(1)
		go func(c chan *Article, files []FileData) {
			defer wg.Done()

			log.Debug("[%s] Article generator started", name)

			mc := NewMmapCache()

			for filenum, fd := range files {
				log.Debug("fd: %+v", fd)
				// Open and mmap the file
				md, err := mc.MapFile(fd.path, len(Config.Server))
				if err != nil {
					log.Fatalf("MapFile error: %s", err)
				}

				// Work out how many parts we need
				parts := fd.size / Config.Global.ArticleSize
				rem := fd.size % Config.Global.ArticleSize
				if rem > 0 {
					parts++
				}

				// Build some articles
				for partnum := int64(0); partnum < parts; partnum++ {
					start := partnum * Config.Global.ArticleSize
					end := min((partnum+1)*Config.Global.ArticleSize, fd.size)

					ad := &ArticleData{
						PartNum:   partnum + 1,
						PartTotal: parts,
						PartSize:  end - start,
						PartBegin: start,
						PartEnd:   end,
						FileNum:   filenum + 1,
						FileTotal: len(files),
						FileSize:  fd.size,
						FileName:  filepath.Base(fd.path),
					}

					var subject string
					if *dirSubjectFlag {
						subject = filepath.Base(filepath.Dir(fd.path))
					} else {
						subject = *subjectFlag
					}

					a := NewArticle(md.data[start:end], ad, subject)
					c <- a

					//log.Debug("%s %d = %d -> %d", fd.path, i, start, end)
				}

				if md.Decrement() {
					err = mc.CloseFile(fd.path)
					if err != nil {
						log.Fatalf("CloseFile error: %s", err)
					}
					log.Debug("[%s] Closed file %s", name, fd.path)
				}
			}

			close(c)
		}(achan, files)

		// Start a goroutine for each individual connection
		for i := 0; i < server.Connections; i++ {
			connID := i + 1

			// Increment the WaitGroup counter
			wg.Add(1)
			go func(achan chan *Article, tchan chan *Totals) {
				// Decrement the counter when the goroutine completes
				defer wg.Done()

				// Connect
				log.Debug("[%s:%02d] Connecting...", name, connID)
				conn, err := simplenntp.Dial(server.Address, server.Port, server.TLS)
				if err != nil {
					log.Critical("[%s] Error while connecting: %s", name, err)
				}
				log.Debug("[%s:%02d] Connected", name, connID)

				// Authenticate if required
				if len(server.Username) > 0 {
					log.Debug("[%s:%02d] Authenticating...", name, connID)
					err := conn.Authenticate(server.Username, server.Password)
					if err != nil {
						log.Fatalf("[%s:%02d] Error while authenticating: %s", name, connID, err)
					}
					log.Debug("[%s:%02d] Authenticated", name, connID)
				}

				t := Totals{start: time.Now()}

				// Begin consuming
				for article := range achan {
					log.Debug("[%s:%02d] Article: %p", name, connID, article)
					err := conn.Post(article.Body)
					if err != nil {
						log.Warning("[%s:%02d] Post error: %s", name, connID, err)
					}

					t.bytes += int64(len(article.Body))
				}

				t.end = time.Now()
				tchan <- &t

				dur := t.end.Sub(t.start)
				speed := float64(t.bytes) / dur.Seconds() / 1024
				log.Info("[%s:%02d] Posted %d bytes in %s at %.1fKB/s", name, connID, t.bytes, dur.String(), speed)

				// Close the connection
				log.Debug("[%s:%02d] Closing connection", name, connID)
				err = conn.Quit()
				if err != nil {
					log.Warning("[%s:%02d] Error while closing connection: %s", name, connID, err)
				}
			}(achan, tchan)
		}
	}

	// Wait for all connections to complete
	wg.Wait()
}

func min(a, b int64) int64 {
	if a < b {
		return a
	} else {
		return b
	}
}
<commit_msg>Handle connection errors by quitting instead of exploding<commit_after>package main

import (
	"github.com/madcowfred/simplenntp"
	"os"
	"path/filepath"
	"sync"
	"time"
)

type FileData struct {
	path string
	size int64
}

type Totals struct {
	start time.Time
	end   time.Time
	bytes int64
}

func Spawner(filenames []string) {
	var wg sync.WaitGroup
	files := make([]FileData, 0)

	log.Debug("Spawner started")

	// Walk any directories and collect files
	for _, filename := range filenames {
		err := filepath.Walk(filename, func(path string, fi os.FileInfo, err error) error {
			if !fi.IsDir() && fi.Size() > 0 {
				files = append(files, FileData{path: path, size: fi.Size()})
			}
			return err
		})
		if err != nil {
			log.Fatalf("Spawner walk error: %s", err)
		}
	}
	for _, fd := range files {
		log.Debug("%+v", fd)
	}

	for name, server := range Config.Server {
		log.Info("[%s] Starting %d connections", name, server.Connections)

		// Make a channel to stuff Articles into
		achan := make(chan *Article, server.Connections)

		// Make a channel to stuff Totals into
		tchan := make(chan *Totals, server.Connections)

		// Start a goroutine to generate articles
		wg.Add(1)
		go func(c chan *Article, files []FileData) {
			defer wg.Done()

			log.Debug("[%s] Article generator started", name)

			mc := NewMmapCache()

			for filenum, fd := range files {
				log.Debug("fd: %+v", fd)
				// Open and mmap the file
				md, err := mc.MapFile(fd.path, len(Config.Server))
				if err != nil {
					log.Fatalf("MapFile error: %s", err)
				}

				// Work out how many parts we need
				parts := fd.size / Config.Global.ArticleSize
				rem := fd.size % Config.Global.ArticleSize
				if rem > 0 {
					parts++
				}

				// Build some articles
				for partnum := int64(0); partnum < parts; partnum++ {
					start := partnum * Config.Global.ArticleSize
					end := min((partnum+1)*Config.Global.ArticleSize, fd.size)

					ad := &ArticleData{
						PartNum:   partnum + 1,
						PartTotal: parts,
						PartSize:  end - start,
						PartBegin: start,
						PartEnd:   end,
						FileNum:   filenum + 1,
						FileTotal: len(files),
						FileSize:  fd.size,
						FileName:  filepath.Base(fd.path),
					}

					var subject string
					if *dirSubjectFlag {
						subject = filepath.Base(filepath.Dir(fd.path))
					} else {
						subject = *subjectFlag
					}

					a := NewArticle(md.data[start:end], ad, subject)
					c <- a

					//log.Debug("%s %d = %d -> %d", fd.path, i, start, end)
				}

				if md.Decrement() {
					err = mc.CloseFile(fd.path)
					if err != nil {
						log.Fatalf("CloseFile error: %s", err)
					}
					log.Debug("[%s] Closed file %s", name, fd.path)
				}
			}

			close(c)
		}(achan, files)

		// Start a goroutine for each individual connection
		for i := 0; i < server.Connections; i++ {
			connID := i + 1

			// Increment the WaitGroup counter
			wg.Add(1)
			go func(achan chan *Article, tchan chan *Totals) {
				// Decrement the counter when the goroutine completes
				defer wg.Done()

				// Connect
				log.Debug("[%s:%02d] Connecting...", name, connID)
				conn, err := simplenntp.Dial(server.Address, server.Port, server.TLS)
				if err != nil {
					log.Fatalf("[%s] Error while connecting: %s", name, err)
				}
				log.Debug("[%s:%02d] Connected", name, connID)

				// Authenticate if required
				if len(server.Username) > 0 {
					log.Debug("[%s:%02d] Authenticating...", name, connID)
					err := conn.Authenticate(server.Username, server.Password)
					if err != nil {
						log.Fatalf("[%s:%02d] Error while authenticating: %s", name, connID, err)
					}
					log.Debug("[%s:%02d] Authenticated", name, connID)
				}

				t := Totals{start: time.Now()}

				// Begin consuming
				for article := range achan {
					log.Debug("[%s:%02d] Article: %p", name, connID, article)
					err := conn.Post(article.Body)
					if err != nil {
						log.Warning("[%s:%02d] Post error: %s", name, connID, err)
					}

					t.bytes += int64(len(article.Body))
				}

				t.end = time.Now()
				tchan <- &t

				dur := t.end.Sub(t.start)
				speed := float64(t.bytes) / dur.Seconds() / 1024
				log.Info("[%s:%02d] Posted %d bytes in %s at %.1fKB/s", name, connID, t.bytes, dur.String(), speed)

				// Close the connection
				log.Debug("[%s:%02d] Closing connection", name, connID)
				err = conn.Quit()
				if err != nil {
					log.Warning("[%s:%02d] Error while closing connection: %s", name, connID, err)
				}
			}(achan, tchan)
		}
	}

	// Wait for all connections to complete
	wg.Wait()
}

func min(a, b int64) int64 {
	if a < b {
		return a
	} else {
		return b
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strconv"
	"strings"

	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/container"
	"github.com/docker/engine-api/types/registry"
)

var typeCustomizations = map[typeCustomizationKey]CSType{
	{reflect.TypeOf(container.RestartPolicy{}), "Name"}: {"", "RestartPolicyKind", false},
	{reflect.TypeOf(types.ContainerChange{}), "Kind"}:   {"", "FileSystemChangeKind", false},
	{reflect.TypeOf(types.Image{}), "Created"}:          {"System", "DateTime", false},
}

type typeCustomizationKey struct {
	Type         reflect.Type
	PropertyName string
}

type typeDef struct {
	Type   reflect.Type
	CsName string
}

var dockerTypesToReflect = []typeDef{

	// POST /auth
	{reflect.TypeOf(AuthConfigParameters{}), "AuthConfigParameters"},
	{reflect.TypeOf(types.AuthResponse{}), "AuthResponse"},

	// POST /build
	{reflect.TypeOf(ImageBuildParameters{}), "ImageBuildParameters"},
	{reflect.TypeOf(types.ImageBuildResponse{}), "ImageBuildResponse"},

	// POST /commit
	{reflect.TypeOf(ContainerCommitParamters{}), "CommitContainerChangesParameters"},
	{reflect.TypeOf(types.ContainerCommitResponse{}), "CommitContainerChangesResponse"},

	// POST /containers/create
	{reflect.TypeOf(ContainerCreateParameters{}), "CreateContainerParameters"},
	{reflect.TypeOf(types.ContainerCreateResponse{}), "CreateContainerResponse"},

	// GET /containers/json
	{reflect.TypeOf(ContainerListParameters{}), "ContainersListParameters"},
	{reflect.TypeOf(types.Container{}), "ContainerListResponse"},

	// DELETE /containers/(id)
	{reflect.TypeOf(ContainerRemoveParameters{}), "ContainerRemoveParameters"},

	// GET /containers/(id)/archive
	{reflect.TypeOf(ContainerPathStatParameters{}), "ContainerPathStatParameters"},
	{reflect.TypeOf(types.ContainerPathStat{}), "ContainerPathStatResponse"},

	// POST /containers/(id)/attach
	{reflect.TypeOf(ContainerAttachParameters{}), "ContainerAttachParameters"},

	// POST /containers/(id)/attach/ws

	// GET /containers/(id)/changes
	{reflect.TypeOf(types.ContainerChange{}), "ContainerFileSystemChangeResponse"},

	// OBSOLETE - POST /containers/(id)/copy

	// GET /containers/(id)/export
	// TODO: TAR Stream

	// POST /containers/(id)/exec
	{reflect.TypeOf(ContainerExecCreateParameters{}), "ContainerExecCreateParameters"},
	{reflect.TypeOf(types.ContainerExecCreateResponse{}), "ContainerExecCreateResponse"},

	// GET /containers/(id)/json
	{reflect.TypeOf(ContainerInspectParameters{}), "ContainerInspectParameters"},
	{reflect.TypeOf(types.ContainerJSON{}), "ContainerInspectResponse"},

	// POST /containers/(id)/kill
	{reflect.TypeOf(ContainerKillParameters{}), "ContainerKillParameters"},

	// GET /containers/(id)/logs
	{reflect.TypeOf(ContainerLogsParameters{}), "ContainerLogsParameters"},

	// POST /containers/(id)/pause

	// POST /containers/(id)/rename
	{reflect.TypeOf(ContainerRenameParameters{}), "ContainerRenameParameters"},

	// POST /containers/(id)/resize
	{reflect.TypeOf(ContainerResizeParameters{}), "ContainerResizeParameters"},

	// POST /containers/(id)/restart
	{reflect.TypeOf(ContainerRestartParameters{}), "ConatinerRestartParameters"},

	// POST /containers/(id)/start
	{reflect.TypeOf(ContainerStartParameters{}), "ContainerStartParameters"},

	// POST /containers/(id)/stop
	{reflect.TypeOf(ContainerStopParameters{}), "ContainerStopParameters"},

	// GET /containers/(id)/stats
	{reflect.TypeOf(ContainerStatsParameters{}), "ContainerStatsParameters"},
	{reflect.TypeOf(types.StatsJSON{}), "ContainerStatsResponse"},

	// GET /containers/(id)/top
	{reflect.TypeOf(ContainerListProcessesParameters{}), "ContainerListProcessesParameters"},
	{reflect.TypeOf(types.ContainerProcessList{}), "ContainerProcessesResponse"},

	// POST /containers/(id)/unpause

	// POST /containers/(id)/update
	{reflect.TypeOf(ContainerUpdateParameters{}), "ContainerUpdateParameters"},
	{reflect.TypeOf(types.ContainerUpdateResponse{}), "ContainerUpdateResponse"},

	// POST /containers/(id)/wait
	{reflect.TypeOf(types.ContainerWaitResponse{}), "ContainerWaitResponse"},

	// GET /events
	{reflect.TypeOf(ContainerEventsParameters{}), "ContainerEventsParameters"},

	// POST /images/create
	{reflect.TypeOf(ImageCreateParameters{}), "ImagesCreateParameters"},
	{reflect.TypeOf(ImageImportParameters{}), "ImagesImportParameters"},
	{reflect.TypeOf(ImagePullParameters{}), "ImagesPullParameters"},

	// GET /images/get
	// TODO: stream

	// GET /images/json
	{reflect.TypeOf(ImageListParameters{}), "ImagesListParameters"},
	{reflect.TypeOf(types.Image{}), "ImagesListResponse"},

	// POST /images/load
	// TODO: headers: application/x-tar body.
	{reflect.TypeOf(ImageLoadParameters{}), "ImageLoadParameters"},
	{reflect.TypeOf(types.ImageLoadResponse{}), "ImagesLoadResponse"},

	// GET /images/search
	{reflect.TypeOf(ImageSearchParameters{}), "ImagesSearchParameters"},
	{reflect.TypeOf(registry.SearchResult{}), "ImageSearchResponse"},

	// DELETE /images/(id)
	{reflect.TypeOf(ImageDeleteParameters{}), "ImageDeleteParameters"},
	{reflect.TypeOf(types.ImageDelete{}), "ImageDeleteResponse"},

	// GET /images/(id)/history
	{reflect.TypeOf(types.ImageHistory{}), "ImageHistoryResponse"},

	// GET /images/(id)/json
	{reflect.TypeOf(ImageInspectParameters{}), "ImageInspectParameters"},
	{reflect.TypeOf(types.ImageInspect{}), "ImageInspectResponse"},

	// POST /images/(id)/push
	{reflect.TypeOf(ImagePushParameters{}), "ImagePushParameters"},

	// POST /images/(id)/tag
	{reflect.TypeOf(ImageTagParameters{}), "ImageTagParameters"},

	// GET /info
	{reflect.TypeOf(types.Info{}), "SystemInfoResponse"},

	// GET /networks
	{reflect.TypeOf(NetworkListParameters{}), "NetworksListParameters"},
	{reflect.TypeOf(types.NetworkResource{}), "NetworkListResponse"},

	// POST /networks/create
	{reflect.TypeOf(types.NetworkCreateRequest{}), "NetworksCreateParameters"},
	{reflect.TypeOf(types.NetworkCreateResponse{}), "NetworksCreateResponse"},

	// GET /networks/(id)
	{reflect.TypeOf(types.NetworkResource{}), "NetworkResponse"},

	// DELETE /networks/(id)

	// POST /networks/(id)/connect
	{reflect.TypeOf(types.NetworkConnect{}), "NetworkConnectParameters"},

	// POST /networks/(id)/disconnect
	{reflect.TypeOf(types.NetworkDisconnect{}), "NetworkDisconnectParameters"},

	// GET /version
	{reflect.TypeOf(types.Version{}), "VersionResponse"},

	// GET /volumes
	{reflect.TypeOf(VolumesListParameters{}), "VolumesListParameters"},
	{reflect.TypeOf(VolumesListResponse{}), "VolumesListResponse"},

	// POST /volumes/create
	{reflect.TypeOf(types.VolumeCreateRequest{}), "VolumesCreateParameters"},

	// GET /volumes/(id)
	{reflect.TypeOf(VolumeResponse{}), "VolumeResponse"},

	// DELETE /volumes/(id)
}

func csType(t reflect.Type, opt bool) CSType {
	def, ok := CSCustomTypeMap[t]
	if !ok {
		def, ok = CSInboxTypesMap[t.Kind()]
	}

	if ok {
		return def
	}

	switch t.Kind() {
	case reflect.Array:
		return CSType{"", fmt.Sprintf("%s[]", csType(t.Elem(), false).Name), false}
	case reflect.Slice:
		return CSType{"System.Collections.Generic", fmt.Sprintf("IList<%s>", csType(t.Elem(), false).Name), false}
	case reflect.Map:
		if t.Elem() == EmptyStruct {
			return CSType{"System.Collections.Generic", fmt.Sprintf("IDictionary<%s, object>", csType(t.Key(), false).Name), false}
		}

		return CSType{"System.Collections.Generic", fmt.Sprintf("IDictionary<%s, %s>", csType(t.Key(), false).Name, csType(t.Elem(), false).Name), false}
	case reflect.Ptr:
		return csType(t.Elem(), true)
	case reflect.Struct:
		return CSType{"", t.Name(), false}
	case reflect.Interface:
		return CSType{"", "object", false}
	default:
		panic(fmt.Errorf("cannot convert type %s", t))
	}
}

func ultimateType(t reflect.Type) reflect.Type {
	for {
		switch t.Kind() {
		case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
			t = t.Elem()
		default:
			return t
		}
	}
}

func reflectTypeMembers(t reflect.Type, m *CSModelType, reflectedTypes map[string]*CSModelType) {
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)

		if f.Type.Kind() == reflect.Func {
			continue
		}

		if f.Type.Kind() == reflect.Struct && f.Type.Name() == "" {
			// TODO: Inline struct definitions. Probably need to write an inline class named the property name?
			continue
		}

		// If the type is anonymous we need to inline its values to this model.
		if f.Anonymous {
			clen := len(m.Constructors)
			if clen == 0 {
				// We need to add a default constructor and a custom one since its the first time.
				m.Constructors = append(m.Constructors, CSConstructor{}, CSConstructor{})
			}

			ut := ultimateType(f.Type)
			reflectType(ut.Name(), ut, reflectedTypes)
			newType := reflectedTypes[ut.Name()]
			m.Constructors[1].Parameters = append(m.Constructors[1].Parameters, CSParameter{newType, f.Name})

			// Now we need to add in all of the inherited types parameters
			for _, p := range newType.Properties {
				m.Properties = append(m.Properties, p)
			}
		} else {
			// If we are referencing a struct that isnt inline or anonymous we need to update it too.
			if ut := ultimateType(f.Type); ut.Kind() == reflect.Struct {
				if _, ok := CSInboxTypesMap[f.Type.Kind()]; !ok {
					if _, ok := CSCustomTypeMap[f.Type]; !ok {
						reflectType(ut.Name(), ut, reflectedTypes)
					}
				}
			}

			// If the json tag says to omit we skip generation.
			jsonTag := strings.Split(f.Tag.Get("json"), ",")
			if jsonTag[0] == "-" {
				continue
			}

			// Create our new property.
			csProp := CSProperty{Name: f.Name, Type: csType(f.Type, false)}

			jsonName := f.Name
			if jsonTag[0] != "" {
				jsonName = jsonTag[0]
			}

			if ft, ok := typeCustomizations[typeCustomizationKey{t, f.Name}]; ok {
				// We have a custom modification. Change the type.
				csProp.Type = ft
			}

			if restTag, err := RestTagFromString(f.Tag.Get("rest")); err == nil && restTag.In != Body {
				if restTag.Name == "" {
					restTag.Name = strings.ToLower(f.Name)
				}

				a := CSAttribute{Type: CSType{"", "QueryStringParameter", false}}
				a.Arguments = append(
					a.Arguments,
					CSArgument{
						restTag.Name,
						CSInboxTypesMap[reflect.String]},
					CSArgument{strconv.FormatBool(restTag.Required),
						CSInboxTypesMap[reflect.Bool]})

				switch f.Type.Kind() {
				case reflect.Bool:
					a.Arguments = append(a.Arguments, CSArgument{Value: "typeof(BoolQueryStringConverter)"})
				}

				csProp.IsOpt = !restTag.Required
				csProp.Attributes = append(csProp.Attributes, a)
			} else {
				a := CSAttribute{Type: CSType{"", "DataMember", false}}
				a.NamedArguments = append(a.NamedArguments, CSNamedArgument{"Name", CSArgument{jsonName, CSInboxTypesMap[reflect.String]}})
				a.NamedArguments = append(a.NamedArguments, CSNamedArgument{"EmitDefaultValue", CSArgument{strconv.FormatBool(false), CSInboxTypesMap[reflect.Bool]}})
				csProp.Attributes = append(csProp.Attributes, a)
			}

			// Lastly assign the property to our type.
			m.Properties = append(m.Properties, csProp)
		}
	}
}

func reflectType(name string, t reflect.Type, reflectedTypes map[string]*CSModelType) {
	if _, ok := reflectedTypes[name]; ok {
		return
	} else if name == "" {
		return
	}

	m := NewModel(name, fmt.Sprintf("%s", t))
	reflectedTypes[name] = m

	reflectTypeMembers(t, m, reflectedTypes)
}

func reflectDockerType(t typeDef, reflectedTypes map[string]*CSModelType) {
	reflectType(t.CsName, t.Type, reflectedTypes)
}

func reflectDockerTypes() map[string]*CSModelType {
	reflectedTypes := make(map[string]*CSModelType)

	for _, t := range dockerTypesToReflect {
		reflectDockerType(t, reflectedTypes)
	}

	return reflectedTypes
}

func main() {
	argsLen := len(os.Args)
	sourcePath := ""
	if argsLen >= 2 {
		sourcePath = os.Args[1]
		fmt.Println(sourcePath)
		if _, err := os.Stat(sourcePath); err != nil {
			if os.IsNotExist(err) {
				panic(sourcePath + ", is not a valid directory.")
			}
		}
	} else {
		sourcePath, _ = os.Getwd()
	}

	// Delete any previously generated files.
	if files, err := ioutil.ReadDir(sourcePath); err != nil {
		panic(err)
	} else {
		for _, file := range files {
			if strings.HasSuffix(file.Name(), ".Generated.cs") {
				if err := os.Remove(path.Join(sourcePath, file.Name())); err != nil {
					panic(err)
				}
			}
		}
	}

	csTypes := reflectDockerTypes()

	for k, v := range csTypes {
		f, err := ioutil.TempFile(sourcePath, "ser")
		if err != nil {
			panic(err)
		}

		defer f.Close()

		b := bufio.NewWriter(f)
		v.Write(b)
		err = b.Flush()
		if err != nil {
			os.Remove(f.Name())
			panic(err)
		}

		f.Close()
		os.Rename(f.Name(), path.Join(sourcePath, k+".Generated.cs"))
	}
}
<commit_msg>Fixes an issue where in order to handle maps/enumerables better we need to handle the query string serialization in a custom way.<commit_after>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strconv"
	"strings"

	"github.com/docker/engine-api/types"
	"github.com/docker/engine-api/types/container"
	"github.com/docker/engine-api/types/registry"
)

var typeCustomizations = map[typeCustomizationKey]CSType{
	{reflect.TypeOf(container.RestartPolicy{}), "Name"}: {"", "RestartPolicyKind", false},
	{reflect.TypeOf(types.ContainerChange{}), "Kind"}:   {"", "FileSystemChangeKind", false},
	{reflect.TypeOf(types.Image{}), "Created"}:          {"System", "DateTime", false},
}

type typeCustomizationKey struct {
	Type         reflect.Type
	PropertyName string
}

type typeDef struct {
	Type   reflect.Type
	CsName string
}

var dockerTypesToReflect = []typeDef{

	// POST /auth
	{reflect.TypeOf(AuthConfigParameters{}), "AuthConfigParameters"},
	{reflect.TypeOf(types.AuthResponse{}), "AuthResponse"},

	// POST /build
	{reflect.TypeOf(ImageBuildParameters{}), "ImageBuildParameters"},
	{reflect.TypeOf(types.ImageBuildResponse{}), "ImageBuildResponse"},

	// POST /commit
	{reflect.TypeOf(ContainerCommitParamters{}), "CommitContainerChangesParameters"},
	{reflect.TypeOf(types.ContainerCommitResponse{}), "CommitContainerChangesResponse"},

	// POST /containers/create
	{reflect.TypeOf(ContainerCreateParameters{}), "CreateContainerParameters"},
	{reflect.TypeOf(types.ContainerCreateResponse{}), "CreateContainerResponse"},

	// GET /containers/json
	{reflect.TypeOf(ContainerListParameters{}), "ContainersListParameters"},
	{reflect.TypeOf(types.Container{}), "ContainerListResponse"},

	// DELETE /containers/(id)
	{reflect.TypeOf(ContainerRemoveParameters{}), "ContainerRemoveParameters"},

	// GET /containers/(id)/archive
	{reflect.TypeOf(ContainerPathStatParameters{}), "ContainerPathStatParameters"},
	{reflect.TypeOf(types.ContainerPathStat{}), "ContainerPathStatResponse"},

	// POST /containers/(id)/attach
	{reflect.TypeOf(ContainerAttachParameters{}), "ContainerAttachParameters"},

	// POST /containers/(id)/attach/ws

	// GET /containers/(id)/changes
	{reflect.TypeOf(types.ContainerChange{}), "ContainerFileSystemChangeResponse"},

	// OBSOLETE - POST /containers/(id)/copy

	// GET /containers/(id)/export
	// TODO: TAR Stream

	// POST /containers/(id)/exec
	{reflect.TypeOf(ContainerExecCreateParameters{}), "ContainerExecCreateParameters"},
	{reflect.TypeOf(types.ContainerExecCreateResponse{}), "ContainerExecCreateResponse"},

	// GET /containers/(id)/json
	{reflect.TypeOf(ContainerInspectParameters{}), "ContainerInspectParameters"},
	{reflect.TypeOf(types.ContainerJSON{}), "ContainerInspectResponse"},

	// POST /containers/(id)/kill
	{reflect.TypeOf(ContainerKillParameters{}), "ContainerKillParameters"},

	// GET /containers/(id)/logs
	{reflect.TypeOf(ContainerLogsParameters{}), "ContainerLogsParameters"},

	// POST /containers/(id)/pause

	// POST /containers/(id)/rename
	{reflect.TypeOf(ContainerRenameParameters{}), "ContainerRenameParameters"},

	// POST /containers/(id)/resize
	{reflect.TypeOf(ContainerResizeParameters{}), "ContainerResizeParameters"},

	// POST /containers/(id)/restart
	{reflect.TypeOf(ContainerRestartParameters{}), "ConatinerRestartParameters"},

	// POST /containers/(id)/start
	{reflect.TypeOf(ContainerStartParameters{}), "ContainerStartParameters"},

	// POST /containers/(id)/stop
	{reflect.TypeOf(ContainerStopParameters{}), "ContainerStopParameters"},

	// GET /containers/(id)/stats
	{reflect.TypeOf(ContainerStatsParameters{}), "ContainerStatsParameters"},
	{reflect.TypeOf(types.StatsJSON{}), "ContainerStatsResponse"},

	// GET /containers/(id)/top
	{reflect.TypeOf(ContainerListProcessesParameters{}), "ContainerListProcessesParameters"},
	{reflect.TypeOf(types.ContainerProcessList{}), "ContainerProcessesResponse"},

	// POST /containers/(id)/unpause

	// POST /containers/(id)/update
	{reflect.TypeOf(ContainerUpdateParameters{}), "ContainerUpdateParameters"},
	{reflect.TypeOf(types.ContainerUpdateResponse{}), "ContainerUpdateResponse"},

	// POST /containers/(id)/wait
	{reflect.TypeOf(types.ContainerWaitResponse{}), "ContainerWaitResponse"},

	// GET /events
	{reflect.TypeOf(ContainerEventsParameters{}), "ContainerEventsParameters"},

	// POST /images/create
	{reflect.TypeOf(ImageCreateParameters{}), "ImagesCreateParameters"},
	{reflect.TypeOf(ImageImportParameters{}), "ImagesImportParameters"},
	{reflect.TypeOf(ImagePullParameters{}), "ImagesPullParameters"},

	// GET /images/get
	// TODO: stream

	// GET /images/json
	{reflect.TypeOf(ImageListParameters{}), "ImagesListParameters"},
	{reflect.TypeOf(types.Image{}), "ImagesListResponse"},

	// POST /images/load
	// TODO: headers: application/x-tar body.
	{reflect.TypeOf(ImageLoadParameters{}), "ImageLoadParameters"},
	{reflect.TypeOf(types.ImageLoadResponse{}), "ImagesLoadResponse"},

	// GET /images/search
	{reflect.TypeOf(ImageSearchParameters{}), "ImagesSearchParameters"},
	{reflect.TypeOf(registry.SearchResult{}), "ImageSearchResponse"},

	// DELETE /images/(id)
	{reflect.TypeOf(ImageDeleteParameters{}), "ImageDeleteParameters"},
	{reflect.TypeOf(types.ImageDelete{}), "ImageDeleteResponse"},

	// GET /images/(id)/history
	{reflect.TypeOf(types.ImageHistory{}), "ImageHistoryResponse"},

	// GET /images/(id)/json
	{reflect.TypeOf(ImageInspectParameters{}), "ImageInspectParameters"},
	{reflect.TypeOf(types.ImageInspect{}), "ImageInspectResponse"},

	// POST /images/(id)/push
	{reflect.TypeOf(ImagePushParameters{}), "ImagePushParameters"},

	// POST /images/(id)/tag
	{reflect.TypeOf(ImageTagParameters{}), "ImageTagParameters"},

	// GET /info
	{reflect.TypeOf(types.Info{}), "SystemInfoResponse"},

	// GET /networks
	{reflect.TypeOf(NetworkListParameters{}), "NetworksListParameters"},
	{reflect.TypeOf(types.NetworkResource{}), "NetworkListResponse"},

	// POST /networks/create
	{reflect.TypeOf(types.NetworkCreateRequest{}), "NetworksCreateParameters"},
	{reflect.TypeOf(types.NetworkCreateResponse{}), "NetworksCreateResponse"},

	// GET /networks/(id)
	{reflect.TypeOf(types.NetworkResource{}), "NetworkResponse"},

	// DELETE /networks/(id)

	// POST /networks/(id)/connect
	{reflect.TypeOf(types.NetworkConnect{}), "NetworkConnectParameters"},

	// POST /networks/(id)/disconnect
	{reflect.TypeOf(types.NetworkDisconnect{}), "NetworkDisconnectParameters"},

	// GET /version
	{reflect.TypeOf(types.Version{}), "VersionResponse"},

	// GET /volumes
	{reflect.TypeOf(VolumesListParameters{}), "VolumesListParameters"},
	{reflect.TypeOf(VolumesListResponse{}), "VolumesListResponse"},

	// POST /volumes/create
	{reflect.TypeOf(types.VolumeCreateRequest{}), "VolumesCreateParameters"},

	// GET /volumes/(id)
	{reflect.TypeOf(VolumeResponse{}), "VolumeResponse"},

	// DELETE /volumes/(id)
}

func csType(t reflect.Type, opt bool) CSType {
	def, ok := CSCustomTypeMap[t]
	if !ok {
		def, ok = CSInboxTypesMap[t.Kind()]
	}

	if ok {
		return def
	}

	switch t.Kind() {
	case reflect.Array:
		return CSType{"", fmt.Sprintf("%s[]", csType(t.Elem(), false).Name), false}
	case reflect.Slice:
		return CSType{"System.Collections.Generic", fmt.Sprintf("IList<%s>", csType(t.Elem(), false).Name), false}
	case reflect.Map:
		if t.Elem() == EmptyStruct {
			return CSType{"System.Collections.Generic", fmt.Sprintf("IDictionary<%s, object>", csType(t.Key(), false).Name), false}
		}

		return CSType{"System.Collections.Generic", fmt.Sprintf("IDictionary<%s, %s>", csType(t.Key(), false).Name, csType(t.Elem(), false).Name), false}
	case reflect.Ptr:
		return csType(t.Elem(), true)
	case reflect.Struct:
		return CSType{"", t.Name(), false}
	case reflect.Interface:
		return CSType{"", "object", false}
	default:
		panic(fmt.Errorf("cannot convert type %s", t))
	}
}

func ultimateType(t reflect.Type) reflect.Type {
	for {
		switch t.Kind() {
		case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
			t = t.Elem()
		default:
			return t
		}
	}
}

func reflectTypeMembers(t reflect.Type, m *CSModelType, reflectedTypes map[string]*CSModelType) {
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)

		if f.Type.Kind() == reflect.Func {
			continue
		}

		if f.Type.Kind() == reflect.Struct && f.Type.Name() == "" {
			// TODO: Inline struct definitions. Probably need to write an inline class named the property name?
			continue
		}

		// If the type is anonymous we need to inline its values to this model.
		if f.Anonymous {
			clen := len(m.Constructors)
			if clen == 0 {
				// We need to add a default constructor and a custom one since its the first time.
				m.Constructors = append(m.Constructors, CSConstructor{}, CSConstructor{})
			}

			ut := ultimateType(f.Type)
			reflectType(ut.Name(), ut, reflectedTypes)
			newType := reflectedTypes[ut.Name()]
			m.Constructors[1].Parameters = append(m.Constructors[1].Parameters, CSParameter{newType, f.Name})

			// Now we need to add in all of the inherited types parameters
			for _, p := range newType.Properties {
				m.Properties = append(m.Properties, p)
			}
		} else {
			// If we are referencing a struct that isnt inline or anonymous we need to update it too.
			if ut := ultimateType(f.Type); ut.Kind() == reflect.Struct {
				if _, ok := CSInboxTypesMap[f.Type.Kind()]; !ok {
					if _, ok := CSCustomTypeMap[f.Type]; !ok {
						reflectType(ut.Name(), ut, reflectedTypes)
					}
				}
			}

			// If the json tag says to omit we skip generation.
			jsonTag := strings.Split(f.Tag.Get("json"), ",")
			if jsonTag[0] == "-" {
				continue
			}

			// Create our new property.
			csProp := CSProperty{Name: f.Name, Type: csType(f.Type, false)}

			jsonName := f.Name
			if jsonTag[0] != "" {
				jsonName = jsonTag[0]
			}

			if ft, ok := typeCustomizations[typeCustomizationKey{t, f.Name}]; ok {
				// We have a custom modification. Change the type.
				csProp.Type = ft
			}

			if restTag, err := RestTagFromString(f.Tag.Get("rest")); err == nil && restTag.In != Body {
				if restTag.Name == "" {
					restTag.Name = strings.ToLower(f.Name)
				}

				a := CSAttribute{Type: CSType{"", "QueryStringParameter", false}}
				a.Arguments = append(
					a.Arguments,
					CSArgument{
						restTag.Name,
						CSInboxTypesMap[reflect.String]},
					CSArgument{strconv.FormatBool(restTag.Required),
						CSInboxTypesMap[reflect.Bool]})

				switch f.Type.Kind() {
				case reflect.Bool:
					a.Arguments = append(a.Arguments, CSArgument{Value: "typeof(BoolQueryStringConverter)"})
				case reflect.Slice, reflect.Array:
					a.Arguments = append(a.Arguments, CSArgument{Value: "typeof(EnumerableQueryStringConverter)"})
				case reflect.Map:
					a.Arguments = append(a.Arguments, CSArgument{Value: "typeof(MapQueryStringConverter)"})
				}

				csProp.IsOpt = !restTag.Required
				csProp.Attributes = append(csProp.Attributes, a)
			} else {
				a := CSAttribute{Type: CSType{"", "DataMember", false}}
				a.NamedArguments = append(a.NamedArguments, CSNamedArgument{"Name", CSArgument{jsonName, CSInboxTypesMap[reflect.String]}})
				a.NamedArguments = append(a.NamedArguments, CSNamedArgument{"EmitDefaultValue", CSArgument{strconv.FormatBool(false), CSInboxTypesMap[reflect.Bool]}})
				csProp.Attributes = append(csProp.Attributes, a)
			}

			// Lastly assign the property to our type.
			m.Properties = append(m.Properties, csProp)
		}
	}
}

func reflectType(name string, t reflect.Type, reflectedTypes map[string]*CSModelType) {
	if _, ok := reflectedTypes[name]; ok {
		return
	} else if name == "" {
		return
	}

	m := NewModel(name, fmt.Sprintf("%s", t))
	reflectedTypes[name] = m

	reflectTypeMembers(t, m, reflectedTypes)
}

func reflectDockerType(t typeDef, reflectedTypes map[string]*CSModelType) {
	reflectType(t.CsName, t.Type, reflectedTypes)
}

func reflectDockerTypes() map[string]*CSModelType {
	reflectedTypes := make(map[string]*CSModelType)

	for _, t := range dockerTypesToReflect {
		reflectDockerType(t, reflectedTypes)
	}

	return reflectedTypes
}

func main() {
	argsLen := len(os.Args)
	sourcePath := ""
	if argsLen >= 2 {
		sourcePath = os.Args[1]
		fmt.Println(sourcePath)
		if _, err := os.Stat(sourcePath); err != nil {
			if os.IsNotExist(err) {
				panic(sourcePath + ", is not a valid directory.")
			}
		}
	} else {
		sourcePath, _ = os.Getwd()
	}

	// Delete any previously generated files.
	if files, err := ioutil.ReadDir(sourcePath); err != nil {
		panic(err)
	} else {
		for _, file := range files {
			if strings.HasSuffix(file.Name(), ".Generated.cs") {
				if err := os.Remove(path.Join(sourcePath, file.Name())); err != nil {
					panic(err)
				}
			}
		}
	}

	csTypes := reflectDockerTypes()

	for k, v := range csTypes {
		f, err := ioutil.TempFile(sourcePath, "ser")
		if err != nil {
			panic(err)
		}

		defer f.Close()

		b := bufio.NewWriter(f)
		v.Write(b)
		err = b.Flush()
		if err != nil {
			os.Remove(f.Name())
			panic(err)
		}

		f.Close()
		os.Rename(f.Name(), path.Join(sourcePath, k+".Generated.cs"))
	}
}
<|endoftext|>


<commit_before>package routes

import (
	"github.com/danjac/photoshare/api/models"
	"github.com/danjac/photoshare/api/render"
	"github.com/danjac/photoshare/api/session"
	"github.com/danjac/photoshare/api/utils"
	"net/http"
)

func upload(w http.ResponseWriter, r *http.Request) {

	user, err := session.GetCurrentUser(r)
	if err != nil {
		render.Error(w, err)
		return
	}
	if user == nil {
		render.Status(w, http.StatusUnauthorized, "Not logged in")
		return
	}

	title := r.FormValue("title")
	src, hdr, err := r.FormFile("photo")
	if err != nil {
		render.Error(w, err)
		return
	}
	contentType := hdr.Header["Content-Type"][0]
	if contentType != "image/png" && contentType != "image/jpeg" {
		render.Status(w, http.StatusBadRequest, "Not a valid image")
		return
	}

	defer src.Close()
	filename, err := utils.ProcessImage(src, contentType, fileUploadDir)
	if err != nil {
		render.Error(w, err)
		return
	}

	photo := &models.Photo{Title: title,
		OwnerID: user.ID, Photo: filename}

	if result := photo.Validate(); !result.OK {
		render.JSON(w, http.StatusBadRequest, result)
	}

	if err := photo.Save(); err != nil {
		render.Error(w, err)
		return
	}

	render.JSON(w, http.StatusOK, photo)
}

func getPhotos(w http.ResponseWriter, r *http.Request) {

	photos, err := models.GetPhotos()
	if err != nil {
		render.Error(w, err)
		return
	}
	render.JSON(w, http.StatusOK, photos)
}
<commit_msg>Validation fix<commit_after>package routes

import (
	"github.com/danjac/photoshare/api/models"
	"github.com/danjac/photoshare/api/render"
	"github.com/danjac/photoshare/api/session"
	"github.com/danjac/photoshare/api/utils"
	"net/http"
)

func upload(w http.ResponseWriter, r *http.Request) {

	user, err := session.GetCurrentUser(r)
	if err != nil {
		render.Error(w, err)
		return
	}
	if user == nil {
		render.Status(w, http.StatusUnauthorized, "Not logged in")
		return
	}

	title := r.FormValue("title")
	src, hdr, err := r.FormFile("photo")
	if err != nil {
		render.Error(w, err)
		return
	}
	contentType := hdr.Header["Content-Type"][0]
	if contentType != "image/png" && contentType != "image/jpeg" {
		render.Status(w, http.StatusBadRequest, "Not a valid image")
		return
	}

	defer src.Close()
	filename, err := utils.ProcessImage(src, contentType, fileUploadDir)
	if err != nil {
		render.Error(w, err)
		return
	}

	photo := &models.Photo{Title: title,
		OwnerID: user.ID, Photo: filename}

	if result := photo.Validate(); !result.OK {
		render.JSON(w, http.StatusBadRequest, result)
        return
	}

	if err := photo.Save(); err != nil {
		render.Error(w, err)
		return
	}

	render.JSON(w, http.StatusOK, photo)
}

func getPhotos(w http.ResponseWriter, r *http.Request) {

	photos, err := models.GetPhotos()
	if err != nil {
		render.Error(w, err)
		return
	}
	render.JSON(w, http.StatusOK, photos)
}
<|endoftext|>


<commit_before>package logs

import (
	"encoding/json"
	"strings"

	"github.com/Shopify/sarama"
	"github.com/appcelerator/amp/data/elasticsearch"
	"github.com/appcelerator/amp/data/kafka"
	"github.com/appcelerator/amp/data/storage"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"gopkg.in/olivere/elastic.v3"
)

const (
	esIndex       = "amp-logs"
	kafkaLogTopic = "amp-logs"
)

// Logs is used to implement log.LogServer
type Logs struct {
	Es    elasticsearch.Elasticsearch
	Store storage.Interface
	Kafka kafka.Kafka
}

// Get implements log.LogServer
func (logs *Logs) Get(ctx context.Context, in *GetRequest) (*GetReply, error) {
	// TODO: Authentication is disabled in order to allow tests. Re-enable this as soon as we have a way to auth in tests.
	//_, err := oauth.CheckAuthorization(ctx, logs.Store)
	//if err != nil {
	//	return nil, err
	//}
	// Prepare request to elasticsearch
	request := logs.Es.GetClient().Search().Index(esIndex)
	request.Sort("time_id", false)
	if in.Size != 0 {
		request.Size(int(in.Size))
	} else {
		request.Size(100)
	}

	masterQuery := elastic.NewBoolQuery()
	if in.ServiceId != "" {
		masterQuery.Must(elastic.NewPrefixQuery("service_id", in.ServiceId))
	}
	if in.ServiceName != "" {
		masterQuery.Must(elastic.NewPrefixQuery("service_name", in.ServiceName))
	}
	if in.ContainerId != "" {
		masterQuery.Must(elastic.NewPrefixQuery("container_id", in.ContainerId))
	}
	if in.NodeId != "" {
		masterQuery.Must(elastic.NewPrefixQuery("node_id", in.NodeId))
	}
	if in.ServiceIsh != "" {
		queryString := elastic.NewQueryStringQuery(in.ServiceIsh + "*")
		queryString.Field("service_id")
		queryString.Field("service_name")
		queryString.AnalyzeWildcard(true)
		masterQuery.Must(queryString)
	}
	if in.Message != "" {
		queryString := elastic.NewQueryStringQuery(in.Message + "*")
		queryString.Field("message")
		queryString.AnalyzeWildcard(true)
		masterQuery.Must(queryString)
	}
	// TODO timestamp queries

	// Perform request
	searchResult, err := request.Query(masterQuery).Do()
	if err != nil {
		return nil, err
	}

	// Build reply (from elasticsearch response)
	reply := GetReply{}
	reply.Entries = make([]*LogEntry, len(searchResult.Hits.Hits))
	for i, hit := range searchResult.Hits.Hits {
		entry, err := parseJSONLogEntry(*hit.Source)
		if err != nil {
			return nil, err
		}
		reply.Entries[i] = &entry
	}

	// Reverse entries
	for i, j := 0, len(reply.Entries)-1; i < j; i, j = i+1, j-1 {
		reply.Entries[i], reply.Entries[j] = reply.Entries[j], reply.Entries[i]
	}

	return &reply, nil
}

// GetStream implements log.LogServer
func (logs *Logs) GetStream(in *GetRequest, stream Logs_GetStreamServer) error {
	consumer, err := logs.Kafka.NewConsumer()
	if err != nil {
		return err
	}
	partitionConsumer, err := consumer.ConsumePartition(kafkaLogTopic, 0, sarama.OffsetNewest)
	if err != nil {
		return err
	}

	for {
		select {
		case msg := <-partitionConsumer.Messages():
			entry, err := parseProtoLogEntry(msg.Value)
			if err != nil {
				return err
			}
			if filter(&entry, in) {
				stream.Send(&entry)
			}

		case <-stream.Context().Done():
			return stream.Context().Err()
		}
	}
}

func parseJSONLogEntry(data []byte) (logEntry LogEntry, err error) {
	err = json.Unmarshal(data, &logEntry)
	return
}

func parseProtoLogEntry(data []byte) (logEntry LogEntry, err error) {
	err = proto.Unmarshal(data, &logEntry)
	return
}

func filter(entry *LogEntry, in *GetRequest) bool {
	match := true
	if in.ServiceId != "" {
		match = strings.EqualFold(entry.ServiceId, in.ServiceId)
	}
	if in.ServiceName != "" {
		match = strings.EqualFold(entry.ServiceName, in.ServiceName)
	}
	if in.ContainerId != "" {
		match = strings.EqualFold(entry.ContainerId, in.ContainerId)
	}
	if in.NodeId != "" {
		match = strings.EqualFold(entry.NodeId, in.NodeId)
	}
	if in.Message != "" {
		match = strings.Contains(strings.ToLower(entry.Message), strings.ToLower(in.Message))
	}
	return match
}
<commit_msg>amp logs CLI now accept parameters for serviceIsh and streaming (#228)<commit_after>package logs

import (
	"encoding/json"
	"strings"

	"github.com/Shopify/sarama"
	"github.com/appcelerator/amp/data/elasticsearch"
	"github.com/appcelerator/amp/data/kafka"
	"github.com/appcelerator/amp/data/storage"
	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"gopkg.in/olivere/elastic.v3"
)

const (
	esIndex       = "amp-logs"
	kafkaLogTopic = "amp-logs"
)

// Logs is used to implement log.LogServer
type Logs struct {
	Es    elasticsearch.Elasticsearch
	Store storage.Interface
	Kafka kafka.Kafka
}

// Get implements log.LogServer
func (logs *Logs) Get(ctx context.Context, in *GetRequest) (*GetReply, error) {
	// TODO: Authentication is disabled in order to allow tests. Re-enable this as soon as we have a way to auth in tests.
	//_, err := oauth.CheckAuthorization(ctx, logs.Store)
	//if err != nil {
	//	return nil, err
	//}
	// Prepare request to elasticsearch
	request := logs.Es.GetClient().Search().Index(esIndex)
	request.Sort("time_id", false)
	if in.Size != 0 {
		request.Size(int(in.Size))
	} else {
		request.Size(100)
	}

	masterQuery := elastic.NewBoolQuery()
	if in.ServiceId != "" {
		masterQuery.Must(elastic.NewPrefixQuery("service_id", in.ServiceId))
	}
	if in.ServiceName != "" {
		masterQuery.Must(elastic.NewPrefixQuery("service_name", in.ServiceName))
	}
	if in.ContainerId != "" {
		masterQuery.Must(elastic.NewPrefixQuery("container_id", in.ContainerId))
	}
	if in.NodeId != "" {
		masterQuery.Must(elastic.NewPrefixQuery("node_id", in.NodeId))
	}
	if in.ServiceIsh != "" {
		queryString := elastic.NewQueryStringQuery(in.ServiceIsh + "*")
		queryString.Field("service_id")
		queryString.Field("service_name")
		queryString.AnalyzeWildcard(true)
		masterQuery.Must(queryString)
	}
	if in.Message != "" {
		queryString := elastic.NewQueryStringQuery(in.Message + "*")
		queryString.Field("message")
		queryString.AnalyzeWildcard(true)
		masterQuery.Must(queryString)
	}
	// TODO timestamp queries

	// Perform request
	searchResult, err := request.Query(masterQuery).Do()
	if err != nil {
		return nil, err
	}

	// Build reply (from elasticsearch response)
	reply := GetReply{}
	reply.Entries = make([]*LogEntry, len(searchResult.Hits.Hits))
	for i, hit := range searchResult.Hits.Hits {
		entry, err := parseJSONLogEntry(*hit.Source)
		if err != nil {
			return nil, err
		}
		reply.Entries[i] = &entry
	}

	// Reverse entries
	for i, j := 0, len(reply.Entries)-1; i < j; i, j = i+1, j-1 {
		reply.Entries[i], reply.Entries[j] = reply.Entries[j], reply.Entries[i]
	}

	return &reply, nil
}

// GetStream implements log.LogServer
func (logs *Logs) GetStream(in *GetRequest, stream Logs_GetStreamServer) error {
	consumer, err := logs.Kafka.NewConsumer()
	if err != nil {
		return err
	}
	partitionConsumer, err := consumer.ConsumePartition(kafkaLogTopic, 0, sarama.OffsetNewest)
	if err != nil {
		return err
	}

	for {
		select {
		case msg := <-partitionConsumer.Messages():
			entry, err := parseProtoLogEntry(msg.Value)
			if err != nil {
				return err
			}
			if filter(&entry, in) {
				stream.Send(&entry)
			}

		case <-stream.Context().Done():
			return stream.Context().Err()
		}
	}
}

func parseJSONLogEntry(data []byte) (logEntry LogEntry, err error) {
	err = json.Unmarshal(data, &logEntry)
	return
}

func parseProtoLogEntry(data []byte) (logEntry LogEntry, err error) {
	err = proto.Unmarshal(data, &logEntry)
	return
}

func filter(entry *LogEntry, in *GetRequest) bool {
	match := true
	if in.ServiceId != "" {
		match = strings.EqualFold(entry.ServiceId, in.ServiceId)
	}
	if in.ServiceName != "" {
		match = strings.EqualFold(entry.ServiceName, in.ServiceName)
	}
	if in.ContainerId != "" {
		match = strings.EqualFold(entry.ContainerId, in.ContainerId)
	}
	if in.NodeId != "" {
		match = strings.EqualFold(entry.NodeId, in.NodeId)
	}
	if in.ServiceIsh != "" {
		serviceID := strings.ToLower(entry.ServiceId)
		serviceName := strings.ToLower(entry.ServiceName)
		match = strings.HasPrefix(serviceID, strings.ToLower(in.ServiceIsh)) || strings.HasPrefix(serviceName, strings.ToLower(in.ServiceIsh))
	}
	if in.Message != "" {
		match = strings.Contains(strings.ToLower(entry.Message), strings.ToLower(in.Message))
	}
	return match
}
<|endoftext|>


<commit_before>package server

import (
	"crypto/tls"
	"net"
	"net/http"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/server/httputils"
	"github.com/docker/docker/api/server/router"
	"github.com/docker/docker/api/server/router/build"
	"github.com/docker/docker/api/server/router/container"
	"github.com/docker/docker/api/server/router/local"
	"github.com/docker/docker/api/server/router/network"
	"github.com/docker/docker/api/server/router/system"
	"github.com/docker/docker/api/server/router/volume"
	"github.com/docker/docker/daemon"
	"github.com/docker/docker/pkg/authorization"
	"github.com/docker/docker/utils"
	"github.com/docker/go-connections/sockets"
	"github.com/gorilla/mux"
	"golang.org/x/net/context"
)

// versionMatcher defines a variable matcher to be parsed by the router
// when a request is about to be served.
const versionMatcher = "/v{version:[0-9.]+}"

// Config provides the configuration for the API server
type Config struct {
	Logging                  bool
	EnableCors               bool
	CorsHeaders              string
	AuthorizationPluginNames []string
	Version                  string
	SocketGroup              string
	TLSConfig                *tls.Config
	Addrs                    []Addr
}

// Server contains instance details for the server
type Server struct {
	cfg           *Config
	servers       []*HTTPServer
	routers       []router.Router
	authZPlugins  []authorization.Plugin
	routerSwapper *routerSwapper
}

// Addr contains string representation of address and its protocol (tcp, unix...).
type Addr struct {
	Proto string
	Addr  string
}

// New returns a new instance of the server based on the specified configuration.
// It allocates resources which will be needed for ServeAPI(ports, unix-sockets).
func New(cfg *Config) (*Server, error) {
	s := &Server{
		cfg: cfg,
	}
	for _, addr := range cfg.Addrs {
		srv, err := s.newServer(addr.Proto, addr.Addr)
		if err != nil {
			return nil, err
		}
		logrus.Debugf("Server created for HTTP on %s (%s)", addr.Proto, addr.Addr)
		s.servers = append(s.servers, srv...)
	}
	return s, nil
}

// Close closes servers and thus stop receiving requests
func (s *Server) Close() {
	for _, srv := range s.servers {
		if err := srv.Close(); err != nil {
			logrus.Error(err)
		}
	}
}

// serveAPI loops through all initialized servers and spawns goroutine
// with Server method for each. It sets createMux() as Handler also.
func (s *Server) serveAPI() error {
	s.initRouterSwapper()

	var chErrors = make(chan error, len(s.servers))
	for _, srv := range s.servers {
		srv.srv.Handler = s.routerSwapper
		go func(srv *HTTPServer) {
			var err error
			logrus.Infof("API listen on %s", srv.l.Addr())
			if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
				err = nil
			}
			chErrors <- err
		}(srv)
	}

	for i := 0; i < len(s.servers); i++ {
		err := <-chErrors
		if err != nil {
			return err
		}
	}

	return nil
}

// HTTPServer contains an instance of http server and the listener.
// srv *http.Server, contains configuration to create a http server and a mux router with all api end points.
// l   net.Listener, is a TCP or Socket listener that dispatches incoming request to the router.
type HTTPServer struct {
	srv *http.Server
	l   net.Listener
}

// Serve starts listening for inbound requests.
func (s *HTTPServer) Serve() error {
	return s.srv.Serve(s.l)
}

// Close closes the HTTPServer from listening for the inbound requests.
func (s *HTTPServer) Close() error {
	return s.l.Close()
}

func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
	logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
	w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
	w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
}

func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
	if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
		logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
	}
	if l, err = sockets.NewTCPSocket(addr, s.cfg.TLSConfig); err != nil {
		return nil, err
	}
	if err := allocateDaemonPort(addr); err != nil {
		return nil, err
	}
	return
}

func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// log the handler call
		logrus.Debugf("Calling %s %s", r.Method, r.URL.Path)

		// Define the context that we'll pass around to share info
		// like the docker-request-id.
		//
		// The 'context' will be used for global data that should
		// apply to all requests. Data that is specific to the
		// immediate function being called should still be passed
		// as 'args' on the function call.
		ctx := context.Background()
		handlerFunc := s.handleWithGlobalMiddlewares(handler)

		vars := mux.Vars(r)
		if vars == nil {
			vars = make(map[string]string)
		}

		if err := handlerFunc(ctx, w, r, vars); err != nil {
			logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
			httputils.WriteError(w, err)
		}
	}
}

// InitRouters initializes a list of routers for the server.
func (s *Server) InitRouters(d *daemon.Daemon) {
	s.addRouter(container.NewRouter(d))
	s.addRouter(local.NewRouter(d))
	s.addRouter(network.NewRouter(d))
	s.addRouter(system.NewRouter(d))
	s.addRouter(volume.NewRouter(d))
	s.addRouter(build.NewRouter(d))
}

// addRouter adds a new router to the server.
func (s *Server) addRouter(r router.Router) {
	s.routers = append(s.routers, r)
}

// createMux initializes the main router the server uses.
// we keep enableCors just for legacy usage, need to be removed in the future
func (s *Server) createMux() *mux.Router {
	m := mux.NewRouter()
	if utils.IsDebugEnabled() {
		profilerSetup(m, "/debug/")
	}

	logrus.Debugf("Registering routers")
	for _, apiRouter := range s.routers {
		for _, r := range apiRouter.Routes() {
			f := s.makeHTTPHandler(r.Handler())

			logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
			m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
			m.Path(r.Path()).Methods(r.Method()).Handler(f)
		}
	}

	return m
}

// Wait blocks the server goroutine until it exits.
// It sends an error message if there is any error during
// the API execution.
func (s *Server) Wait(waitChan chan error) {
	if err := s.serveAPI(); err != nil {
		logrus.Errorf("ServeAPI error: %v", err)
		waitChan <- err
		return
	}
	waitChan <- nil
}

func (s *Server) initRouterSwapper() {
	s.routerSwapper = &routerSwapper{
		router: s.createMux(),
	}
}

// Reload reads configuration changes and modifies the
// server according to those changes.
// Currently, only the --debug configuration is taken into account.
func (s *Server) Reload(config *daemon.Config) {
	debugEnabled := utils.IsDebugEnabled()
	switch {
	case debugEnabled && !config.Debug: // disable debug
		utils.DisableDebug()
		s.routerSwapper.Swap(s.createMux())
	case config.Debug && !debugEnabled: // enable debug
		utils.EnableDebug()
		s.routerSwapper.Swap(s.createMux())
	}
}
<commit_msg>Remove obsolete comment<commit_after>package server

import (
	"crypto/tls"
	"net"
	"net/http"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/server/httputils"
	"github.com/docker/docker/api/server/router"
	"github.com/docker/docker/api/server/router/build"
	"github.com/docker/docker/api/server/router/container"
	"github.com/docker/docker/api/server/router/local"
	"github.com/docker/docker/api/server/router/network"
	"github.com/docker/docker/api/server/router/system"
	"github.com/docker/docker/api/server/router/volume"
	"github.com/docker/docker/daemon"
	"github.com/docker/docker/pkg/authorization"
	"github.com/docker/docker/utils"
	"github.com/docker/go-connections/sockets"
	"github.com/gorilla/mux"
	"golang.org/x/net/context"
)

// versionMatcher defines a variable matcher to be parsed by the router
// when a request is about to be served.
const versionMatcher = "/v{version:[0-9.]+}"

// Config provides the configuration for the API server
type Config struct {
	Logging                  bool
	EnableCors               bool
	CorsHeaders              string
	AuthorizationPluginNames []string
	Version                  string
	SocketGroup              string
	TLSConfig                *tls.Config
	Addrs                    []Addr
}

// Server contains instance details for the server
type Server struct {
	cfg           *Config
	servers       []*HTTPServer
	routers       []router.Router
	authZPlugins  []authorization.Plugin
	routerSwapper *routerSwapper
}

// Addr contains string representation of address and its protocol (tcp, unix...).
type Addr struct {
	Proto string
	Addr  string
}

// New returns a new instance of the server based on the specified configuration.
// It allocates resources which will be needed for ServeAPI(ports, unix-sockets).
func New(cfg *Config) (*Server, error) {
	s := &Server{
		cfg: cfg,
	}
	for _, addr := range cfg.Addrs {
		srv, err := s.newServer(addr.Proto, addr.Addr)
		if err != nil {
			return nil, err
		}
		logrus.Debugf("Server created for HTTP on %s (%s)", addr.Proto, addr.Addr)
		s.servers = append(s.servers, srv...)
	}
	return s, nil
}

// Close closes servers and thus stop receiving requests
func (s *Server) Close() {
	for _, srv := range s.servers {
		if err := srv.Close(); err != nil {
			logrus.Error(err)
		}
	}
}

// serveAPI loops through all initialized servers and spawns goroutine
// with Server method for each. It sets createMux() as Handler also.
func (s *Server) serveAPI() error {
	s.initRouterSwapper()

	var chErrors = make(chan error, len(s.servers))
	for _, srv := range s.servers {
		srv.srv.Handler = s.routerSwapper
		go func(srv *HTTPServer) {
			var err error
			logrus.Infof("API listen on %s", srv.l.Addr())
			if err = srv.Serve(); err != nil && strings.Contains(err.Error(), "use of closed network connection") {
				err = nil
			}
			chErrors <- err
		}(srv)
	}

	for i := 0; i < len(s.servers); i++ {
		err := <-chErrors
		if err != nil {
			return err
		}
	}

	return nil
}

// HTTPServer contains an instance of http server and the listener.
// srv *http.Server, contains configuration to create a http server and a mux router with all api end points.
// l   net.Listener, is a TCP or Socket listener that dispatches incoming request to the router.
type HTTPServer struct {
	srv *http.Server
	l   net.Listener
}

// Serve starts listening for inbound requests.
func (s *HTTPServer) Serve() error {
	return s.srv.Serve(s.l)
}

// Close closes the HTTPServer from listening for the inbound requests.
func (s *HTTPServer) Close() error {
	return s.l.Close()
}

func writeCorsHeaders(w http.ResponseWriter, r *http.Request, corsHeaders string) {
	logrus.Debugf("CORS header is enabled and set to: %s", corsHeaders)
	w.Header().Add("Access-Control-Allow-Origin", corsHeaders)
	w.Header().Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth")
	w.Header().Add("Access-Control-Allow-Methods", "HEAD, GET, POST, DELETE, PUT, OPTIONS")
}

func (s *Server) initTCPSocket(addr string) (l net.Listener, err error) {
	if s.cfg.TLSConfig == nil || s.cfg.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert {
		logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\")
	}
	if l, err = sockets.NewTCPSocket(addr, s.cfg.TLSConfig); err != nil {
		return nil, err
	}
	if err := allocateDaemonPort(addr); err != nil {
		return nil, err
	}
	return
}

func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// log the handler call
		logrus.Debugf("Calling %s %s", r.Method, r.URL.Path)

		// Define the context that we'll pass around to share info
		// like the docker-request-id.
		//
		// The 'context' will be used for global data that should
		// apply to all requests. Data that is specific to the
		// immediate function being called should still be passed
		// as 'args' on the function call.
		ctx := context.Background()
		handlerFunc := s.handleWithGlobalMiddlewares(handler)

		vars := mux.Vars(r)
		if vars == nil {
			vars = make(map[string]string)
		}

		if err := handlerFunc(ctx, w, r, vars); err != nil {
			logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
			httputils.WriteError(w, err)
		}
	}
}

// InitRouters initializes a list of routers for the server.
func (s *Server) InitRouters(d *daemon.Daemon) {
	s.addRouter(container.NewRouter(d))
	s.addRouter(local.NewRouter(d))
	s.addRouter(network.NewRouter(d))
	s.addRouter(system.NewRouter(d))
	s.addRouter(volume.NewRouter(d))
	s.addRouter(build.NewRouter(d))
}

// addRouter adds a new router to the server.
func (s *Server) addRouter(r router.Router) {
	s.routers = append(s.routers, r)
}

// createMux initializes the main router the server uses.
func (s *Server) createMux() *mux.Router {
	m := mux.NewRouter()
	if utils.IsDebugEnabled() {
		profilerSetup(m, "/debug/")
	}

	logrus.Debugf("Registering routers")
	for _, apiRouter := range s.routers {
		for _, r := range apiRouter.Routes() {
			f := s.makeHTTPHandler(r.Handler())

			logrus.Debugf("Registering %s, %s", r.Method(), r.Path())
			m.Path(versionMatcher + r.Path()).Methods(r.Method()).Handler(f)
			m.Path(r.Path()).Methods(r.Method()).Handler(f)
		}
	}

	return m
}

// Wait blocks the server goroutine until it exits.
// It sends an error message if there is any error during
// the API execution.
func (s *Server) Wait(waitChan chan error) {
	if err := s.serveAPI(); err != nil {
		logrus.Errorf("ServeAPI error: %v", err)
		waitChan <- err
		return
	}
	waitChan <- nil
}

func (s *Server) initRouterSwapper() {
	s.routerSwapper = &routerSwapper{
		router: s.createMux(),
	}
}

// Reload reads configuration changes and modifies the
// server according to those changes.
// Currently, only the --debug configuration is taken into account.
func (s *Server) Reload(config *daemon.Config) {
	debugEnabled := utils.IsDebugEnabled()
	switch {
	case debugEnabled && !config.Debug: // disable debug
		utils.DisableDebug()
		s.routerSwapper.Swap(s.createMux())
	case config.Debug && !debugEnabled: // enable debug
		utils.EnableDebug()
		s.routerSwapper.Swap(s.createMux())
	}
}
<|endoftext|>


<commit_before>package pixur

import (
	"os"
	"testing"
)

// TODO: add tests

<commit_msg>add shell test for webm<commit_after>package pixur

import (
	"os"
	"testing"
)

// TODO: add tests
<|endoftext|>


<commit_before>package scope

import (
	"testing"

	"github.com/gernest/ngorm/engine"
	"github.com/gernest/ngorm/fixture"
	"github.com/gernest/ngorm/model"
)

func TestFieldByName(t *testing.T) {
	e := &engine.Engine{
		Search:    &engine.Search{},
		Scope:     &engine.Scope{},
		StructMap: model.NewModelStructsMap(),
	}
	e.Parent = e
	var field fixture.CalculateField
	if f, ok := FieldByName(e, &field, "Children"); !ok || f.Relationship == nil {
		t.Errorf("Should calculate fields correctly for the first time")
	}
}
<commit_msg>[scope] Refactoring tests<commit_after>package scope

import (
	"testing"

	"github.com/gernest/ngorm/fixture"
)

func TestFieldByName(t *testing.T) {
	e := fixture.TestEngine()
	e.Parent = e
	var field fixture.CalculateField
	if f, ok := FieldByName(e, &field, "Children"); !ok || f.Relationship == nil {
		t.Errorf("Should calculate fields correctly for the first time")
	}
}
<|endoftext|>


<commit_before>package reverseproxy

import (
	"io"
	"net"
	"net/http"
	"sync"
)

// ProxyWebSocket proxies a WebSocket request to a given host.
// This should only be used if the request had an "Upgrade: websocket" header.
func ProxyWebSocket(w http.ResponseWriter, r *http.Request, host string) {
	proxyWebSocket(w, r, []string{host}, []int{0})
}

func proxyWebSocket(w http.ResponseWriter, r *http.Request, hosts []string,
	indices []int) {
	// Make sure we can hijack the ResponseWriter.
	hj, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "could not hijack connection", http.StatusBadGateway)
		return
	}

	// Open a raw connection to a destination host
	var conn net.Conn
	var err error
	var host string
	for _, i := range indices {
		host = hosts[i]
		conn, err = net.Dial("tcp", host)
		if err == nil {
			break
		}
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	// Update the headers and send the request to the target host
	r.Header = requestHeaders(r, host, true)
	r.Host = host
	if err := r.Write(conn); err != nil {
		conn.Close()
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	// Hijack the response and proxy the data.
	hjConn, hjStream, err := hj.Hijack()
	if err != nil {
		conn.Close()
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	bidirectionalPipe(hjStream, conn, func() {
		hjStream.Flush()
		conn.Close()
		hjConn.Close()
	})
}

// bidirectionalPipe pipes two io.ReadWriters into each other.
// When one io.ReadWriter is closed, closeBoth() is called.
// This method only returns once both streams have been closed.
func bidirectionalPipe(a io.ReadWriter, b io.ReadWriter, closeBoth func()) {
	wg := &sync.WaitGroup{}
	wg.Add(2)
	go func() {
		io.Copy(b, a)
		closeBoth()
		wg.Done()
	}()
	go func() {
		io.Copy(a, b)
		closeBoth()
		wg.Done()
	}()
	wg.Wait()
}
<commit_msg>flush buffers when proxying websocket<commit_after>package reverseproxy

import (
	"bufio"
	"io"
	"net"
	"net/http"
	"sync"
)

// ProxyWebSocket proxies a WebSocket request to a given host.
// This should only be used if the request had an "Upgrade: websocket" header.
func ProxyWebSocket(w http.ResponseWriter, r *http.Request, host string) {
	proxyWebSocket(w, r, []string{host}, []int{0})
}

func proxyWebSocket(w http.ResponseWriter, r *http.Request, hosts []string,
	indices []int) {
	// Make sure we can hijack the ResponseWriter.
	hj, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "could not hijack connection", http.StatusBadGateway)
		return
	}

	// Open a raw connection to a destination host
	var conn net.Conn
	var err error
	var host string
	for _, i := range indices {
		host = hosts[i]
		conn, err = net.Dial("tcp", host)
		if err == nil {
			break
		}
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	// Update the headers and send the request to the target host
	r.Header = requestHeaders(r, host, true)
	r.Host = host
	if err := r.Write(conn); err != nil {
		conn.Close()
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}

	// Hijack the response and proxy the data.
	hjConn, hjStream, err := hj.Hijack()
	if err != nil {
		conn.Close()
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	bidirectionalPipe(&flushWriter{hjStream}, conn, func() {
		hjStream.Flush()
		conn.Close()
		hjConn.Close()
	})
}

// bidirectionalPipe pipes two io.ReadWriters into each other.
// When one io.ReadWriter is closed, closeBoth() is called.
// This method only returns once both streams have been closed.
func bidirectionalPipe(a io.ReadWriter, b io.ReadWriter, closeBoth func()) {
	wg := &sync.WaitGroup{}
	wg.Add(2)
	go func() {
		io.Copy(b, a)
		closeBoth()
		wg.Done()
	}()
	go func() {
		io.Copy(a, b)
		closeBoth()
		wg.Done()
	}()
	wg.Wait()
}

type flushWriter struct {
	b *bufio.ReadWriter
}

func (f *flushWriter) Read(buf []byte) (int, error) {
	return f.b.Read(buf)
}

func (f *flushWriter) Write(b []byte) (n int, err error) {
	n, err = f.b.Write(b)
	err1 := f.b.Flush()
	if err == nil {
		err = err1
	}
	return
}
<|endoftext|>


<commit_before>// spi is a package used by physical implementations. it provides
// additional interfaces that allow the physical implementations
// to efficiently map the abstract application entities onto a physical
// substrate such as a Modbus link or an XML document.
package spi

import (
	"github.com/crabmusket/gosunspec"
)

// An anchor is a physical-implementation specific anchor to
// information that pertains to the physical implementation
// of a data element. So, for example, physical implementations
// the anchor might be the offset of a block or a model from the
// start of the physical address space. In an XML implementation
// the anchor might be a reference to correponding element
// of the XML representation.
//
// The purpose it to allow navigation back to the physical
// implementation from the "canonical" representation.

type Anchor interface{}

type Anchored interface {
	Anchor() Anchor
	SetAnchor(a Anchor)
}

// PointSPI provides additional interfaces that the physical implementation
// needs to support the public interface of the point.
type PointSPI interface {
	Anchored
	sunspec.Point
	Length() uint16
	Offset() uint16
	Unmarshal([]byte) error
	Marshal([]byte) error
	SetError(err error) // SetError clears the value and sets the error to the specified error
	ScaleFactorPoint() PointSPI
	MarshalXML() string
	UnmarshalXML(s string) error
}

// BlockSPI provides additional interfaces that the physical implementation
// needs to support the public interface of a block.
type BlockSPI interface {
	Anchored
	sunspec.Block
	Length() uint16
	SetLength(l uint16) // in cases where actual length differs from the spec length

	// Plan takes a set of pointIds to be read and returns a slice of points to
	// be read in the order they should be applied to the model
	// The algorithm ensures that:
	//    - if no points are specified, all are retrieved
	//    - if a point is read, then its scale factor (if any) is also read.
	//    - scale factors are applied to the model before any related points
	Plan(pointIds ...string) ([]PointSPI, error)

	// Invalidate any related point that depends on the specified point.
	Invalidate(p PointSPI)
}

// ModelSPI provides additional interfaces that the physical implementation
// needs to support the public interface of a model.
type ModelSPI interface {
	Anchored
	sunspec.Model
	Length() uint16
	AddRepeat() error // Add one repeat to the model
}

// DeviceSPI provides additional interfaces that the physical implementation
// needs to support the public interface of a device.
type DeviceSPI interface {
	Anchored
	sunspec.Device
	AddModel(m ModelSPI) error // Add a new model to the device
}

// ArraySPI provides additional interfaces that the physical implementation
// needs to support the public interface of an array.
type ArraySPI interface {
	Anchored
	sunspec.Array
	AddDevice(m DeviceSPI) error // Add a new model to the device
}

// Physical can read and write from the implementation model
// into the
type Physical interface {
	Write(block BlockSPI, pointIds ...string) error
	Read(block BlockSPI, pointIds ...string) error
}

// WithDeviceSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Device which also implements DeviceSPI.
func WithDeviceSPI(f func(DeviceSPI)) func(sunspec.Device) {
	return func(d sunspec.Device) {
		if ds, ok := d.(DeviceSPI); ok {
			f(ds)
		}
	}
}

// WithModelSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Model which also implements ModelSPI.
func WithModelSPI(f func(ModelSPI)) func(sunspec.Model) {
	return func(m sunspec.Model) {
		if ms, ok := m.(ModelSPI); ok {
			f(ms)
		}
	}
}

// WithBlockSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Block which also implements BlockSPI.
func WithBlockSPI(f func(BlockSPI)) func(sunspec.Block) {
	return func(b sunspec.Block) {
		if bs, ok := b.(BlockSPI); ok {
			f(bs)
		}
	}
}

// WithPointSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Point which also implements PointSPI.
func WithPointSPI(f func(PointSPI)) func(sunspec.Point) {
	return func(p sunspec.Point) {
		if ps, ok := p.(PointSPI); ok {
			f(ps)
		}
	}
}
<commit_msg>spi: refine documentation of what BlockSPI.Plan() does.<commit_after>// spi is a package used by physical implementations. it provides
// additional interfaces that allow the physical implementations
// to efficiently map the abstract application entities onto a physical
// substrate such as a Modbus link or an XML document.
package spi

import (
	"github.com/crabmusket/gosunspec"
)

// An anchor is a physical-implementation specific anchor to
// information that pertains to the physical implementation
// of a data element. So, for example, physical implementations
// the anchor might be the offset of a block or a model from the
// start of the physical address space. In an XML implementation
// the anchor might be a reference to correponding element
// of the XML representation.
//
// The purpose it to allow navigation back to the physical
// implementation from the "canonical" representation.

type Anchor interface{}

type Anchored interface {
	Anchor() Anchor
	SetAnchor(a Anchor)
}

// PointSPI provides additional interfaces that the physical implementation
// needs to support the public interface of the point.
type PointSPI interface {
	Anchored
	sunspec.Point
	Length() uint16
	Offset() uint16
	Unmarshal([]byte) error
	Marshal([]byte) error
	SetError(err error) // SetError clears the value and sets the error to the specified error
	ScaleFactorPoint() PointSPI
	MarshalXML() string
	UnmarshalXML(s string) error
}

// BlockSPI provides additional interfaces that the physical implementation
// needs to support the public interface of a block.
type BlockSPI interface {
	Anchored
	sunspec.Block
	Length() uint16
	SetLength(l uint16) // in cases where actual length differs from the spec length

	// Plan takes a set of pointIds to be read and returns a slice of points to
	// be read in the order they should be applied to the model
	//
	// The algorithm ensures that:
	//    - if no points are specified, then all are read
	//    - if a point is read, then the related scale factor point (if any) is also read.
	//    - if a scale factor point is read, then any other point dependent on the scale factor
	//      is also read.
	//    - scale factors are applied to the model before any related points
	Plan(pointIds ...string) ([]PointSPI, error)

	// Invalidate any related point that depends on the specified point.
	Invalidate(p PointSPI)
}

// ModelSPI provides additional interfaces that the physical implementation
// needs to support the public interface of a model.
type ModelSPI interface {
	Anchored
	sunspec.Model
	Length() uint16
	AddRepeat() error // Add one repeat to the model
}

// DeviceSPI provides additional interfaces that the physical implementation
// needs to support the public interface of a device.
type DeviceSPI interface {
	Anchored
	sunspec.Device
	AddModel(m ModelSPI) error // Add a new model to the device
}

// ArraySPI provides additional interfaces that the physical implementation
// needs to support the public interface of an array.
type ArraySPI interface {
	Anchored
	sunspec.Array
	AddDevice(m DeviceSPI) error // Add a new model to the device
}

// Physical can read and write from the implementation model
// into the
type Physical interface {
	Write(block BlockSPI, pointIds ...string) error
	Read(block BlockSPI, pointIds ...string) error
}

// WithDeviceSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Device which also implements DeviceSPI.
func WithDeviceSPI(f func(DeviceSPI)) func(sunspec.Device) {
	return func(d sunspec.Device) {
		if ds, ok := d.(DeviceSPI); ok {
			f(ds)
		}
	}
}

// WithModelSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Model which also implements ModelSPI.
func WithModelSPI(f func(ModelSPI)) func(sunspec.Model) {
	return func(m sunspec.Model) {
		if ms, ok := m.(ModelSPI); ok {
			f(ms)
		}
	}
}

// WithBlockSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Block which also implements BlockSPI.
func WithBlockSPI(f func(BlockSPI)) func(sunspec.Block) {
	return func(b sunspec.Block) {
		if bs, ok := b.(BlockSPI); ok {
			f(bs)
		}
	}
}

// WithPointSPI answers a function that will apply the specified function, f, to the function's
// argument if, and only if, the argument is a Point which also implements PointSPI.
func WithPointSPI(f func(PointSPI)) func(sunspec.Point) {
	return func(p sunspec.Point) {
		if ps, ok := p.(PointSPI); ok {
			f(ps)
		}
	}
}
<|endoftext|>


<commit_before>package langd

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"path/filepath"
	"sync"

	"github.com/object88/langd/log"
	"github.com/object88/rope"
)

// Workspace is a mass of code
type Workspace struct {
	rwm sync.RWMutex

	Loader *Loader

	log *log.Log
}

// CreateWorkspace returns a new instance of the Workspace struct
func CreateWorkspace(loader *Loader, log *log.Log) *Workspace {
	return &Workspace{
		Loader: loader,
		log:    log,
	}
}

// ChangeFile applies changes to an opened file
func (w *Workspace) ChangeFile(absFilepath string, startLine, startCharacter, endLine, endCharacter int, text string) error {
	buf, ok := w.Loader.openedFiles[absFilepath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absFilepath)
	}

	// Have position (line, character), need to transform into offset into file
	// Then replace starting from there.
	r1 := buf.NewReader()
	startOffset, err := CalculateOffsetForPosition(r1, startLine, startCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from start: %s", err.Error())
	}

	r2 := buf.NewReader()
	endOffset, err := CalculateOffsetForPosition(r2, endLine, endCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from end: %s", err.Error())
	}

	fmt.Printf("offsets: [%d:%d]\n", startOffset, endOffset)

	if err = buf.Alter(startOffset, endOffset, text); err != nil {
		return err
	}

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	return nil
}

// CloseFile will take a file out of the OpenedFiles struct and reparse
func (w *Workspace) CloseFile(absPath string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		w.log.Warnf("File %s is not opened\n", absPath)
		return nil
	}

	delete(w.Loader.openedFiles, absPath)

	w.log.Debugf("File %s is closed\n", absPath)

	return nil
}

// LocateIdent scans the loaded fset for the identifier at the requested
// position
func (w *Workspace) LocateIdent(p *token.Position) (*ast.Ident, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x *ast.Ident

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}
		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if WithinPosition(p, &pStart, &pEnd) {
			switch v := n.(type) {
			case *ast.Ident:
				offset := int(v.NamePos) - int(f.Pos())
				fmt.Printf("Found;     (offset %d) %#v\n", offset, n)
				x = v
				return false
			default:
				fmt.Printf("Narrowing; %#v\n", n)
			}
			return true
		}
		return false
	})

	return x, nil
}

// LocateDeclaration returns the position where the provided identifier is
// declared & defined
func (w *Workspace) LocateDeclaration(p *token.Position) (*token.Position, error) {
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		return nil, err
	}

	declPos := pkg.Fset.Position(obj.Pos())

	return &declPos, nil
}

// LocateReferences returns the array of positions where the given identifier
// is referenced or used
func (w *Workspace) LocateReferences(p *token.Position) []token.Position {
	// Get declaration position, ident, and package
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		// Crappy crap.
		return nil
	}

	// TODO: If declaration should be included in results set, add to `ps`

	refs := w.locateReferences(obj, pkg)

	ps := make([]token.Position, len(refs)+1)
	ps[0] = pkg.Fset.Position(obj.Pos())
	i := 1
	for _, v := range refs {
		ps[i] = v.pkg.Fset.Position(v.pos)
		i++
	}

	return ps
}

// OpenFile shadows the file read from the disk with an in-memory version,
// which the workspace can accept edits to.
func (w *Workspace) OpenFile(absFilepath, text string) error {
	if _, ok := w.Loader.openedFiles[absFilepath]; ok {
		return fmt.Errorf("File %s is already opened", absFilepath)
	}
	w.Loader.openedFiles[absFilepath] = rope.CreateRope(text)

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	w.log.Debugf("Shadowed file '%s'\n", absFilepath)

	return nil
}

// ReplaceFile replaces the entire contents of an opened file
func (w *Workspace) ReplaceFile(absPath, text string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absPath)
	}

	// Replace the entire document
	buf := rope.CreateRope(text)
	w.Loader.openedFiles[absPath] = buf

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	return nil
}

// Lock will synchronize access to the workspace for read or write access
func (w *Workspace) Lock(write bool) {
	if write {
		w.rwm.Lock()
	} else {
		w.rwm.RLock()
	}
}

// Unlock will synchronize access to the workspace for read or write access
func (w *Workspace) Unlock(write bool) {
	if write {
		w.rwm.Unlock()
	} else {
		w.rwm.RUnlock()
	}
}

func (w *Workspace) locateDeclaration(p *token.Position) (types.Object, *Package, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x ast.Node

	fmt.Printf("LocateDeclaration: %s\n", p.String())

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}

		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if !WithinPosition(p, &pStart, &pEnd) {
			return false
		}

		switch v := n.(type) {
		case *ast.Ident:
			fmt.Printf("... found ident; %#v\n", v)
			x = v
			return false
		case *ast.SelectorExpr:
			fmt.Printf("... found selector; %#v\n", v)
			selPos := v.Sel
			pSelStart := pkg.Fset.Position(selPos.Pos())
			pSelEnd := pkg.Fset.Position(selPos.End())
			if WithinPosition(p, &pSelStart, &pSelEnd) {
				s := pkg.checker.Selections[v]
				fmt.Printf("Selector: %#v\n", s)
				x = v
				return false
			}
		}

		return true
	})

	if x == nil {
		fmt.Printf("No x found\n")
		return nil, nil, nil
	}

	return w.xyz(x, pkg)
}

func (w *Workspace) xyz(x ast.Node, pkg *Package) (types.Object, *Package, error) {
	switch v := x.(type) {
	case *ast.Ident:
		fmt.Printf("Have ident %#v\n", v)
		if v.Obj != nil {
			fmt.Printf("Ident has obj %#v (%d)\n", v.Obj, v.Pos())
			vObj := pkg.checker.ObjectOf(v)
			return vObj, pkg, nil
		}
		if vDef, ok := pkg.checker.Defs[v]; ok {
			fmt.Printf("Have vDef from Defs: %#v\n", vDef)
			return vDef, pkg, nil
		}
		if vUse, ok := pkg.checker.Uses[v]; ok {
			// Used when var is defined in a package, in another file
			fmt.Printf("Have vUse from Uses: %#v\n", vUse)
			return vUse, pkg, nil
		}

	case *ast.SelectorExpr:
		return w.processSelectorExpr(v, pkg)

	default:
		fmt.Printf("Is %#v\n", x)
	}

	return nil, nil, nil
}

func (w *Workspace) processSelectorExpr(v *ast.SelectorExpr, pkg *Package) (types.Object, *Package, error) {
	fmt.Printf("Have SelectorExpr\n")
	switch vX := v.X.(type) {
	case *ast.Ident:
		vXObj := pkg.checker.ObjectOf(vX)
		if vXObj == nil {
			return nil, nil, fmt.Errorf("v.X (%s) not in ObjectOf", vX.Name)
		}
		fmt.Printf("checker.ObjectOf(v.X): %#v\n", vXObj)
		switch v1 := vXObj.(type) {
		case *types.PkgName:
			fmt.Printf("Have PkgName %s, type %s\n", v1.Name(), v1.Type())
			absPath := v1.Imported().Path()
			n, _ := w.Loader.caravan.Find(absPath)
			pkg1 := n.Element.(*Package)
			fmt.Printf("From pkg %#v\n", pkg1)

			oooo := pkg1.typesPkg.Scope().Lookup(v.Sel.Name)
			if oooo != nil {
				return oooo, pkg1, nil
			}

		case *types.Var:
			fmt.Printf("Have Var %s, type %s\n\tv1: %#v\n\tv1.Sel: %#v\n", v1.Name(), v1.Type(), v1, v.Sel)
			vSelObj := pkg.checker.ObjectOf(v.Sel)
			path := vSelObj.Pkg().Path()
			n, _ := w.Loader.caravan.Find(path)
			pkg1 := n.Element.(*Package)
			return vSelObj, pkg1, nil
		}
	case *ast.SelectorExpr:
		vSelObj := pkg.checker.ObjectOf(v.Sel)
		path := vSelObj.Pkg().Path()
		n, _ := w.Loader.caravan.Find(path)
		pkg1 := n.Element.(*Package)
		return vSelObj, pkg1, nil
	}

	return nil, nil, nil
}
<commit_msg>Fixing build error<commit_after>package langd

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"path/filepath"
	"sync"

	"github.com/object88/langd/log"
	"github.com/object88/rope"
)

// Workspace is a mass of code
type Workspace struct {
	rwm sync.RWMutex

	Loader *Loader

	log *log.Log
}

// CreateWorkspace returns a new instance of the Workspace struct
func CreateWorkspace(loader *Loader, log *log.Log) *Workspace {
	return &Workspace{
		Loader: loader,
		log:    log,
	}
}

// ChangeFile applies changes to an opened file
func (w *Workspace) ChangeFile(absFilepath string, startLine, startCharacter, endLine, endCharacter int, text string) error {
	buf, ok := w.Loader.openedFiles[absFilepath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absFilepath)
	}

	// Have position (line, character), need to transform into offset into file
	// Then replace starting from there.
	r1 := buf.NewReader()
	startOffset, err := CalculateOffsetForPosition(r1, startLine, startCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from start: %s", err.Error())
	}

	r2 := buf.NewReader()
	endOffset, err := CalculateOffsetForPosition(r2, endLine, endCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from end: %s", err.Error())
	}

	fmt.Printf("offsets: [%d:%d]\n", startOffset, endOffset)

	if err = buf.Alter(startOffset, endOffset, text); err != nil {
		return err
	}

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	return nil
}

// CloseFile will take a file out of the OpenedFiles struct and reparse
func (w *Workspace) CloseFile(absPath string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		w.log.Warnf("File %s is not opened\n", absPath)
		return nil
	}

	delete(w.Loader.openedFiles, absPath)

	w.log.Debugf("File %s is closed\n", absPath)

	return nil
}

// LocateIdent scans the loaded fset for the identifier at the requested
// position
func (w *Workspace) LocateIdent(p *token.Position) (*ast.Ident, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x *ast.Ident

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}
		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if WithinPosition(p, &pStart, &pEnd) {
			switch v := n.(type) {
			case *ast.Ident:
				offset := int(v.NamePos) - int(f.Pos())
				fmt.Printf("Found;     (offset %d) %#v\n", offset, n)
				x = v
				return false
			default:
				fmt.Printf("Narrowing; %#v\n", n)
			}
			return true
		}
		return false
	})

	return x, nil
}

// LocateDeclaration returns the position where the provided identifier is
// declared & defined
func (w *Workspace) LocateDeclaration(p *token.Position) (*token.Position, error) {
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		return nil, err
	}

	declPos := pkg.Fset.Position(obj.Pos())

	return &declPos, nil
}

// LocateReferences returns the array of positions where the given identifier
// is referenced or used
func (w *Workspace) LocateReferences(p *token.Position) []token.Position {
	// Get declaration position, ident, and package
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		// Crappy crap.
		return nil
	}

	// TODO: If declaration should be included in results set, add to `ps`

	refs := w.locateReferences(obj, pkg)

	ps := make([]token.Position, len(refs)+1)
	ps[0] = pkg.Fset.Position(obj.Pos())
	i := 1
	for _, v := range refs {
		ps[i] = v.pkg.Fset.Position(v.pos)
		i++
	}

	return ps
}

// OpenFile shadows the file read from the disk with an in-memory version,
// which the workspace can accept edits to.
func (w *Workspace) OpenFile(absFilepath, text string) error {
	if _, ok := w.Loader.openedFiles[absFilepath]; ok {
		return fmt.Errorf("File %s is already opened", absFilepath)
	}
	w.Loader.openedFiles[absFilepath] = rope.CreateRope(text)

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	w.log.Debugf("Shadowed file '%s'\n", absFilepath)

	return nil
}

// ReplaceFile replaces the entire contents of an opened file
func (w *Workspace) ReplaceFile(absFilepath, text string) error {
	_, ok := w.Loader.openedFiles[absFilepath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absFilepath)
	}

	// Replace the entire document
	buf := rope.CreateRope(text)
	w.Loader.openedFiles[absFilepath] = buf

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	return nil
}

// Lock will synchronize access to the workspace for read or write access
func (w *Workspace) Lock(write bool) {
	if write {
		w.rwm.Lock()
	} else {
		w.rwm.RLock()
	}
}

// Unlock will synchronize access to the workspace for read or write access
func (w *Workspace) Unlock(write bool) {
	if write {
		w.rwm.Unlock()
	} else {
		w.rwm.RUnlock()
	}
}

func (w *Workspace) locateDeclaration(p *token.Position) (types.Object, *Package, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x ast.Node

	fmt.Printf("LocateDeclaration: %s\n", p.String())

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}

		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if !WithinPosition(p, &pStart, &pEnd) {
			return false
		}

		switch v := n.(type) {
		case *ast.Ident:
			fmt.Printf("... found ident; %#v\n", v)
			x = v
			return false
		case *ast.SelectorExpr:
			fmt.Printf("... found selector; %#v\n", v)
			selPos := v.Sel
			pSelStart := pkg.Fset.Position(selPos.Pos())
			pSelEnd := pkg.Fset.Position(selPos.End())
			if WithinPosition(p, &pSelStart, &pSelEnd) {
				s := pkg.checker.Selections[v]
				fmt.Printf("Selector: %#v\n", s)
				x = v
				return false
			}
		}

		return true
	})

	if x == nil {
		fmt.Printf("No x found\n")
		return nil, nil, nil
	}

	return w.xyz(x, pkg)
}

func (w *Workspace) xyz(x ast.Node, pkg *Package) (types.Object, *Package, error) {
	switch v := x.(type) {
	case *ast.Ident:
		fmt.Printf("Have ident %#v\n", v)
		if v.Obj != nil {
			fmt.Printf("Ident has obj %#v (%d)\n", v.Obj, v.Pos())
			vObj := pkg.checker.ObjectOf(v)
			return vObj, pkg, nil
		}
		if vDef, ok := pkg.checker.Defs[v]; ok {
			fmt.Printf("Have vDef from Defs: %#v\n", vDef)
			return vDef, pkg, nil
		}
		if vUse, ok := pkg.checker.Uses[v]; ok {
			// Used when var is defined in a package, in another file
			fmt.Printf("Have vUse from Uses: %#v\n", vUse)
			return vUse, pkg, nil
		}

	case *ast.SelectorExpr:
		return w.processSelectorExpr(v, pkg)

	default:
		fmt.Printf("Is %#v\n", x)
	}

	return nil, nil, nil
}

func (w *Workspace) processSelectorExpr(v *ast.SelectorExpr, pkg *Package) (types.Object, *Package, error) {
	fmt.Printf("Have SelectorExpr\n")
	switch vX := v.X.(type) {
	case *ast.Ident:
		vXObj := pkg.checker.ObjectOf(vX)
		if vXObj == nil {
			return nil, nil, fmt.Errorf("v.X (%s) not in ObjectOf", vX.Name)
		}
		fmt.Printf("checker.ObjectOf(v.X): %#v\n", vXObj)
		switch v1 := vXObj.(type) {
		case *types.PkgName:
			fmt.Printf("Have PkgName %s, type %s\n", v1.Name(), v1.Type())
			absPath := v1.Imported().Path()
			n, _ := w.Loader.caravan.Find(absPath)
			pkg1 := n.Element.(*Package)
			fmt.Printf("From pkg %#v\n", pkg1)

			oooo := pkg1.typesPkg.Scope().Lookup(v.Sel.Name)
			if oooo != nil {
				return oooo, pkg1, nil
			}

		case *types.Var:
			fmt.Printf("Have Var %s, type %s\n\tv1: %#v\n\tv1.Sel: %#v\n", v1.Name(), v1.Type(), v1, v.Sel)
			vSelObj := pkg.checker.ObjectOf(v.Sel)
			path := vSelObj.Pkg().Path()
			n, _ := w.Loader.caravan.Find(path)
			pkg1 := n.Element.(*Package)
			return vSelObj, pkg1, nil
		}
	case *ast.SelectorExpr:
		vSelObj := pkg.checker.ObjectOf(v.Sel)
		path := vSelObj.Pkg().Path()
		n, _ := w.Loader.caravan.Find(path)
		pkg1 := n.Element.(*Package)
		return vSelObj, pkg1, nil
	}

	return nil, nil, nil
}
<|endoftext|>


<commit_before>package env
import (
	"os"
	"errors"
	"strconv"
)

func GetOr(key string, fallback string) string {
	if val, found := os.LookupEnv(key); found {
		return val
	}
	return fallback
}

func GetOrInt(key string, fallback int) (int, error) {
	if strVal, found := os.LookupEnv(key); found != false {
		if val,err := strconv.Atoi(strVal); err != nil {
			return val, nil
		} else {
			return 0, errors.New("Failed to make int from ENV " + key + ": " + err.Error())
		}
	} else {
		return fallback, nil
	}
}
<commit_msg>Fixed typo in env.go.<commit_after>package env
import (
	"os"
	"errors"
	"strconv"
)

func GetOr(key string, fallback string) string {
	if val, found := os.LookupEnv(key); found {
		return val
	}
	return fallback
}

func GetOrInt(key string, fallback int) (int, error) {
	if strVal, found := os.LookupEnv(key); found != false {
		if val,err := strconv.Atoi(strVal); err == nil {
			return val, nil
		} else {
			return 0, errors.New("Failed to make int from ENV " + key + ": " + err.Error())
		}
	} else {
		return fallback, nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 Apcera Inc. All rights reserved.
// +build ignore

package main

import (
	"flag"
	"log"
	"runtime"
	"strings"

	"github.com/nats-io/nats"
)

func usage() {
	log.Fatalf("Usage: nats-sub [-s server] [--ssl] [-t] <subject> \n")
}

var index = 0

func printMsg(m *nats.Msg, i int) {
	index += 1
	log.Printf("[#%d] Received on [%s]: '%s'\n", i, m.Subject, string(m.Data))
}

func main() {
	var urls = flag.String("s", nats.DefaultURL, "The nats server URLs (separated by comma)")
	var showTime = flag.Bool("t", false, "Display timestamps")
	var ssl = flag.Bool("ssl", false, "Use Secure Connection")

	log.SetFlags(0)
	flag.Usage = usage
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	opts := nats.DefaultOptions
	opts.Servers = strings.Split(*urls, ",")
	for i, s := range opts.Servers {
		opts.Servers[i] = strings.Trim(s, " ")
	}
	opts.Secure = *ssl

	nc, err := opts.Connect()
	if err != nil {
		log.Fatalf("Can't connect: %v\n", err)
	}

	subj, i := args[0], 0

	nc.Subscribe(subj, func(msg *nats.Msg) {
		i += 1
		printMsg(msg, i)
	})

	log.Printf("Listening on [%s]\n", subj)
	if *showTime {
		log.SetFlags(log.LstdFlags)
	}

	runtime.Goexit()
}
<commit_msg>removed unnneed variable index. Index was incremented but never used<commit_after>// Copyright 2012-2015 Apcera Inc. All rights reserved.
// +build ignore

package main

import (
	"flag"
	"log"
	"runtime"
	"strings"

	"github.com/nats-io/nats"
)

func usage() {
	log.Fatalf("Usage: nats-sub [-s server] [--ssl] [-t] <subject> \n")
}

func printMsg(m *nats.Msg, i int) {
	log.Printf("[#%d] Received on [%s]: '%s'\n", i, m.Subject, string(m.Data))
}

func main() {
	var urls = flag.String("s", nats.DefaultURL, "The nats server URLs (separated by comma)")
	var showTime = flag.Bool("t", false, "Display timestamps")
	var ssl = flag.Bool("ssl", false, "Use Secure Connection")

	log.SetFlags(0)
	flag.Usage = usage
	flag.Parse()

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	opts := nats.DefaultOptions
	opts.Servers = strings.Split(*urls, ",")
	for i, s := range opts.Servers {
		opts.Servers[i] = strings.Trim(s, " ")
	}
	opts.Secure = *ssl

	nc, err := opts.Connect()
	if err != nil {
		log.Fatalf("Can't connect: %v\n", err)
	}

	subj, i := args[0], 0

	nc.Subscribe(subj, func(msg *nats.Msg) {
		i += 1
		printMsg(msg, i)
	})

	log.Printf("Listening on [%s]\n", subj)
	if *showTime {
		log.SetFlags(log.LstdFlags)
	}

	runtime.Goexit()
}
<|endoftext|>