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

package lsp

import (
	"bytes"
	"context"
	"fmt"
	"go/ast"
	"go/token"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/event"
)

func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
	// TODO(golang/go#36501): Support document links for go.mod files.
	snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.UnknownKind)
	if !ok {
		return nil, err
	}
	switch fh.Identity().Kind {
	case source.Mod:
		return modLinks(ctx, snapshot, fh)
	case source.Go:
		return goLinks(ctx, snapshot.View(), fh)
	}
	return nil, nil
}

func modLinks(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentLink, error) {
	view := snapshot.View()

	file, m, err := snapshot.ModHandle(ctx, fh).Parse(ctx)
	if err != nil {
		return nil, err
	}
	var links []protocol.DocumentLink
	for _, req := range file.Require {
		dep := []byte(req.Mod.Path)
		s, e := req.Syntax.Start.Byte, req.Syntax.End.Byte
		i := bytes.Index(m.Content[s:e], dep)
		if i == -1 {
			continue
		}
		// Shift the start position to the location of the
		// dependency within the require statement.
		start, end := token.Pos(s+i), token.Pos(s+i+len(dep))
		target := fmt.Sprintf("https://%s/mod/%s", view.Options().LinkTarget, req.Mod.String())
		l, err := toProtocolLink(view, m, target, start, end, source.Mod)
		if err != nil {
			return nil, err
		}
		links = append(links, l)
	}
	// TODO(ridersofrohan): handle links for replace and exclude directives.
	if syntax := file.Syntax; syntax == nil {
		return links, nil
	}
	// Get all the links that are contained in the comments of the file.
	for _, expr := range file.Syntax.Stmt {
		comments := expr.Comment()
		if comments == nil {
			continue
		}
		for _, cmt := range comments.Before {
			links = append(links, findLinksInString(ctx, view, cmt.Token, token.Pos(cmt.Start.Byte), m, source.Mod)...)
		}
		for _, cmt := range comments.Suffix {
			links = append(links, findLinksInString(ctx, view, cmt.Token, token.Pos(cmt.Start.Byte), m, source.Mod)...)
		}
		for _, cmt := range comments.After {
			links = append(links, findLinksInString(ctx, view, cmt.Token, token.Pos(cmt.Start.Byte), m, source.Mod)...)
		}
	}
	return links, nil
}

func goLinks(ctx context.Context, view source.View, fh source.FileHandle) ([]protocol.DocumentLink, error) {
	phs, err := view.Snapshot().PackageHandles(ctx, fh)
	if err != nil {
		return nil, err
	}
	ph, err := source.WidestPackageHandle(phs)
	if err != nil {
		return nil, err
	}
	file, _, m, _, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
	if err != nil {
		return nil, err
	}
	var links []protocol.DocumentLink
	ast.Inspect(file, func(node ast.Node) bool {
		switch n := node.(type) {
		case *ast.ImportSpec:
			// For import specs, provide a link to a documentation website, like https://pkg.go.dev.
			if target, err := strconv.Unquote(n.Path.Value); err == nil {
				if mod, version, ok := moduleAtVersion(ctx, target, ph); ok && strings.ToLower(view.Options().LinkTarget) == "pkg.go.dev" {
					target = strings.Replace(target, mod, mod+"@"+version, 1)
				}
				target = fmt.Sprintf("https://%s/%s", view.Options().LinkTarget, target)
				// Account for the quotation marks in the positions.
				start, end := n.Path.Pos()+1, n.Path.End()-1
				l, err := toProtocolLink(view, m, target, start, end, source.Go)
				if err != nil {
					event.Error(ctx, "failed to create link", err)
					return false
				}
				links = append(links, l)
			}
			return false
		case *ast.BasicLit:
			// Look for links in string literals.
			if n.Kind == token.STRING {
				links = append(links, findLinksInString(ctx, view, n.Value, n.Pos(), m, source.Go)...)
			}
			return false
		}
		return true
	})
	// Look for links in comments.
	for _, commentGroup := range file.Comments {
		for _, comment := range commentGroup.List {
			links = append(links, findLinksInString(ctx, view, comment.Text, comment.Pos(), m, source.Go)...)
		}
	}
	return links, nil
}

func moduleAtVersion(ctx context.Context, target string, ph source.PackageHandle) (string, string, bool) {
	pkg, err := ph.Check(ctx)
	if err != nil {
		return "", "", false
	}
	impPkg, err := pkg.GetImport(target)
	if err != nil {
		return "", "", false
	}
	if impPkg.Module() == nil {
		return "", "", false
	}
	version, modpath := impPkg.Module().Version, impPkg.Module().Path
	if modpath == "" || version == "" {
		return "", "", false
	}
	return modpath, version, true
}

func findLinksInString(ctx context.Context, view source.View, src string, pos token.Pos, m *protocol.ColumnMapper, fileKind source.FileKind) []protocol.DocumentLink {
	var links []protocol.DocumentLink
	for _, index := range view.Options().URLRegexp.FindAllIndex([]byte(src), -1) {
		start, end := index[0], index[1]
		startPos := token.Pos(int(pos) + start)
		endPos := token.Pos(int(pos) + end)
		url, err := url.Parse(src[start:end])
		if err != nil {
			event.Error(ctx, "failed to parse matching URL", err)
			continue
		}
		// If the URL has no scheme, use https.
		if url.Scheme == "" {
			url.Scheme = "https"
		}
		l, err := toProtocolLink(view, m, url.String(), startPos, endPos, fileKind)
		if err != nil {
			event.Error(ctx, "failed to create protocol link", err)
			continue
		}
		links = append(links, l)
	}
	// Handle golang/go#1234-style links.
	r := getIssueRegexp()
	for _, index := range r.FindAllIndex([]byte(src), -1) {
		start, end := index[0], index[1]
		startPos := token.Pos(int(pos) + start)
		endPos := token.Pos(int(pos) + end)
		matches := r.FindStringSubmatch(src)
		if len(matches) < 4 {
			continue
		}
		org, repo, number := matches[1], matches[2], matches[3]
		target := fmt.Sprintf("https://github.com/%s/%s/issues/%s", org, repo, number)
		l, err := toProtocolLink(view, m, target, startPos, endPos, fileKind)
		if err != nil {
			event.Error(ctx, "failed to create protocol link", err)
			continue
		}
		links = append(links, l)
	}
	return links
}

func getIssueRegexp() *regexp.Regexp {
	once.Do(func() {
		issueRegexp = regexp.MustCompile(`(\w+)/([\w-]+)#([0-9]+)`)
	})
	return issueRegexp
}

var (
	once        sync.Once
	issueRegexp *regexp.Regexp
)

func toProtocolLink(view source.View, m *protocol.ColumnMapper, target string, start, end token.Pos, fileKind source.FileKind) (protocol.DocumentLink, error) {
	var rng protocol.Range
	switch fileKind {
	case source.Go:
		spn, err := span.NewRange(view.Session().Cache().FileSet(), start, end).Span()
		if err != nil {
			return protocol.DocumentLink{}, err
		}
		rng, err = m.Range(spn)
		if err != nil {
			return protocol.DocumentLink{}, err
		}
	case source.Mod:
		s, e := int(start), int(end)
		line, col, err := m.Converter.ToPosition(s)
		if err != nil {
			return protocol.DocumentLink{}, err
		}
		start := span.NewPoint(line, col, s)
		line, col, err = m.Converter.ToPosition(e)
		if err != nil {
			return protocol.DocumentLink{}, err
		}
		end := span.NewPoint(line, col, e)
		rng, err = m.Range(span.New(m.URI, start, end))
		if err != nil {
			return protocol.DocumentLink{}, err
		}
	}
	return protocol.DocumentLink{
		Range:  rng,
		Target: target,
	}, nil
}
<commit_msg>internal/lsp: linkify IP addresses in textDocument/documentLink<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lsp

import (
	"bytes"
	"context"
	"fmt"
	"go/ast"
	"go/token"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/mod/modfile"
	"golang.org/x/tools/internal/lsp/debug/tag"
	"golang.org/x/tools/internal/lsp/protocol"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/event"
)

func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) (links []protocol.DocumentLink, err error) {
	snapshot, fh, ok, err := s.beginFileRequest(params.TextDocument.URI, source.UnknownKind)
	if !ok {
		return nil, err
	}
	switch fh.Identity().Kind {
	case source.Mod:
		links, err = modLinks(ctx, snapshot, fh)
	case source.Go:
		links, err = goLinks(ctx, snapshot.View(), fh)
	}
	// Don't return errors for document links.
	if err != nil {
		event.Error(ctx, "failed to compute document links", err, tag.URI.Of(fh.Identity().URI))
		return nil, nil
	}
	return links, nil
}

func modLinks(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) ([]protocol.DocumentLink, error) {
	view := snapshot.View()

	file, m, err := snapshot.ModHandle(ctx, fh).Parse(ctx)
	if err != nil {
		return nil, err
	}
	var links []protocol.DocumentLink
	for _, req := range file.Require {
		dep := []byte(req.Mod.Path)
		s, e := req.Syntax.Start.Byte, req.Syntax.End.Byte
		i := bytes.Index(m.Content[s:e], dep)
		if i == -1 {
			continue
		}
		// Shift the start position to the location of the
		// dependency within the require statement.
		start, end := token.Pos(s+i), token.Pos(s+i+len(dep))
		target := fmt.Sprintf("https://%s/mod/%s", view.Options().LinkTarget, req.Mod.String())
		l, err := toProtocolLink(view, m, target, start, end, source.Mod)
		if err != nil {
			return nil, err
		}
		links = append(links, l)
	}
	// TODO(ridersofrohan): handle links for replace and exclude directives.
	if syntax := file.Syntax; syntax == nil {
		return links, nil
	}
	// Get all the links that are contained in the comments of the file.
	for _, expr := range file.Syntax.Stmt {
		comments := expr.Comment()
		if comments == nil {
			continue
		}
		for _, section := range [][]modfile.Comment{comments.Before, comments.Suffix, comments.After} {
			for _, comment := range section {
				l, err := findLinksInString(ctx, view, comment.Token, token.Pos(comment.Start.Byte), m, source.Mod)
				if err != nil {
					return nil, err
				}
				links = append(links, l...)
			}
		}
	}
	return links, nil
}

func goLinks(ctx context.Context, view source.View, fh source.FileHandle) ([]protocol.DocumentLink, error) {
	phs, err := view.Snapshot().PackageHandles(ctx, fh)
	if err != nil {
		return nil, err
	}
	ph, err := source.WidestPackageHandle(phs)
	if err != nil {
		return nil, err
	}
	file, _, m, _, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
	if err != nil {
		return nil, err
	}
	var imports []*ast.ImportSpec
	var str []*ast.BasicLit
	ast.Inspect(file, func(node ast.Node) bool {
		switch n := node.(type) {
		case *ast.ImportSpec:
			imports = append(imports, n)
			return false
		case *ast.BasicLit:
			// Look for links in string literals.
			if n.Kind == token.STRING {
				str = append(str, n)
			}
			return false
		}
		return true
	})
	var links []protocol.DocumentLink
	for _, imp := range imports {
		// For import specs, provide a link to a documentation website, like https://pkg.go.dev.
		target, err := strconv.Unquote(imp.Path.Value)
		if err != nil {
			continue
		}
		if mod, version, ok := moduleAtVersion(ctx, target, ph); ok && strings.ToLower(view.Options().LinkTarget) == "pkg.go.dev" {
			target = strings.Replace(target, mod, mod+"@"+version, 1)
		}
		// Account for the quotation marks in the positions.
		start := imp.Path.Pos() + 1
		end := imp.Path.End() - 1
		target = fmt.Sprintf("https://%s/%s", view.Options().LinkTarget, target)
		l, err := toProtocolLink(view, m, target, start, end, source.Go)
		if err != nil {
			return nil, err
		}
		links = append(links, l)
	}
	for _, s := range str {
		l, err := findLinksInString(ctx, view, s.Value, s.Pos(), m, source.Go)
		if err != nil {
			return nil, err
		}
		links = append(links, l...)
	}
	for _, commentGroup := range file.Comments {
		for _, comment := range commentGroup.List {
			l, err := findLinksInString(ctx, view, comment.Text, comment.Pos(), m, source.Go)
			if err != nil {
				return nil, err
			}
			links = append(links, l...)
		}
	}
	return links, nil
}

func moduleAtVersion(ctx context.Context, target string, ph source.PackageHandle) (string, string, bool) {
	pkg, err := ph.Check(ctx)
	if err != nil {
		return "", "", false
	}
	impPkg, err := pkg.GetImport(target)
	if err != nil {
		return "", "", false
	}
	if impPkg.Module() == nil {
		return "", "", false
	}
	version, modpath := impPkg.Module().Version, impPkg.Module().Path
	if modpath == "" || version == "" {
		return "", "", false
	}
	return modpath, version, true
}

func findLinksInString(ctx context.Context, view source.View, src string, pos token.Pos, m *protocol.ColumnMapper, fileKind source.FileKind) ([]protocol.DocumentLink, error) {
	var links []protocol.DocumentLink
	for _, index := range view.Options().URLRegexp.FindAllIndex([]byte(src), -1) {
		start, end := index[0], index[1]
		startPos := token.Pos(int(pos) + start)
		endPos := token.Pos(int(pos) + end)
		link := src[start:end]
		linkURL, err := url.Parse(link)
		// Fallback: Linkify IP addresses as suggested in golang/go#18824.
		if err != nil {
			linkURL, err = url.Parse("//" + link)
			// Not all potential links will be valid, so don't return this error.
			if err != nil {
				continue
			}
		}
		// If the URL has no scheme, use https.
		if linkURL.Scheme == "" {
			linkURL.Scheme = "https"
		}
		l, err := toProtocolLink(view, m, linkURL.String(), startPos, endPos, fileKind)
		if err != nil {
			return nil, err
		}
		links = append(links, l)
	}
	// Handle golang/go#1234-style links.
	r := getIssueRegexp()
	for _, index := range r.FindAllIndex([]byte(src), -1) {
		start, end := index[0], index[1]
		startPos := token.Pos(int(pos) + start)
		endPos := token.Pos(int(pos) + end)
		matches := r.FindStringSubmatch(src)
		if len(matches) < 4 {
			continue
		}
		org, repo, number := matches[1], matches[2], matches[3]
		target := fmt.Sprintf("https://github.com/%s/%s/issues/%s", org, repo, number)
		l, err := toProtocolLink(view, m, target, startPos, endPos, fileKind)
		if err != nil {
			return nil, err
		}
		links = append(links, l)
	}
	return links, nil
}

func getIssueRegexp() *regexp.Regexp {
	once.Do(func() {
		issueRegexp = regexp.MustCompile(`(\w+)/([\w-]+)#([0-9]+)`)
	})
	return issueRegexp
}

var (
	once        sync.Once
	issueRegexp *regexp.Regexp
)

func toProtocolLink(view source.View, m *protocol.ColumnMapper, target string, start, end token.Pos, fileKind source.FileKind) (protocol.DocumentLink, error) {
	var rng protocol.Range
	switch fileKind {
	case source.Go:
		spn, err := span.NewRange(view.Session().Cache().FileSet(), start, end).Span()
		if err != nil {
			return protocol.DocumentLink{}, err
		}
		rng, err = m.Range(spn)
		if err != nil {
			return protocol.DocumentLink{}, err
		}
	case source.Mod:
		s, e := int(start), int(end)
		line, col, err := m.Converter.ToPosition(s)
		if err != nil {
			return protocol.DocumentLink{}, err
		}
		start := span.NewPoint(line, col, s)
		line, col, err = m.Converter.ToPosition(e)
		if err != nil {
			return protocol.DocumentLink{}, err
		}
		end := span.NewPoint(line, col, e)
		rng, err = m.Range(span.New(m.URI, start, end))
		if err != nil {
			return protocol.DocumentLink{}, err
		}
	}
	return protocol.DocumentLink{
		Range:  rng,
		Target: target,
	}, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package internal

// This file has code for accessing metadata.
//
// References:
//	https://cloud.google.com/compute/docs/metadata

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
)

const (
	metadataHost = "metadata"
	metadataPath = "/computeMetadata/v1/"
)

var (
	metadataRequestHeaders = http.Header{
		"X-Google-Metadata-Request": []string{"True"},
	}
)

// TODO(dsymonds): Do we need to support default values, like Python?
func mustGetMetadata(key string) []byte {
	b, err := getMetadata(key)
	if err != nil {
		log.Fatalf("Metadata fetch failed: %v", err)
	}
	return b
}

func getMetadata(key string) ([]byte, error) {
	// TODO(dsymonds): May need to use url.Parse to support keys with query args.
	req := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Scheme: "http",
			Host:   metadataHost,
			Path:   metadataPath + key,
		},
		Header: metadataRequestHeaders,
		Host:   metadataHost,
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("metadata server returned HTTP %d", resp.StatusCode)
	}
	return ioutil.ReadAll(resp.Body)
}
<commit_msg>internal: Use the recommended metadata header.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package internal

// This file has code for accessing metadata.
//
// References:
//	https://cloud.google.com/compute/docs/metadata

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
)

const (
	metadataHost = "metadata"
	metadataPath = "/computeMetadata/v1/"
)

var (
	metadataRequestHeaders = http.Header{
		"Metadata-Flavor": []string{"Google"},
	}
)

// TODO(dsymonds): Do we need to support default values, like Python?
func mustGetMetadata(key string) []byte {
	b, err := getMetadata(key)
	if err != nil {
		log.Fatalf("Metadata fetch failed: %v", err)
	}
	return b
}

func getMetadata(key string) ([]byte, error) {
	// TODO(dsymonds): May need to use url.Parse to support keys with query args.
	req := &http.Request{
		Method: "GET",
		URL: &url.URL{
			Scheme: "http",
			Host:   metadataHost,
			Path:   metadataPath + key,
		},
		Header: metadataRequestHeaders,
		Host:   metadataHost,
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("metadata server returned HTTP %d", resp.StatusCode)
	}
	return ioutil.ReadAll(resp.Body)
}
<|endoftext|>


<commit_before>package vm

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/grubby/grubby/ast"
	"github.com/grubby/grubby/interpreter/vm/builtins"
	"github.com/grubby/grubby/parser"
)

type vm struct {
	currentFilename string
	ObjectSpace     map[string]builtins.Value
	Globals         map[string]builtins.Value
	KnownSymbols    map[string]builtins.Value
}

type VM interface {
	Run(string) (builtins.Value, error)
	Get(string) (builtins.Value, error)
	MustGet(string) builtins.Value

	Set(string, builtins.Value)

	Symbols() map[string]builtins.Value
}

func NewVM(name string) VM {
	vm := &vm{
		currentFilename: name,
		Globals:         make(map[string]builtins.Value),
		ObjectSpace:     make(map[string]builtins.Value),
		KnownSymbols:    make(map[string]builtins.Value),
	}

	loadPath := builtins.NewArrayClass().(builtins.Class).New()
	vm.Globals["$LOAD_PATH"] = loadPath
	vm.Globals["$:"] = loadPath // FIXME: add a test that these are the same object

	objectClass := builtins.NewGlobalObjectClass()
	vm.ObjectSpace["Object"] = objectClass
	vm.ObjectSpace["Kernel"] = builtins.NewGlobalKernelClass()
	vm.ObjectSpace["File"] = builtins.NewFileClass()
	vm.ObjectSpace["ARGV"] = builtins.NewArrayClass().(builtins.Class).New()
	vm.ObjectSpace["Process"] = builtins.NewProcessClass()

	main := objectClass.(builtins.Class).New()
	main.AddMethod(builtins.NewMethod("to_s", func(args ...builtins.Value) (builtins.Value, error) {
		return builtins.NewString("main"), nil
	}))
	main.AddMethod(builtins.NewMethod("require", func(args ...builtins.Value) (builtins.Value, error) {
		fileName := args[0].(*builtins.StringValue).String()
		if fileName == "rubygems" {
			// don't "require 'rubygems'"
			return builtins.NewFalseClass().(builtins.Class).New(), nil
		}

		for _, pathStr := range loadPath.(*builtins.Array).Members() {
			path := pathStr.(*builtins.StringValue)
			fullPath := filepath.Join(path.String(), fileName+".rb")
			file, err := os.Open(fullPath)
			if err != nil {
				continue
			}

			contents, err := ioutil.ReadAll(file)

			if err == nil {
				originalName := vm.currentFilename
				defer func() {
					vm.currentFilename = originalName
				}()

				vm.currentFilename = file.Name()
				vm.Run(string(contents))
				return nil, nil
			}
		}

		err := fmt.Sprintf("LoadError: cannot load such file -- %s", fileName)
		return nil, builtins.NewLoadError(err)

	}))
	main.AddMethod(builtins.NewMethod("puts", func(args ...builtins.Value) (builtins.Value, error) {
		for _, arg := range args {
			os.Stdout.Write([]byte(arg.String() + "\n"))
		}

		return nil, nil
	}))

	vm.ObjectSpace["main"] = main

	return vm
}

func (vm *vm) MustGet(key string) builtins.Value {
	val, ok := vm.ObjectSpace[key]
	if ok {
		return val
	}

	val, ok = vm.Globals[key]
	if ok {
		return val
	}

	return nil
}

func (vm *vm) Get(key string) (builtins.Value, error) {
	val, ok := vm.ObjectSpace[key]
	if ok {
		return val, nil
	}

	val, ok = vm.Globals[key]
	if ok {
		return val, nil
	}

	return nil, errors.New(fmt.Sprintf("'%s' is undefined", key))
}

func (vm *vm) Set(key string, value builtins.Value) {
	vm.ObjectSpace[key] = value
}

func (vm *vm) Symbols() map[string]builtins.Value {
	return vm.KnownSymbols
}

type ParseError struct{}

func NewParseError() *ParseError {
	return &ParseError{}
}

func (err *ParseError) Error() string {
	return "parse error"
}

func (vm *vm) Run(input string) (builtins.Value, error) {
	lexer := parser.NewLexer(input)
	result := parser.RubyParse(lexer)
	if result != 0 {
		return nil, NewParseError()
	}

	main := vm.ObjectSpace["main"]
	return vm.executeWithContext(parser.Statements, main)
}

func (vm *vm) executeWithContext(statements []ast.Node, context builtins.Value) (builtins.Value, error) {
	var (
		returnValue builtins.Value
		returnErr   error
	)
	for _, statement := range statements {
		switch statement.(type) {
		case ast.IfBlock:
			truthy := false
			ifBlock := statement.(ast.IfBlock)
			switch ifBlock.Condition.(type) {
			case ast.Boolean:
				truthy = ifBlock.Condition.(ast.Boolean).Value
			case ast.BareReference:
				truthy = ifBlock.Condition.(ast.BareReference).Name == "nil"
			default:
				truthy = true
			}

			if truthy {
				returnValue, returnErr = vm.executeWithContext(ifBlock.Body, context)
			} else {
				returnValue, returnErr = vm.executeWithContext(ifBlock.Else, context)
			}
		case ast.FuncDecl:
			// FIXME: assumes for now this will only ever be at the top level
			// it seems like this should be replaced with context, but that's really context for calling methods, not
			// necessarily for defining new methods
			funcNode := statement.(ast.FuncDecl)
			method := builtins.NewMethod(funcNode.Name.Name, func(args ...builtins.Value) (builtins.Value, error) {
				return nil, nil
			})
			returnValue = method
			vm.ObjectSpace["Kernel"].AddPrivateMethod(method)
		case ast.SimpleString:
			returnValue = builtins.NewString(statement.(ast.SimpleString).Value)
		case ast.InterpolatedString:
			returnValue = builtins.NewString(statement.(ast.InterpolatedString).Value)
		case ast.Boolean:
			if statement.(ast.Boolean).Value {
				returnValue = builtins.NewTrueClass().(builtins.Class).New()
			} else {
				returnValue = builtins.NewFalseClass().(builtins.Class).New()
			}
		case ast.GlobalVariable:
			returnValue = vm.Globals[statement.(ast.GlobalVariable).Name]
		case ast.ConstantInt:
			returnValue = builtins.NewInt(statement.(ast.ConstantInt).Value)
		case ast.ConstantFloat:
			returnValue = builtins.NewFloat(statement.(ast.ConstantFloat).Value)
		case ast.Symbol:
			name := statement.(ast.Symbol).Name
			maybe, ok := vm.KnownSymbols[name]
			if !ok {
				returnValue = builtins.NewSymbol(name)
				vm.KnownSymbols[name] = returnValue
			} else {
				returnValue = maybe
			}
		case ast.BareReference:
			name := statement.(ast.BareReference).Name
			maybe, ok := vm.ObjectSpace[name]
			if ok {
				returnValue = maybe
			} else {
				returnErr = builtins.NewNameError(name, context.String(), context.Class().String())
			}
		case ast.CallExpression:
			var method builtins.Method
			callExpr := statement.(ast.CallExpression)

			var target = context
			if callExpr.Target != nil {
				target = vm.ObjectSpace[callExpr.Target.(ast.BareReference).Name]
			}

			if target == nil {
				panic("could not find: " + callExpr.Target.(ast.BareReference).Name)
			}
			method, err := target.Method(callExpr.Func.Name)

			if err != nil {
				err := builtins.NewNameError(callExpr.Func.Name, target.String(), target.Class().String())
				return nil, err
			}

			args := []builtins.Value{}
			for _, astArgument := range callExpr.Args {
				arg, err := vm.executeWithContext([]ast.Node{astArgument}, context)
				if err != nil {
					return nil, err
				}

				args = append(args, arg)
			}

			returnValue, returnErr = method.Execute(args...)
		case ast.Assignment:
			assignment := statement.(ast.Assignment)
			returnValue, err := vm.executeWithContext([]ast.Node{assignment.RHS}, context)
			if err != nil {
				return nil, err
			}

			switch assignment.LHS.(type) {
			case ast.BareReference:
				ref := assignment.LHS.(ast.BareReference)
				vm.ObjectSpace[ref.Name] = returnValue
			case ast.GlobalVariable:
				globalVar := assignment.LHS.(ast.GlobalVariable)
				vm.Globals[globalVar.Name] = returnValue
			default:
				panic(fmt.Sprintf("unimplemented assignment failure: %#v", assignment.LHS))
			}

		case ast.FileNameConstReference:
			returnValue = builtins.NewString(vm.currentFilename)
		case ast.Begin:
			begin := statement.(ast.Begin)
			_, err := vm.executeWithContext(begin.Body, context)

			if err != nil {
				rubyErr := err.(builtins.Value)
				for _, rescue := range begin.Rescue {
					r := rescue.(ast.Rescue)
					if r.Exception.Class.Name == rubyErr.String() {
						_, err = vm.executeWithContext(r.Body, context)
						if err == nil {
							break
						}
					}
				}
			}

			if err != nil {
				returnErr = err
			}
		default:
			panic(fmt.Sprintf("handled unknown statement type: %T:\n\t\n => %#v\n", statement, statement))
		}
	}

	return returnValue, returnErr
}
<commit_msg>Kernel#require returns an error<commit_after>package vm

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/grubby/grubby/ast"
	"github.com/grubby/grubby/interpreter/vm/builtins"
	"github.com/grubby/grubby/parser"
)

type vm struct {
	currentFilename string
	ObjectSpace     map[string]builtins.Value
	Globals         map[string]builtins.Value
	KnownSymbols    map[string]builtins.Value
}

type VM interface {
	Run(string) (builtins.Value, error)
	Get(string) (builtins.Value, error)
	MustGet(string) builtins.Value

	Set(string, builtins.Value)

	Symbols() map[string]builtins.Value
}

func NewVM(name string) VM {
	vm := &vm{
		currentFilename: name,
		Globals:         make(map[string]builtins.Value),
		ObjectSpace:     make(map[string]builtins.Value),
		KnownSymbols:    make(map[string]builtins.Value),
	}

	loadPath := builtins.NewArrayClass().(builtins.Class).New()
	vm.Globals["$LOAD_PATH"] = loadPath
	vm.Globals["$:"] = loadPath // FIXME: add a test that these are the same object

	objectClass := builtins.NewGlobalObjectClass()
	vm.ObjectSpace["Object"] = objectClass
	vm.ObjectSpace["Kernel"] = builtins.NewGlobalKernelClass()
	vm.ObjectSpace["File"] = builtins.NewFileClass()
	vm.ObjectSpace["ARGV"] = builtins.NewArrayClass().(builtins.Class).New()
	vm.ObjectSpace["Process"] = builtins.NewProcessClass()

	main := objectClass.(builtins.Class).New()
	main.AddMethod(builtins.NewMethod("to_s", func(args ...builtins.Value) (builtins.Value, error) {
		return builtins.NewString("main"), nil
	}))
	main.AddMethod(builtins.NewMethod("require", func(args ...builtins.Value) (builtins.Value, error) {
		fileName := args[0].(*builtins.StringValue).String()
		if fileName == "rubygems" {
			// don't "require 'rubygems'"
			return builtins.NewFalseClass().(builtins.Class).New(), nil
		}

		for _, pathStr := range loadPath.(*builtins.Array).Members() {
			path := pathStr.(*builtins.StringValue)
			fullPath := filepath.Join(path.String(), fileName+".rb")
			file, err := os.Open(fullPath)
			if err != nil {
				continue
			}

			contents, err := ioutil.ReadAll(file)

			if err == nil {
				originalName := vm.currentFilename
				defer func() {
					vm.currentFilename = originalName
				}()

				vm.currentFilename = file.Name()
				_, rubyErr := vm.Run(string(contents))
				return builtins.NewTrueClass().(builtins.Class).New(), rubyErr
			}
		}

		err := fmt.Sprintf("LoadError: cannot load such file -- %s", fileName)
		return nil, builtins.NewLoadError(err)

	}))
	main.AddMethod(builtins.NewMethod("puts", func(args ...builtins.Value) (builtins.Value, error) {
		for _, arg := range args {
			os.Stdout.Write([]byte(arg.String() + "\n"))
		}

		return nil, nil
	}))

	vm.ObjectSpace["main"] = main

	return vm
}

func (vm *vm) MustGet(key string) builtins.Value {
	val, ok := vm.ObjectSpace[key]
	if ok {
		return val
	}

	val, ok = vm.Globals[key]
	if ok {
		return val
	}

	return nil
}

func (vm *vm) Get(key string) (builtins.Value, error) {
	val, ok := vm.ObjectSpace[key]
	if ok {
		return val, nil
	}

	val, ok = vm.Globals[key]
	if ok {
		return val, nil
	}

	return nil, errors.New(fmt.Sprintf("'%s' is undefined", key))
}

func (vm *vm) Set(key string, value builtins.Value) {
	vm.ObjectSpace[key] = value
}

func (vm *vm) Symbols() map[string]builtins.Value {
	return vm.KnownSymbols
}

type ParseError struct{}

func NewParseError() *ParseError {
	return &ParseError{}
}

func (err *ParseError) Error() string {
	return "parse error"
}

func (vm *vm) Run(input string) (builtins.Value, error) {
	lexer := parser.NewLexer(input)
	result := parser.RubyParse(lexer)
	if result != 0 {
		return nil, NewParseError()
	}

	main := vm.ObjectSpace["main"]
	return vm.executeWithContext(parser.Statements, main)
}

func (vm *vm) executeWithContext(statements []ast.Node, context builtins.Value) (builtins.Value, error) {
	var (
		returnValue builtins.Value
		returnErr   error
	)
	for _, statement := range statements {
		switch statement.(type) {
		case ast.IfBlock:
			truthy := false
			ifBlock := statement.(ast.IfBlock)
			switch ifBlock.Condition.(type) {
			case ast.Boolean:
				truthy = ifBlock.Condition.(ast.Boolean).Value
			case ast.BareReference:
				truthy = ifBlock.Condition.(ast.BareReference).Name == "nil"
			default:
				truthy = true
			}

			if truthy {
				returnValue, returnErr = vm.executeWithContext(ifBlock.Body, context)
			} else {
				returnValue, returnErr = vm.executeWithContext(ifBlock.Else, context)
			}
		case ast.FuncDecl:
			// FIXME: assumes for now this will only ever be at the top level
			// it seems like this should be replaced with context, but that's really context for calling methods, not
			// necessarily for defining new methods
			funcNode := statement.(ast.FuncDecl)
			method := builtins.NewMethod(funcNode.Name.Name, func(args ...builtins.Value) (builtins.Value, error) {
				return nil, nil
			})
			returnValue = method
			vm.ObjectSpace["Kernel"].AddPrivateMethod(method)
		case ast.SimpleString:
			returnValue = builtins.NewString(statement.(ast.SimpleString).Value)
		case ast.InterpolatedString:
			returnValue = builtins.NewString(statement.(ast.InterpolatedString).Value)
		case ast.Boolean:
			if statement.(ast.Boolean).Value {
				returnValue = builtins.NewTrueClass().(builtins.Class).New()
			} else {
				returnValue = builtins.NewFalseClass().(builtins.Class).New()
			}
		case ast.GlobalVariable:
			returnValue = vm.Globals[statement.(ast.GlobalVariable).Name]
		case ast.ConstantInt:
			returnValue = builtins.NewInt(statement.(ast.ConstantInt).Value)
		case ast.ConstantFloat:
			returnValue = builtins.NewFloat(statement.(ast.ConstantFloat).Value)
		case ast.Symbol:
			name := statement.(ast.Symbol).Name
			maybe, ok := vm.KnownSymbols[name]
			if !ok {
				returnValue = builtins.NewSymbol(name)
				vm.KnownSymbols[name] = returnValue
			} else {
				returnValue = maybe
			}
		case ast.BareReference:
			name := statement.(ast.BareReference).Name
			maybe, ok := vm.ObjectSpace[name]
			if ok {
				returnValue = maybe
			} else {
				returnErr = builtins.NewNameError(name, context.String(), context.Class().String())
			}
		case ast.CallExpression:
			var method builtins.Method
			callExpr := statement.(ast.CallExpression)

			var target = context
			if callExpr.Target != nil {
				target = vm.ObjectSpace[callExpr.Target.(ast.BareReference).Name]
			}

			if target == nil {
				panic("could not find: " + callExpr.Target.(ast.BareReference).Name)
			}
			method, err := target.Method(callExpr.Func.Name)

			if err != nil {
				err := builtins.NewNameError(callExpr.Func.Name, target.String(), target.Class().String())
				return nil, err
			}

			args := []builtins.Value{}
			for _, astArgument := range callExpr.Args {
				arg, err := vm.executeWithContext([]ast.Node{astArgument}, context)
				if err != nil {
					return nil, err
				}

				args = append(args, arg)
			}

			returnValue, returnErr = method.Execute(args...)
		case ast.Assignment:
			assignment := statement.(ast.Assignment)
			returnValue, err := vm.executeWithContext([]ast.Node{assignment.RHS}, context)
			if err != nil {
				return nil, err
			}

			switch assignment.LHS.(type) {
			case ast.BareReference:
				ref := assignment.LHS.(ast.BareReference)
				vm.ObjectSpace[ref.Name] = returnValue
			case ast.GlobalVariable:
				globalVar := assignment.LHS.(ast.GlobalVariable)
				vm.Globals[globalVar.Name] = returnValue
			default:
				panic(fmt.Sprintf("unimplemented assignment failure: %#v", assignment.LHS))
			}

		case ast.FileNameConstReference:
			returnValue = builtins.NewString(vm.currentFilename)
		case ast.Begin:
			begin := statement.(ast.Begin)
			_, err := vm.executeWithContext(begin.Body, context)

			if err != nil {
				rubyErr := err.(builtins.Value)
				for _, rescue := range begin.Rescue {
					r := rescue.(ast.Rescue)
					if r.Exception.Class.Name == rubyErr.String() {
						_, err = vm.executeWithContext(r.Body, context)
						if err == nil {
							break
						}
					}
				}
			}

			if err != nil {
				returnErr = err
			}
		default:
			panic(fmt.Sprintf("handled unknown statement type: %T:\n\t\n => %#v\n", statement, statement))
		}
	}

	return returnValue, returnErr
}
<|endoftext|>


<commit_before>/* RPC with a pool of providers each connected via a web-socket. */
package wsrpcpool

// The pool server module

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"golang.org/x/net/websocket"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
)

/* PoolServer is used to listen on a set of web-socket URLs for RPC
providers. */
type PoolServer struct {
	Server http.Server
	// Provider name to call channel map
	PoolMap map[string]chan *rpc.Call
	// Default call channel
	DefaultPool chan *rpc.Call
	// Used to signal the pool is listening for incoming connections
	Listening <-chan struct{}
	// Used to signal the pool is listening for incoming connections (pool side)
	listening chan struct{}
	// Used to signal the pool to stop
	stop chan struct{}
	// Used to return the error on close
	errc chan error
	// Path to call channel map
	pathMap map[string]chan *rpc.Call
}

var (
	// ErrNoDefaultPool signals that provider isn't found and there is no default pool
	ErrNoDefaultPool = errors.New("No default path is bound")
	// ErrNoCertsParsed signals that no SSL certificates were found in the given file
	ErrNoCertsParsed = errors.New("No certificates parsed")
)

/* NewPool returns a plain PoolServer instance. */
func NewPool() *PoolServer {
	listening := make(chan struct{}, 1)
	return &PoolServer{
		Listening: listening,
		listening: listening,
		stop:      make(chan struct{}),
		errc:      make(chan error, 1),
	}
}

/* NewPoolTLS returns a PoolServer instance equipped with the given
SSL certificate. */
func NewPoolTLS(certfile, keyfile string) (*PoolServer, error) {
	pool := NewPool()
	if err := pool.AppendCertificate(certfile, keyfile); err != nil {
		return nil, err
	}
	return pool, nil
}

/* NewPoolTLSAuth returns a PoolServer instance equipped with the given
SSL certificate and a root CA certificates for client authentication. */
func NewPoolTLSAuth(certfile, keyfile string, clientCAs ...string) (*PoolServer, error) {
	pool, err := NewPoolTLS(certfile, keyfile)
	if err != nil {
		return nil, err
	}
	err = pool.AppendClientCAs(clientCAs...)
	if err != nil {
		return nil, err
	}
	return pool, err
}

/* AppendCertificate appends an SSL certificate to the set of server
certificates loading it from the pair of public certificate and private
key files. */
func (pool *PoolServer) AppendCertificate(certfile, keyfile string) error {
	if pool.Server.TLSConfig == nil {
		pool.Server.TLSConfig = &tls.Config{}
	}
	return appendCertificate(pool.Server.TLSConfig, certfile, keyfile)
}

/* appendCertificate appends an SSL certificate to the given tls.Config
loading it from the pair of public certificate and private key files. */
func appendCertificate(tlsConfig *tls.Config, certfile, keyfile string) error {
	cert, err := tls.LoadX509KeyPair(certfile, keyfile)
	if err != nil {
		return err
	}
	tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
	tlsConfig.BuildNameToCertificate()
	return nil
}

/* AppendClientCAs appends the given SSL root CA certificate files to the
set of client CAs to verify client connections against. */
func (pool *PoolServer) AppendClientCAs(clientCAs ...string) error {
	if len(clientCAs) == 0 {
		return nil
	}
	if pool.Server.TLSConfig == nil {
		pool.Server.TLSConfig = &tls.Config{}
	}
	if pool.Server.TLSConfig.ClientCAs == nil {
		pool.Server.TLSConfig.ClientCAs = x509.NewCertPool()
	}
	err := appendCAs(pool.Server.TLSConfig.ClientCAs, clientCAs...)
	if err == nil {
		pool.Server.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
	}
	return err
}

/* appendCAs appends the given SSL root CA certificate files to the
given CA pool. */
func appendCAs(caPool *x509.CertPool, caCerts ...string) error {
	for _, caFile := range caCerts {
		caCert, err := ioutil.ReadFile(caFile)
		if err != nil {
			return err
		}
		if !caPool.AppendCertsFromPEM(caCert) {
			return ErrNoCertsParsed
		}
	}
	return nil
}

/* invoke passes the given call to the client. */
func invoke(client *rpc.Client, call *rpc.Call) *rpc.Call {
	return client.Go(call.ServiceMethod, call.Args, call.Reply, call.Done)
}

/* handle returns the websocket.Handler that the passes calls from the
given channel over a websocket connection. */
func handle(callIn <-chan *rpc.Call) websocket.Handler {
	return websocket.Handler(func(ws *websocket.Conn) {
		client := jsonrpc.NewClient(ws)
		for c := range callIn {
			invoke(client, c)
		}
		client.Close()
	})
}

/* Bind associates the given path with the set of remote providers or
makes it the default path if no object provider names given. */
func (pool *PoolServer) Bind(path string, providers ...string) {
	if pool.Server.Handler == nil {
		pool.Server.Handler = http.NewServeMux()
	}
	mux := pool.Server.Handler.(*http.ServeMux)
	if pool.pathMap == nil {
		pool.pathMap = make(map[string]chan *rpc.Call)
	}
	callIn := pool.pathMap[path]
	if callIn == nil {
		callIn = make(chan *rpc.Call)
		pool.pathMap[path] = callIn
	}
	if len(providers) > 0 {
		if pool.PoolMap == nil {
			pool.PoolMap = make(map[string]chan *rpc.Call)
		}
		for _, name := range providers {
			pool.PoolMap[name] = callIn
		}
	} else {
		pool.DefaultPool = callIn
	}
	mux.Handle(path, handle(callIn))
}

/* listen returns the active listener for the current pool config
and an error if any. It also send a signal over the "listening"
channel. */
func (pool *PoolServer) listen() (net.Listener, error) {
	l, err := net.Listen("tcp", pool.Server.Addr)
	if err != nil {
		return nil, err
	}
	pool.listening <- struct{}{}
	close(pool.listening)
	return l, nil
}

/* use uses the given listener waiting for a signal on
the "stop" channel. */
func (pool *PoolServer) use(l net.Listener) error {
	go func() {
		err := pool.Server.Serve(l)
		select {
		case <-pool.stop: // FIXME: Check error code
		default:
			pool.errc <- err
		}
		close(pool.errc)
	}()

	select {
	case err := <-pool.errc:
		return err
	case <-pool.stop:
		return l.Close()
	}
}

/* ListenAndUse listens the given (or configured if "" is given) address
([host]:port) with no SSL encryption. */
func (pool *PoolServer) ListenAndUse(addr string) error {
	if addr != "" {
		pool.Server.Addr = addr
	}
	l, err := pool.listen()
	if err != nil {
		return err
	}
	return pool.use(l)
}

/* ListenAndUseTLS listens the listens the given (or configured if "" is given) address
([host]:port) with SSL encryption on. */
func (pool *PoolServer) ListenAndUseTLS(addr string) error {
	if addr != "" {
		pool.Server.Addr = addr
	}
	l, err := pool.listen()
	if err != nil {
		return err
	}
	return pool.use(tls.NewListener(l, pool.Server.TLSConfig))
}

/* Close closes the pool listener. */
func (pool *PoolServer) Close() error {
	close(pool.stop)
	return <-pool.errc
}

/* Go invokes the given remote function asynchronously. The name of the
provider is first searched in the PoolMap and the DefaultPool is used
if it isn't there. If done is nil, a new channel is allocated and
passed in the return value. See net/rpc package for details. */
func (pool *PoolServer) Go(provider, funcName string, args interface{}, reply interface{}, done chan *rpc.Call) (*rpc.Call, error) {
	callIn := pool.PoolMap[provider]
	if callIn == nil {
		callIn = pool.DefaultPool
	}
	if callIn == nil {
		return nil, ErrNoDefaultPool
	}

	call := &rpc.Call{
		ServiceMethod: provider + "." + funcName,
		Args:          args,
		Reply:         reply,
	}
	if done == nil {
		done = make(chan *rpc.Call, 1)
	}
	call.Done = done

	callIn <- call
	return call, nil
}

/* Call invokes the given remote function and waits for it to complete,
returning its error status. */
func (pool *PoolServer) Call(provider, funcName string, args interface{}, reply interface{}) error {
	if call, err := pool.Go(provider, funcName, args, reply, nil); err == nil {
		call = <-call.Done
		return call.Error
	} else {
		return err
	}
}
<commit_msg>Close the connection on I/O error<commit_after>/* RPC with a pool of providers each connected via a web-socket. */
package wsrpcpool

// The pool server module

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"golang.org/x/net/websocket"
	"io/ioutil"
	"net"
	"net/http"
	"net/rpc"
	"net/rpc/jsonrpc"
)

/* PoolServer is used to listen on a set of web-socket URLs for RPC
providers. */
type PoolServer struct {
	Server http.Server
	// Provider name to call channel map
	PoolMap map[string]chan *rpc.Call
	// Default call channel
	DefaultPool chan *rpc.Call
	// Used to signal the pool is listening for incoming connections
	Listening <-chan struct{}
	// Used to signal the pool is listening for incoming connections (pool side)
	listening chan struct{}
	// Used to signal the pool to stop
	stop chan struct{}
	// Used to return the error on close
	errc chan error
	// Path to call channel map
	pathMap map[string]chan *rpc.Call
}

var (
	// ErrNoDefaultPool signals that provider isn't found and there is no default pool
	ErrNoDefaultPool = errors.New("No default path is bound")
	// ErrNoCertsParsed signals that no SSL certificates were found in the given file
	ErrNoCertsParsed = errors.New("No certificates parsed")
)

/* NewPool returns a plain PoolServer instance. */
func NewPool() *PoolServer {
	listening := make(chan struct{}, 1)
	return &PoolServer{
		Listening: listening,
		listening: listening,
		stop:      make(chan struct{}),
		errc:      make(chan error, 1),
	}
}

/* NewPoolTLS returns a PoolServer instance equipped with the given
SSL certificate. */
func NewPoolTLS(certfile, keyfile string) (*PoolServer, error) {
	pool := NewPool()
	if err := pool.AppendCertificate(certfile, keyfile); err != nil {
		return nil, err
	}
	return pool, nil
}

/* NewPoolTLSAuth returns a PoolServer instance equipped with the given
SSL certificate and a root CA certificates for client authentication. */
func NewPoolTLSAuth(certfile, keyfile string, clientCAs ...string) (*PoolServer, error) {
	pool, err := NewPoolTLS(certfile, keyfile)
	if err != nil {
		return nil, err
	}
	err = pool.AppendClientCAs(clientCAs...)
	if err != nil {
		return nil, err
	}
	return pool, err
}

/* AppendCertificate appends an SSL certificate to the set of server
certificates loading it from the pair of public certificate and private
key files. */
func (pool *PoolServer) AppendCertificate(certfile, keyfile string) error {
	if pool.Server.TLSConfig == nil {
		pool.Server.TLSConfig = &tls.Config{}
	}
	return appendCertificate(pool.Server.TLSConfig, certfile, keyfile)
}

/* appendCertificate appends an SSL certificate to the given tls.Config
loading it from the pair of public certificate and private key files. */
func appendCertificate(tlsConfig *tls.Config, certfile, keyfile string) error {
	cert, err := tls.LoadX509KeyPair(certfile, keyfile)
	if err != nil {
		return err
	}
	tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
	tlsConfig.BuildNameToCertificate()
	return nil
}

/* AppendClientCAs appends the given SSL root CA certificate files to the
set of client CAs to verify client connections against. */
func (pool *PoolServer) AppendClientCAs(clientCAs ...string) error {
	if len(clientCAs) == 0 {
		return nil
	}
	if pool.Server.TLSConfig == nil {
		pool.Server.TLSConfig = &tls.Config{}
	}
	if pool.Server.TLSConfig.ClientCAs == nil {
		pool.Server.TLSConfig.ClientCAs = x509.NewCertPool()
	}
	err := appendCAs(pool.Server.TLSConfig.ClientCAs, clientCAs...)
	if err == nil {
		pool.Server.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
	}
	return err
}

/* appendCAs appends the given SSL root CA certificate files to the
given CA pool. */
func appendCAs(caPool *x509.CertPool, caCerts ...string) error {
	for _, caFile := range caCerts {
		caCert, err := ioutil.ReadFile(caFile)
		if err != nil {
			return err
		}
		if !caPool.AppendCertsFromPEM(caCert) {
			return ErrNoCertsParsed
		}
	}
	return nil
}

/* invoke passes the given call to the client. */
func invoke(client *rpc.Client, call *rpc.Call) *rpc.Call {
	return client.Go(call.ServiceMethod, call.Args, call.Reply, call.Done)
}

/* connObserver used to observe I/O errors in a websocket connection */
type connObserver struct {
	*websocket.Conn
	ioError chan error
}

/* reportError sends the given error over the ioError channel
if there is a free slot available and do nothing otherwise
(i.e. non blocking). */
func (conn *connObserver) reportError(err error) {
	select {
	case conn.ioError <- err:
	default:
	}
}

/* Read implements io.Reader. */
func (conn *connObserver) Read(p []byte) (n int, err error) {
	n, err = conn.Conn.Read(p)
	if err != nil {
		conn.reportError(err)
	}
	return
}

/* Write implements io.Writer. */
func (conn *connObserver) Write(p []byte) (n int, err error) {
	n, err = conn.Conn.Write(p)
	if err != nil {
		conn.reportError(err)
	}
	return
}

/* handle returns the websocket.Handler that the passes calls from the
given channel over a websocket connection. */
func handle(callIn <-chan *rpc.Call) websocket.Handler {
	return websocket.Handler(func(ws *websocket.Conn) {
		conn := &connObserver{ws, make(chan error, 10)}
		client := jsonrpc.NewClient(conn)
		for {
			select {
			case c := <-callIn:
				invoke(client, c)
			case <-conn.ioError:
				break
			}
		}
		client.Close()
	})
}

/* Bind associates the given path with the set of remote providers or
makes it the default path if no object provider names given. */
func (pool *PoolServer) Bind(path string, providers ...string) {
	if pool.Server.Handler == nil {
		pool.Server.Handler = http.NewServeMux()
	}
	mux := pool.Server.Handler.(*http.ServeMux)
	if pool.pathMap == nil {
		pool.pathMap = make(map[string]chan *rpc.Call)
	}
	callIn := pool.pathMap[path]
	if callIn == nil {
		callIn = make(chan *rpc.Call)
		pool.pathMap[path] = callIn
	}
	if len(providers) > 0 {
		if pool.PoolMap == nil {
			pool.PoolMap = make(map[string]chan *rpc.Call)
		}
		for _, name := range providers {
			pool.PoolMap[name] = callIn
		}
	} else {
		pool.DefaultPool = callIn
	}
	mux.Handle(path, handle(callIn))
}

/* listen returns the active listener for the current pool config
and an error if any. It also send a signal over the "listening"
channel. */
func (pool *PoolServer) listen() (net.Listener, error) {
	l, err := net.Listen("tcp", pool.Server.Addr)
	if err != nil {
		return nil, err
	}
	pool.listening <- struct{}{}
	close(pool.listening)
	return l, nil
}

/* use uses the given listener waiting for a signal on
the "stop" channel. */
func (pool *PoolServer) use(l net.Listener) error {
	go func() {
		err := pool.Server.Serve(l)
		select {
		case <-pool.stop: // FIXME: Check error code
		default:
			pool.errc <- err
		}
		close(pool.errc)
	}()

	select {
	case err := <-pool.errc:
		return err
	case <-pool.stop:
		return l.Close()
	}
}

/* ListenAndUse listens the given (or configured if "" is given) address
([host]:port) with no SSL encryption. */
func (pool *PoolServer) ListenAndUse(addr string) error {
	if addr != "" {
		pool.Server.Addr = addr
	}
	l, err := pool.listen()
	if err != nil {
		return err
	}
	return pool.use(l)
}

/* ListenAndUseTLS listens the listens the given (or configured if "" is given) address
([host]:port) with SSL encryption on. */
func (pool *PoolServer) ListenAndUseTLS(addr string) error {
	if addr != "" {
		pool.Server.Addr = addr
	}
	l, err := pool.listen()
	if err != nil {
		return err
	}
	return pool.use(tls.NewListener(l, pool.Server.TLSConfig))
}

/* Close closes the pool listener. */
func (pool *PoolServer) Close() error {
	close(pool.stop)
	return <-pool.errc
}

/* Go invokes the given remote function asynchronously. The name of the
provider is first searched in the PoolMap and the DefaultPool is used
if it isn't there. If done is nil, a new channel is allocated and
passed in the return value. See net/rpc package for details. */
func (pool *PoolServer) Go(provider, funcName string, args interface{}, reply interface{}, done chan *rpc.Call) (*rpc.Call, error) {
	callIn := pool.PoolMap[provider]
	if callIn == nil {
		callIn = pool.DefaultPool
	}
	if callIn == nil {
		return nil, ErrNoDefaultPool
	}

	call := &rpc.Call{
		ServiceMethod: provider + "." + funcName,
		Args:          args,
		Reply:         reply,
	}
	if done == nil {
		done = make(chan *rpc.Call, 1)
	}
	call.Done = done

	callIn <- call
	return call, nil
}

/* Call invokes the given remote function and waits for it to complete,
returning its error status. */
func (pool *PoolServer) Call(provider, funcName string, args interface{}, reply interface{}) error {
	if call, err := pool.Go(provider, funcName, args, reply, nil); err == nil {
		call = <-call.Done
		return call.Error
	} else {
		return err
	}
}
<|endoftext|>


<commit_before>// The charset package implements translation between character sets.
// It uses Unicode as the intermediate representation.
// Because it can be large, the character set data is separated
// from the charset package. It can be embedded in the Go
// executable by importing the data package:
//
//	import _ "code.google.com/p/go-charset/data"
//
// It can also made available in a data directory (by settting CharsetDir).
package charset

import (
	"io"
	"strings"
	"unicode/utf8"
)

// Charset holds information about a given character set.
type Charset struct {
	Name    string   // Canonical name of character set.
	Aliases []string // Known aliases.
	Desc    string   // Description.
	NoFrom  bool     // Not possible to translate from this charset.
	NoTo    bool     // Not possible to translate to this charset.
}

// Translator represents a character set converter.
// The Translate method translates the given data,
// and returns the number of bytes of data consumed,
// a slice containing the converted data (which may be
// overwritten on the next call to Translate), and any
// conversion error. If eof is true, the data represents
// the final bytes of the input.
type Translator interface {
	Translate(data []byte, eof bool) (n int, cdata []byte, err error)
}

// A Factory can be used to make character set translators.
type Factory interface {
	// TranslatorFrom creates a translator that will translate from the named character
	// set to UTF-8.
	TranslatorFrom(name string) (Translator, error) // Create a Translator from this character set to.

	// TranslatorTo creates a translator that will translate from UTF-8 to the named character set.
	TranslatorTo(name string) (Translator, error) // Create a Translator To this character set.

	// Names returns all the character set names accessibile through the factory.
	Names() []string

	// Info returns information on the named character set. It returns nil if the
	// factory doesn't recognise the given name.
	Info(name string) *Charset
}

var factories = []Factory{localFactory{}}

// Register registers a new Factory which will be consulted when NewReader
// or NewWriter needs a character set translator for a given name.
func Register(factory Factory) {
	factories = append(factories, factory)
}

// NewReader returns a new Reader that translates from the named
// character set to UTF-8 as it reads r.
func NewReader(charset string, r io.Reader) (io.Reader, error) {
	tr, err := TranslatorFrom(charset)
	if err != nil {
		return nil, err
	}
	return NewTranslatingReader(r, tr), nil
}

// NewWriter returns a new WriteCloser writing to w.  It converts writes
// of UTF-8 text into writes on w of text in the named character set.
// The Close is necessary to flush any remaining partially translated
// characters to the output.
func NewWriter(charset string, w io.Writer) (io.WriteCloser, error) {
	tr, err := TranslatorTo(charset)
	if err != nil {
		return nil, err
	}
	return NewTranslatingWriter(w, tr), nil
}

// Info returns information about a character set, or nil
// if the character set is not found.
func Info(name string) *Charset {
	for _, f := range factories {
		if info := f.Info(name); info != nil {
			return info
		}
	}
	return nil
}

// Names returns the canonical names of all supported character sets, in alphabetical order.
func Names() []string {
	// TODO eliminate duplicates
	var names []string
	for _, f := range factories {
		names = append(names, f.Names()...)
	}
	return names
}

// TranslatorFrom returns a translator that will translate from
// the named character set to UTF-8.
func TranslatorFrom(charset string) (Translator, error) {
	var err error
	var tr Translator
	for _, f := range factories {
		tr, err = f.TranslatorFrom(charset)
		if err == nil {
			break
		}
	}
	if tr == nil {
		return nil, err
	}
	return tr, nil
}

// TranslatorTo returns a translator that will translate from UTF-8
// to the named character set.
func TranslatorTo(charset string) (Translator, error) {
	var err error
	var tr Translator
	for _, f := range factories {
		tr, err = f.TranslatorTo(charset)
		if err == nil {
			break
		}
	}
	if tr == nil {
		return nil, err
	}
	return tr, nil
}

func normalizedChar(c rune) rune {
	switch {
	case c >= 'A' && c <= 'Z':
		c = c - 'A' + 'a'
	case c == '_':
		c = '-'
	}
	return c
}

// NormalisedName returns s with all Roman capitals
// mapped to lower case, and '_' mapped to '-'
func NormalizedName(s string) string {
	return strings.Map(normalizedChar, s)
}

type translatingWriter struct {
	w   io.Writer
	tr  Translator
	buf []byte // unconsumed data from writer.
}

// NewTranslatingWriter returns a new WriteCloser writing to w.
// It passes the written bytes through the given Translator.
func NewTranslatingWriter(w io.Writer, tr Translator) io.WriteCloser {
	return &translatingWriter{w: w, tr: tr}
}

func (w *translatingWriter) Write(data []byte) (rn int, rerr error) {
	wdata := data
	if len(w.buf) > 0 {
		w.buf = append(w.buf, data...)
		wdata = w.buf
	}
	n, cdata, err := w.tr.Translate(wdata, false)
	if err != nil {
		// TODO
	}
	if n > 0 {
		_, err = w.w.Write(cdata)
		if err != nil {
			return 0, err
		}
	}
	w.buf = w.buf[:0]
	if n < len(wdata) {
		w.buf = append(w.buf, wdata[n:]...)
	}
	return len(data), nil
}

func (p *translatingWriter) Close() error {
	for {
		n, data, err := p.tr.Translate(p.buf, true)
		p.buf = p.buf[n:]
		if err != nil {
			// TODO
		}
		// If the Translator produces no data
		// at EOF, then assume that it never will.
		if len(data) == 0 {
			break
		}
		n, err = p.w.Write(data)
		if err != nil {
			return err
		}
		if n < len(data) {
			return io.ErrShortWrite
		}
		if len(p.buf) == 0 {
			break
		}
	}
	return nil
}

type translatingReader struct {
	r     io.Reader
	tr    Translator
	cdata []byte // unconsumed data from converter.
	rdata []byte // unconverted data from reader.
	err   error  // final error from reader.
}

// NewTranslatingReader returns a new Reader that
// translates data using the given Translator as it reads r.
func NewTranslatingReader(r io.Reader, tr Translator) io.Reader {
	return &translatingReader{r: r, tr: tr}
}

func (r *translatingReader) Read(buf []byte) (int, error) {
	for {
		if len(r.cdata) > 0 {
			n := copy(buf, r.cdata)
			r.cdata = r.cdata[n:]
			return n, nil
		}
		if r.err == nil {
			r.rdata = ensureCap(r.rdata, len(r.rdata)+len(buf))
			n, err := r.r.Read(r.rdata[len(r.rdata):cap(r.rdata)])
			// Guard against non-compliant Readers.
			if n == 0 && err == nil {
				err = io.EOF
			}
			r.rdata = r.rdata[0 : len(r.rdata)+n]
			r.err = err
		} else if len(r.rdata) == 0 {
			break
		}
		nc, cdata, cvterr := r.tr.Translate(r.rdata, r.err != nil)
		if cvterr != nil {
			// TODO
		}
		r.cdata = cdata

		// Ensure that we consume all bytes at eof
		// if the converter refuses them.
		if nc == 0 && r.err != nil {
			nc = len(r.rdata)
		}

		// Copy unconsumed data to the start of the rdata buffer.
		r.rdata = r.rdata[0:copy(r.rdata, r.rdata[nc:])]
	}
	return 0, r.err
}

// ensureCap returns s with a capacity of at least n bytes.
// If cap(s) < n, then it returns a new copy of s with the
// required capacity.
func ensureCap(s []byte, n int) []byte {
	if n <= cap(s) {
		return s
	}
	// logic adapted from appendslice1 in runtime
	m := cap(s)
	if m == 0 {
		m = n
	} else {
		for {
			if m < 1024 {
				m += m
			} else {
				m += m / 4
			}
			if m >= n {
				break
			}
		}
	}
	t := make([]byte, len(s), m)
	copy(t, s)
	return t
}

func appendRune(buf []byte, r rune) []byte {
	n := len(buf)
	buf = ensureCap(buf, n+utf8.UTFMax)
	nu := utf8.EncodeRune(buf[n:n+utf8.UTFMax], r)
	return buf[0 : n+nu]
}
<commit_msg>gofmt<commit_after>// The charset package implements translation between character sets.
// It uses Unicode as the intermediate representation.
// Because it can be large, the character set data is separated
// from the charset package. It can be embedded in the Go
// executable by importing the data package:
//
//	import _ "code.google.com/p/go-charset/data"
//
// It can also made available in a data directory (by settting CharsetDir).
package charset

import (
	"io"
	"strings"
	"unicode/utf8"
)

// Charset holds information about a given character set.
type Charset struct {
	Name    string   // Canonical name of character set.
	Aliases []string // Known aliases.
	Desc    string   // Description.
	NoFrom  bool     // Not possible to translate from this charset.
	NoTo    bool     // Not possible to translate to this charset.
}

// Translator represents a character set converter.
// The Translate method translates the given data,
// and returns the number of bytes of data consumed,
// a slice containing the converted data (which may be
// overwritten on the next call to Translate), and any
// conversion error. If eof is true, the data represents
// the final bytes of the input.
type Translator interface {
	Translate(data []byte, eof bool) (n int, cdata []byte, err error)
}

// A Factory can be used to make character set translators.
type Factory interface {
	// TranslatorFrom creates a translator that will translate from the named character
	// set to UTF-8.
	TranslatorFrom(name string) (Translator, error) // Create a Translator from this character set to.

	// TranslatorTo creates a translator that will translate from UTF-8 to the named character set.
	TranslatorTo(name string) (Translator, error) // Create a Translator To this character set.

	// Names returns all the character set names accessibile through the factory.
	Names() []string

	// Info returns information on the named character set. It returns nil if the
	// factory doesn't recognise the given name.
	Info(name string) *Charset
}

var factories = []Factory{localFactory{}}

// Register registers a new Factory which will be consulted when NewReader
// or NewWriter needs a character set translator for a given name.
func Register(factory Factory) {
	factories = append(factories, factory)
}

// NewReader returns a new Reader that translates from the named
// character set to UTF-8 as it reads r.
func NewReader(charset string, r io.Reader) (io.Reader, error) {
	tr, err := TranslatorFrom(charset)
	if err != nil {
		return nil, err
	}
	return NewTranslatingReader(r, tr), nil
}

// NewWriter returns a new WriteCloser writing to w.  It converts writes
// of UTF-8 text into writes on w of text in the named character set.
// The Close is necessary to flush any remaining partially translated
// characters to the output.
func NewWriter(charset string, w io.Writer) (io.WriteCloser, error) {
	tr, err := TranslatorTo(charset)
	if err != nil {
		return nil, err
	}
	return NewTranslatingWriter(w, tr), nil
}

// Info returns information about a character set, or nil
// if the character set is not found.
func Info(name string) *Charset {
	for _, f := range factories {
		if info := f.Info(name); info != nil {
			return info
		}
	}
	return nil
}

// Names returns the canonical names of all supported character sets, in alphabetical order.
func Names() []string {
	// TODO eliminate duplicates
	var names []string
	for _, f := range factories {
		names = append(names, f.Names()...)
	}
	return names
}

// TranslatorFrom returns a translator that will translate from
// the named character set to UTF-8.
func TranslatorFrom(charset string) (Translator, error) {
	var err error
	var tr Translator
	for _, f := range factories {
		tr, err = f.TranslatorFrom(charset)
		if err == nil {
			break
		}
	}
	if tr == nil {
		return nil, err
	}
	return tr, nil
}

// TranslatorTo returns a translator that will translate from UTF-8
// to the named character set.
func TranslatorTo(charset string) (Translator, error) {
	var err error
	var tr Translator
	for _, f := range factories {
		tr, err = f.TranslatorTo(charset)
		if err == nil {
			break
		}
	}
	if tr == nil {
		return nil, err
	}
	return tr, nil
}

func normalizedChar(c rune) rune {
	switch {
	case c >= 'A' && c <= 'Z':
		c = c - 'A' + 'a'
	case c == '_':
		c = '-'
	}
	return c
}

// NormalisedName returns s with all Roman capitals
// mapped to lower case, and '_' mapped to '-'
func NormalizedName(s string) string {
	return strings.Map(normalizedChar, s)
}

type translatingWriter struct {
	w   io.Writer
	tr  Translator
	buf []byte // unconsumed data from writer.
}

// NewTranslatingWriter returns a new WriteCloser writing to w.
// It passes the written bytes through the given Translator.
func NewTranslatingWriter(w io.Writer, tr Translator) io.WriteCloser {
	return &translatingWriter{w: w, tr: tr}
}

func (w *translatingWriter) Write(data []byte) (rn int, rerr error) {
	wdata := data
	if len(w.buf) > 0 {
		w.buf = append(w.buf, data...)
		wdata = w.buf
	}
	n, cdata, err := w.tr.Translate(wdata, false)
	if err != nil {
		// TODO
	}
	if n > 0 {
		_, err = w.w.Write(cdata)
		if err != nil {
			return 0, err
		}
	}
	w.buf = w.buf[:0]
	if n < len(wdata) {
		w.buf = append(w.buf, wdata[n:]...)
	}
	return len(data), nil
}

func (p *translatingWriter) Close() error {
	for {
		n, data, err := p.tr.Translate(p.buf, true)
		p.buf = p.buf[n:]
		if err != nil {
			// TODO
		}
		// If the Translator produces no data
		// at EOF, then assume that it never will.
		if len(data) == 0 {
			break
		}
		n, err = p.w.Write(data)
		if err != nil {
			return err
		}
		if n < len(data) {
			return io.ErrShortWrite
		}
		if len(p.buf) == 0 {
			break
		}
	}
	return nil
}

type translatingReader struct {
	r     io.Reader
	tr    Translator
	cdata []byte // unconsumed data from converter.
	rdata []byte // unconverted data from reader.
	err   error  // final error from reader.
}

// NewTranslatingReader returns a new Reader that
// translates data using the given Translator as it reads r.
func NewTranslatingReader(r io.Reader, tr Translator) io.Reader {
	return &translatingReader{r: r, tr: tr}
}

func (r *translatingReader) Read(buf []byte) (int, error) {
	for {
		if len(r.cdata) > 0 {
			n := copy(buf, r.cdata)
			r.cdata = r.cdata[n:]
			return n, nil
		}
		if r.err == nil {
			r.rdata = ensureCap(r.rdata, len(r.rdata)+len(buf))
			n, err := r.r.Read(r.rdata[len(r.rdata):cap(r.rdata)])
			// Guard against non-compliant Readers.
			if n == 0 && err == nil {
				err = io.EOF
			}
			r.rdata = r.rdata[0 : len(r.rdata)+n]
			r.err = err
		} else if len(r.rdata) == 0 {
			break
		}
		nc, cdata, cvterr := r.tr.Translate(r.rdata, r.err != nil)
		if cvterr != nil {
			// TODO
		}
		r.cdata = cdata

		// Ensure that we consume all bytes at eof
		// if the converter refuses them.
		if nc == 0 && r.err != nil {
			nc = len(r.rdata)
		}

		// Copy unconsumed data to the start of the rdata buffer.
		r.rdata = r.rdata[0:copy(r.rdata, r.rdata[nc:])]
	}
	return 0, r.err
}

// ensureCap returns s with a capacity of at least n bytes.
// If cap(s) < n, then it returns a new copy of s with the
// required capacity.
func ensureCap(s []byte, n int) []byte {
	if n <= cap(s) {
		return s
	}
	// logic adapted from appendslice1 in runtime
	m := cap(s)
	if m == 0 {
		m = n
	} else {
		for {
			if m < 1024 {
				m += m
			} else {
				m += m / 4
			}
			if m >= n {
				break
			}
		}
	}
	t := make([]byte, len(s), m)
	copy(t, s)
	return t
}

func appendRune(buf []byte, r rune) []byte {
	n := len(buf)
	buf = ensureCap(buf, n+utf8.UTFMax)
	nu := utf8.EncodeRune(buf[n:n+utf8.UTFMax], r)
	return buf[0 : n+nu]
}
<|endoftext|>


<commit_before>package dbase

import (
	"database/sql"

	"github.com/devinmcgloin/morph/src/env"
	"github.com/devinmcgloin/morph/src/schema"
	_ "github.com/go-sql-driver/mysql" // want sql drivers to init, work with the database/sql package.

	"log"
)

var DB *sql.DB

// SetDB returns a reference to a sql.DB object. It's best to keep these long lived.
func SetDB() *sql.DB {

	// Create the database handle, confirm driver is
	db, err := sql.Open("mysql", env.Getenv("DB_URL", "root:@/morph"))
	if err != nil {
		log.Fatal(err)
	}
	DB = db
	return db
}

func GetImg(pID string, db *sql.DB) schema.Img {

	var page schema.Img

	rows, err := db.Query(
		`
			SELECT p_title,
			       p_desc,
			       p_url,
			       p_fstop,
			       p_iso,
			       p_fov,
			       p_shutter_speed,
			       p_category
			FROM   photos
			WHERE  p_id = ?
			`, pID)

	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&page.Title, &page.Desc, &page.URL, &page.PhotoMeta.FStop,
			&page.PhotoMeta.ISO, &page.PhotoMeta.FOV, &page.PhotoMeta.ShutterSpeed, &page.Category)

		if err != nil {
			log.Fatal(err)
		}
		log.Println(page)
	}

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	return page
}

func AddImg(img schema.Img, db *sql.DB) {

	stmt, err := db.Prepare(
		`INSERT INTO photos
            (p_id,
						 p_title,
             p_desc,
             p_url,
             p_fstop,
             p_iso,
             p_fov,
             p_shutter_speed,
             p_category,
					   p_publish_date)
		VALUES      (?, ?, ?, ?, ?,
			           ?, ?, ?, ?, ?)`)

	if err != nil {
		log.Fatalf("db.Prepare failed %s", err)
	}

	res, err := stmt.Exec("NULL", img.Title, img.Desc, img.URL, img.PhotoMeta.FStop, img.PhotoMeta.ISO,
		img.PhotoMeta.FOV, img.PhotoMeta.ShutterSpeed, img.Category, "NULL")
	if err != nil {
		log.Fatal(err)
	}
	lastID, err := res.LastInsertId()
	if err != nil {
		log.Fatal(err)
	}
	rowCnt, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("ID = %d, affected = %d\n", lastID, rowCnt)
	stmt.Close()
}

func getCollection(collectionTag string, db *sql.DB) schema.ImgCollection {
	var collectionPage schema.ImgCollection

	return collectionPage
}

func GetAllImgs(db *sql.DB) schema.ImgCollection {
	var collectionPage schema.ImgCollection

	var page schema.Img

	rows, err := db.Query(
		`
			SELECT p_title,
			       p_desc,
			       p_url,
			       p_fstop,
			       p_iso,
			       p_fov,
			       p_shutter_speed,
			       p_category
			FROM   photos
			`)

	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&page.Title, &page.Desc, &page.URL, &page.PhotoMeta.FStop,
			&page.PhotoMeta.ISO, &page.PhotoMeta.FOV, &page.PhotoMeta.ShutterSpeed, &page.Category)

		if err != nil {
			log.Fatal(err)
		}
		collectionPage.Images = append(collectionPage.Images, page)
	}

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}

	collectionPage.NumImg = len(collectionPage.Images)
	collectionPage.Title = "Home"
	return collectionPage
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>logging db url<commit_after>package dbase

import (
	"database/sql"

	"github.com/devinmcgloin/morph/src/env"
	"github.com/devinmcgloin/morph/src/schema"
	_ "github.com/go-sql-driver/mysql" // want sql drivers to init, work with the database/sql package.

	"log"
)

var DB *sql.DB

// SetDB returns a reference to a sql.DB object. It's best to keep these long lived.
func SetDB() *sql.DB {
	log.Printf("DB_URL = %s", env.Getenv("DB_URL", "root:@/morph"))

	// Create the database handle, confirm driver is
	db, err := sql.Open("mysql", env.Getenv("DB_URL", "root:@/morph"))
	if err != nil {
		log.Fatal(err)
	}
	DB = db
	return db
}

func GetImg(pID string, db *sql.DB) schema.Img {

	var page schema.Img

	rows, err := db.Query(
		`
			SELECT p_title,
			       p_desc,
			       p_url,
			       p_fstop,
			       p_iso,
			       p_fov,
			       p_shutter_speed,
			       p_category
			FROM   photos
			WHERE  p_id = ?
			`, pID)

	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&page.Title, &page.Desc, &page.URL, &page.PhotoMeta.FStop,
			&page.PhotoMeta.ISO, &page.PhotoMeta.FOV, &page.PhotoMeta.ShutterSpeed, &page.Category)

		if err != nil {
			log.Fatal(err)
		}
		log.Println(page)
	}

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}
	return page
}

func AddImg(img schema.Img, db *sql.DB) {

	stmt, err := db.Prepare(
		`INSERT INTO photos
            (p_id,
						 p_title,
             p_desc,
             p_url,
             p_fstop,
             p_iso,
             p_fov,
             p_shutter_speed,
             p_category,
					   p_publish_date)
		VALUES      (?, ?, ?, ?, ?,
			           ?, ?, ?, ?, ?)`)

	if err != nil {
		log.Fatalf("db.Prepare failed %s", err)
	}

	res, err := stmt.Exec("NULL", img.Title, img.Desc, img.URL, img.PhotoMeta.FStop, img.PhotoMeta.ISO,
		img.PhotoMeta.FOV, img.PhotoMeta.ShutterSpeed, img.Category, "NULL")
	if err != nil {
		log.Fatal(err)
	}
	lastID, err := res.LastInsertId()
	if err != nil {
		log.Fatal(err)
	}
	rowCnt, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("ID = %d, affected = %d\n", lastID, rowCnt)
	stmt.Close()
}

func getCollection(collectionTag string, db *sql.DB) schema.ImgCollection {
	var collectionPage schema.ImgCollection

	return collectionPage
}

func GetAllImgs(db *sql.DB) schema.ImgCollection {
	var collectionPage schema.ImgCollection

	var page schema.Img

	rows, err := db.Query(
		`
			SELECT p_title,
			       p_desc,
			       p_url,
			       p_fstop,
			       p_iso,
			       p_fov,
			       p_shutter_speed,
			       p_category
			FROM   photos
			`)

	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	for rows.Next() {
		err := rows.Scan(&page.Title, &page.Desc, &page.URL, &page.PhotoMeta.FStop,
			&page.PhotoMeta.ISO, &page.PhotoMeta.FOV, &page.PhotoMeta.ShutterSpeed, &page.Category)

		if err != nil {
			log.Fatal(err)
		}
		collectionPage.Images = append(collectionPage.Images, page)
	}

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}

	collectionPage.NumImg = len(collectionPage.Images)
	collectionPage.Title = "Home"
	return collectionPage
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package ipfs

import (
	"errors"
	"github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core/coreunix"
	"github.com/ipfs/go-ipfs/importer/chunk"
	h "github.com/ipfs/go-ipfs/importer/helpers"
	ihelper "github.com/ipfs/go-ipfs/importer/helpers"
	"io"
	"path"
)

var addErr = errors.New(`Add directory failed`)

// Resursively add a directory to IPFS and return the root hash
func AddDirectory(ctx commands.Context, fpath string) (rootHash string, err error) {
	_, root := path.Split(fpath)
	args := []string{"add", "-r", fpath}
	req, cmd, err := NewRequest(ctx, args)
	if err != nil {
		return "", err
	}
	res := commands.NewResponse(req)
	cmd.PreRun(req)
	cmd.Run(req, res)
	for r := range res.Output().(<-chan interface{}) {
		if r.(*coreunix.AddedObject).Name == root {
			rootHash = r.(*coreunix.AddedObject).Hash
		}
	}
	cmd.PostRun(req, res)
	if res.Error() != nil {
		return "", res.Error()
	}
	if rootHash == "" {
		return "", addErr
	}
	return rootHash, nil
}

func AddFile(ctx commands.Context, fpath string) (string, error) {
	args := []string{"add", fpath}
	req, cmd, err := NewRequest(ctx, args)
	if err != nil {
		return "", err
	}
	res := commands.NewResponse(req)
	cmd.PreRun(req)
	cmd.Run(req, res)
	var fileHash string
	for r := range res.Output().(<-chan interface{}) {
		fileHash = r.(*coreunix.AddedObject).Hash
	}
	cmd.PostRun(req, res)
	if res.Error() != nil {
		return "", res.Error()
	}
	if fileHash == "" {
		return "", addErr
	}
	return fileHash, nil
}

func GetHashOfFile(ctx commands.Context, fpath string) (string, error) {
	args := []string{"add", "-n", fpath}
	req, cmd, err := NewRequest(ctx, args)
	if err != nil {
		return "", err
	}
	res := commands.NewResponse(req)
	cmd.PreRun(req)
	cmd.Run(req, res)
	var fileHash string
	for r := range res.Output().(<-chan interface{}) {
		fileHash = r.(*coreunix.AddedObject).Hash
	}
	cmd.PostRun(req, res)
	if res.Error() != nil {
		return "", res.Error()
	}
	if fileHash == "" {
		return "", addErr
	}
	return fileHash, nil
}

func GetHash(ctx commands.Context, reader io.Reader) (string, error) {
	nd, err := ctx.ConstructNode()
	if err != nil {
		return "", err
	}
	chnk, err := chunk.FromString(reader, "")
	if err != nil {
		return "", err
	}
	params := ihelper.DagBuilderParams{
		Maxlinks: ihelper.DefaultLinksPerBlock,
		Dagserv:  nd.DAG,
	}
	db := params.New(chnk)

	var offset uint64 = 0
	var root *h.UnixfsNode
	for level := 0; !db.Done(); level++ {

		nroot := db.NewUnixfsNode()
		db.SetPosInfo(nroot, 0)

		// add our old root as a child of the new root.
		if root != nil { // nil if it's the first node.
			if err := nroot.AddChild(root, db); err != nil {
				return "", err
			}
		}

		// fill it up.
		if err := fillNodeRec(db, nroot, level, offset); err != nil {
			return "", err
		}

		offset = nroot.FileSize()
		root = nroot

	}
	if root == nil {
		root = db.NewUnixfsNode()
	}
	n, err := root.GetDagNode()
	if err != nil {
		return "", err
	}
	return n.String(), nil
}

// fillNodeRec will fill the given node with data from the dagBuilders input
// source down to an indirection depth as specified by 'depth'
// it returns the total dataSize of the node, and a potential error
//
// warning: **children** pinned indirectly, but input node IS NOT pinned.
func fillNodeRec(db *h.DagBuilderHelper, node *h.UnixfsNode, depth int, offset uint64) error {
	if depth < 0 {
		return errors.New("attempt to fillNode at depth < 0")
	}

	// Base case
	if depth <= 0 { // catch accidental -1's in case error above is removed.
		child, err := db.GetNextDataNode()
		if err != nil {
			return err
		}

		node.Set(child)
		return nil
	}

	// while we have room AND we're not done
	for node.NumChildren() < db.Maxlinks() && !db.Done() {
		child := db.NewUnixfsNode()
		db.SetPosInfo(child, offset)

		err := fillNodeRec(db, child, depth-1, offset)
		if err != nil {
			return err
		}

		if err := node.AddChild(child, db); err != nil {
			return err
		}
		offset += child.FileSize()
	}

	return nil
}
<commit_msg>Switch to CIDv1<commit_after>package ipfs

import (
	"errors"
	"github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core/coreunix"
	"github.com/ipfs/go-ipfs/importer/chunk"
	h "github.com/ipfs/go-ipfs/importer/helpers"
	ihelper "github.com/ipfs/go-ipfs/importer/helpers"
	"io"
	"path"
	"strconv"
)

var addErr = errors.New(`Add directory failed`)

// Resursively add a directory to IPFS and return the root hash
func AddDirectory(ctx commands.Context, fpath string) (rootHash string, err error) {
	_, root := path.Split(fpath)
	args := []string{"add", "-r", fpath, "--cid-version", strconv.Itoa(1)}
	req, cmd, err := NewRequest(ctx, args)
	if err != nil {
		return "", err
	}
	res := commands.NewResponse(req)
	cmd.PreRun(req)
	cmd.Run(req, res)
	for r := range res.Output().(<-chan interface{}) {
		if r.(*coreunix.AddedObject).Name == root {
			rootHash = r.(*coreunix.AddedObject).Hash
		}
	}
	cmd.PostRun(req, res)
	if res.Error() != nil {
		return "", res.Error()
	}
	if rootHash == "" {
		return "", addErr
	}
	return rootHash, nil
}

func AddFile(ctx commands.Context, fpath string) (string, error) {
	args := []string{"add", fpath}
	req, cmd, err := NewRequest(ctx, args)
	if err != nil {
		return "", err
	}
	res := commands.NewResponse(req)
	cmd.PreRun(req)
	cmd.Run(req, res)
	var fileHash string
	for r := range res.Output().(<-chan interface{}) {
		fileHash = r.(*coreunix.AddedObject).Hash
	}
	cmd.PostRun(req, res)
	if res.Error() != nil {
		return "", res.Error()
	}
	if fileHash == "" {
		return "", addErr
	}
	return fileHash, nil
}

func GetHashOfFile(ctx commands.Context, fpath string) (string, error) {
	args := []string{"add", "-n", fpath}
	req, cmd, err := NewRequest(ctx, args)
	if err != nil {
		return "", err
	}
	res := commands.NewResponse(req)
	cmd.PreRun(req)
	cmd.Run(req, res)
	var fileHash string
	for r := range res.Output().(<-chan interface{}) {
		fileHash = r.(*coreunix.AddedObject).Hash
	}
	cmd.PostRun(req, res)
	if res.Error() != nil {
		return "", res.Error()
	}
	if fileHash == "" {
		return "", addErr
	}
	return fileHash, nil
}

func GetHash(ctx commands.Context, reader io.Reader) (string, error) {
	nd, err := ctx.ConstructNode()
	if err != nil {
		return "", err
	}
	chnk, err := chunk.FromString(reader, "")
	if err != nil {
		return "", err
	}
	params := ihelper.DagBuilderParams{
		Maxlinks: ihelper.DefaultLinksPerBlock,
		Dagserv:  nd.DAG,
	}
	db := params.New(chnk)

	var offset uint64 = 0
	var root *h.UnixfsNode
	for level := 0; !db.Done(); level++ {

		nroot := db.NewUnixfsNode()
		db.SetPosInfo(nroot, 0)

		// add our old root as a child of the new root.
		if root != nil { // nil if it's the first node.
			if err := nroot.AddChild(root, db); err != nil {
				return "", err
			}
		}

		// fill it up.
		if err := fillNodeRec(db, nroot, level, offset); err != nil {
			return "", err
		}

		offset = nroot.FileSize()
		root = nroot

	}
	if root == nil {
		root = db.NewUnixfsNode()
	}
	n, err := root.GetDagNode()
	if err != nil {
		return "", err
	}
	return n.String(), nil
}

// fillNodeRec will fill the given node with data from the dagBuilders input
// source down to an indirection depth as specified by 'depth'
// it returns the total dataSize of the node, and a potential error
//
// warning: **children** pinned indirectly, but input node IS NOT pinned.
func fillNodeRec(db *h.DagBuilderHelper, node *h.UnixfsNode, depth int, offset uint64) error {
	if depth < 0 {
		return errors.New("attempt to fillNode at depth < 0")
	}

	// Base case
	if depth <= 0 { // catch accidental -1's in case error above is removed.
		child, err := db.GetNextDataNode()
		if err != nil {
			return err
		}

		node.Set(child)
		return nil
	}

	// while we have room AND we're not done
	for node.NumChildren() < db.Maxlinks() && !db.Done() {
		child := db.NewUnixfsNode()
		db.SetPosInfo(child, offset)

		err := fillNodeRec(db, child, depth-1, offset)
		if err != nil {
			return err
		}

		if err := node.AddChild(child, db); err != nil {
			return err
		}
		offset += child.FileSize()
	}

	return nil
}
<|endoftext|>


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

// Package ipv6 implements IP-level socket options for the Internet
// Protocol version 6.
//
// The package provides IP-level socket options that allow
// manipulation of IPv6 facilities.  The IPv6 and socket options for
// IPv6 are defined in RFC 2460, RFC 3493 and RFC 3542.
//
//
// Unicasting
//
// The options for unicasting are available for net.TCPConn,
// net.UDPConn and net.IPConn which are created as network connections
// that use the IPv6 transport.  When a single TCP connection carrying
// a data flow of multiple packets needs to indicate the flow is
// important, ipv6.Conn is used to set the traffic class field on the
// IPv6 header for each packet.
//
//	ln, err := net.Listen("tcp6", "[::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer ln.Close()
//	for {
//		c, err := ln.Accept()
//		if err != nil {
//			// error handling
//		}
//		go func(c net.Conn) {
//			defer c.Close()
//
// The outgoing packets will be labeled DiffServ assured forwarding
// class 1 low drop precedence, as known as AF11 packets.
//
//			if err := ipv6.NewConn(c).SetTrafficClass(DiffServAF11); err != nil {
//				// error handling
//			}
//			if _, err := c.Write(data); err != nil {
//				// error handling
//			}
//		}(c)
//	}
//
//
// Multicasting
//
// The options for multicasting are available for net.UDPConn and
// net.IPconn which are created as network connections that use the
// IPv6 transport.  A few network facilities must be prepared before
// you begin multicasting, at a minimum joining network interfaces and
// group addresses.
//
//	en0, err := net.InterfaceByName("en0")
//	if err != nil {
//		// error handling
//	}
//	en1, err := net.InterfaceByIndex(911)
//	if err != nil {
//		// error handling
//	}
//	group := net.ParseIP("ff02::114")
//
// First, an application listens to an appropriate address with an
// appropriate service port.
//
//	c, err := net.ListenPacket("udp6", "[::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c.Close()
//
// Second, the application joins groups, starts listening to the
// group addresses on the specified network interfaces.  Note that
// the service port for transport layer protocol does not matter with
// this operation as joining groups affects only network and link
// layer protocols, such as IPv6 and Ethernet.
//
//	p := ipv6.NewPacketConn(c)
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil {
//		// error handling
//	}
//
// The application might set per packet control message transmissions
// between the protocol stack within the kernel.  When the application
// needs a destination address on an incoming packet,
// SetControlMessage of ipv6.PacketConn is used to enable control
// message transmissons.
//
//	if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil {
//		// error handling
//	}
//
// The application could identify whether the received packets are
// of interest by using the control message that contains the
// destination address of the received packet.
//
//	b := make([]byte, 1500)
//	for {
//		n, rcm, src, err := p.ReadFrom(b)
//		if err != nil {
//			// error handling
//		}
//		if rcm.Dst.IsMulticast() {
//			if rcm.Dst.Equal(group)
//				// joined group, do something
//			} else {
//				// unknown group, discard
//				continue
//			}
//		}
//
// The application can also send both unicast and multicast packets.
//
//		p.SetTrafficClass(DiffServCS0)
//		p.SetHopLimit(16)
//		if _, err := p.WriteTo(data[:n], nil, src); err != nil {
//			// error handling
//		}
//		dst := &net.UDPAddr{IP: group, Port: 1024}
//		wcm := ipv6.ControlMessage{TrafficClass: DiffServCS7, HopLimit: 1}
//		for _, ifi := range []*net.Interface{en0, en1} {
//			wcm.IfIndex = ifi.Index
//			if _, err := p.WriteTo(data[:n], &wcm, dst); err != nil {
//				// error handling
//			}
//		}
//	}
//
//
// More multicasting
//
// An application that uses PacketConn or RawConn might join the
// multiple group addresses.  For example, a UDP listener with port
// 1024 might join two different groups across over two different
// network interfaces by using:
//
//	c, err := net.ListenPacket("udp6", "[::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c.Close()
//	p := ipv6.NewPacketConn(c)
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
//		// error handling
//	}
//
// It is possible for multiple UDP listeners that listen on the same
// UDP port to join the same group address.  The net package will
// provide a socket that listens to a wildcard address with reusable
// UDP port when an appropriate multicast address prefix is passed to
// the net.ListenPacket or net.ListenUDP.
//
//	c1, err := net.ListenPacket("udp6", "[ff02::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c1.Close()
//	c2, err := net.ListenPacket("udp6", "[ff02::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c2.Close()
//	p1 := ipv6.NewPacketConn(c1)
//	if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
//		// error handling
//	}
//	p2 := ipv6.NewPacketConn(c2)
//	if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
//		// error handling
//	}
//
// Also it is possible for the application to leave or rejoin a
// multicast group on the network interface.
//
//	if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff01::114")}); err != nil {
//		// error handling
//	}
package ipv6
<commit_msg>go.net/ipv6: remove RawConn reference from package documentation<commit_after>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ipv6 implements IP-level socket options for the Internet
// Protocol version 6.
//
// The package provides IP-level socket options that allow
// manipulation of IPv6 facilities.  The IPv6 and socket options for
// IPv6 are defined in RFC 2460, RFC 3493 and RFC 3542.
//
//
// Unicasting
//
// The options for unicasting are available for net.TCPConn,
// net.UDPConn and net.IPConn which are created as network connections
// that use the IPv6 transport.  When a single TCP connection carrying
// a data flow of multiple packets needs to indicate the flow is
// important, ipv6.Conn is used to set the traffic class field on the
// IPv6 header for each packet.
//
//	ln, err := net.Listen("tcp6", "[::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer ln.Close()
//	for {
//		c, err := ln.Accept()
//		if err != nil {
//			// error handling
//		}
//		go func(c net.Conn) {
//			defer c.Close()
//
// The outgoing packets will be labeled DiffServ assured forwarding
// class 1 low drop precedence, as known as AF11 packets.
//
//			if err := ipv6.NewConn(c).SetTrafficClass(DiffServAF11); err != nil {
//				// error handling
//			}
//			if _, err := c.Write(data); err != nil {
//				// error handling
//			}
//		}(c)
//	}
//
//
// Multicasting
//
// The options for multicasting are available for net.UDPConn and
// net.IPconn which are created as network connections that use the
// IPv6 transport.  A few network facilities must be prepared before
// you begin multicasting, at a minimum joining network interfaces and
// group addresses.
//
//	en0, err := net.InterfaceByName("en0")
//	if err != nil {
//		// error handling
//	}
//	en1, err := net.InterfaceByIndex(911)
//	if err != nil {
//		// error handling
//	}
//	group := net.ParseIP("ff02::114")
//
// First, an application listens to an appropriate address with an
// appropriate service port.
//
//	c, err := net.ListenPacket("udp6", "[::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c.Close()
//
// Second, the application joins groups, starts listening to the
// group addresses on the specified network interfaces.  Note that
// the service port for transport layer protocol does not matter with
// this operation as joining groups affects only network and link
// layer protocols, such as IPv6 and Ethernet.
//
//	p := ipv6.NewPacketConn(c)
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil {
//		// error handling
//	}
//
// The application might set per packet control message transmissions
// between the protocol stack within the kernel.  When the application
// needs a destination address on an incoming packet,
// SetControlMessage of ipv6.PacketConn is used to enable control
// message transmissons.
//
//	if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil {
//		// error handling
//	}
//
// The application could identify whether the received packets are
// of interest by using the control message that contains the
// destination address of the received packet.
//
//	b := make([]byte, 1500)
//	for {
//		n, rcm, src, err := p.ReadFrom(b)
//		if err != nil {
//			// error handling
//		}
//		if rcm.Dst.IsMulticast() {
//			if rcm.Dst.Equal(group)
//				// joined group, do something
//			} else {
//				// unknown group, discard
//				continue
//			}
//		}
//
// The application can also send both unicast and multicast packets.
//
//		p.SetTrafficClass(DiffServCS0)
//		p.SetHopLimit(16)
//		if _, err := p.WriteTo(data[:n], nil, src); err != nil {
//			// error handling
//		}
//		dst := &net.UDPAddr{IP: group, Port: 1024}
//		wcm := ipv6.ControlMessage{TrafficClass: DiffServCS7, HopLimit: 1}
//		for _, ifi := range []*net.Interface{en0, en1} {
//			wcm.IfIndex = ifi.Index
//			if _, err := p.WriteTo(data[:n], &wcm, dst); err != nil {
//				// error handling
//			}
//		}
//	}
//
//
// More multicasting
//
// An application that uses PacketConn may join multiple group
// addresses.  For example, a UDP listener with port 1024 might join
// two different groups across over two different network interfaces
// by using:
//
//	c, err := net.ListenPacket("udp6", "[::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c.Close()
//	p := ipv6.NewPacketConn(c)
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
//		// error handling
//	}
//
// It is possible for multiple UDP listeners that listen on the same
// UDP port to join the same group address.  The net package will
// provide a socket that listens to a wildcard address with reusable
// UDP port when an appropriate multicast address prefix is passed to
// the net.ListenPacket or net.ListenUDP.
//
//	c1, err := net.ListenPacket("udp6", "[ff02::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c1.Close()
//	c2, err := net.ListenPacket("udp6", "[ff02::]:1024")
//	if err != nil {
//		// error handling
//	}
//	defer c2.Close()
//	p1 := ipv6.NewPacketConn(c1)
//	if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
//		// error handling
//	}
//	p2 := ipv6.NewPacketConn(c2)
//	if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
//		// error handling
//	}
//
// Also it is possible for the application to leave or rejoin a
// multicast group on the network interface.
//
//	if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
//		// error handling
//	}
//	if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff01::114")}); err != nil {
//		// error handling
//	}
package ipv6
<|endoftext|>