<commit_before>package indexer

import (
	"bytes"
	"encoding/json"
	"io"
	"strings"

	"github.com/dchest/stemmer/porter2"

	"github.com/dchest/static-search/indexer/tokenizer"
)

type Index struct {
	Docs  []*Document              `json:"docs"`
	Words map[string][]interface{} `json:"words"`

	HTMLTitleWeight        int `json:"-"`
	HTMLURLComponentWeight int `json:"-"`
}

type Document struct {
	URL   string `json:"u"`
	Title string `json:"t"`
}

func New() *Index {
	return &Index{
		Docs:                   make([]*Document, 0),
		Words:                  make(map[string][]interface{}),
		HTMLTitleWeight:        10,
		HTMLURLComponentWeight: 10,
	}
}

func (n *Index) WriteJSON(w io.Writer) error {
	return json.NewEncoder(w).Encode(n)
}

func (n *Index) addWord(word string, doc, weight int) {
	if weight == 1 {
		n.Words[word] = append(n.Words[word], doc)
	} else {
		n.Words[word] = append(n.Words[word], [2]int{doc, weight})
	}
}

func (n *Index) newDocument(url, title string) int {
	n.Docs = append(n.Docs, &Document{URL: url, Title: title})
	return len(n.Docs) - 1
}

func (n *Index) addString(doc int, text string, wordWeight int) {
	wordcnt := make(map[string]int)
	tk := tokenizer.Words(text)
	for tk.Next() {
		w := tk.Token()
		if len(w) < 2 || isStopWord(w) {
			continue
		}
		wordcnt[porter2.Stemmer.Stem(removeAccents(w))] += wordWeight
	}
	for w, c := range wordcnt {
		n.addWord(w, doc, c)
	}
}

func (n *Index) AddText(url, title string, r io.Reader) error {
	var b bytes.Buffer
	if _, err := io.Copy(&b, r); err != nil {
		return err
	}
	n.addString(n.newDocument(url, title), b.String(), 1)
	return nil
}

func (n *Index) AddHTML(url string, r io.Reader) error {
	title, content, err := parseHTML(r)
	if err != nil {
		return err
	}
	doc := n.newDocument(url, title)
	n.addString(doc, title, n.HTMLTitleWeight)
	n.addString(doc, content, 1)
	// Add URL components.
	url = strings.TrimPrefix(url, "http://")
	url = strings.TrimPrefix(url, "https://")
	url = strings.TrimPrefix(url, "www.")
	// The farther the component, the less its weight.
	// Also, each components weight depends on the total number of them, so
	// that "blog" in /blog/ weights more than in /blog/some-post/.
	components := strings.Split(url, "/")
	weight := n.HTMLURLComponentWeight / len(components)
	for _, v := range components {
		weight /= 2
		if weight < 1 {
			weight = 1
		}
		n.addString(doc, v, weight)
	}
	return nil
}
<commit_msg>Tweak static-search weights<commit_after>package indexer

import (
	"bytes"
	"encoding/json"
	"io"
	"strings"

	"github.com/dchest/stemmer/porter2"

	"github.com/dchest/static-search/indexer/tokenizer"
)

type Index struct {
	Docs  []*Document              `json:"docs"`
	Words map[string][]interface{} `json:"words"`

	HTMLTitleWeight        int `json:"-"`
	HTMLURLComponentWeight int `json:"-"`
}

type Document struct {
	URL   string `json:"u"`
	Title string `json:"t"`
}

func New() *Index {
	return &Index{
		Docs:                   make([]*Document, 0),
		Words:                  make(map[string][]interface{}),
		HTMLTitleWeight:        20,
		HTMLURLComponentWeight: 20,
	}
}

func (n *Index) WriteJSON(w io.Writer) error {
	return json.NewEncoder(w).Encode(n)
}

func (n *Index) addWord(word string, doc, weight int) {
	if weight == 1 {
		n.Words[word] = append(n.Words[word], doc)
	} else {
		n.Words[word] = append(n.Words[word], [2]int{doc, weight})
	}
}

func (n *Index) newDocument(url, title string) int {
	n.Docs = append(n.Docs, &Document{URL: url, Title: title})
	return len(n.Docs) - 1
}

func (n *Index) addString(doc int, text string, wordWeight int) {
	wordcnt := make(map[string]int)
	tk := tokenizer.Words(text)
	for tk.Next() {
		w := tk.Token()
		if len(w) < 2 || isStopWord(w) {
			continue
		}
		wordcnt[porter2.Stemmer.Stem(removeAccents(w))] += wordWeight
	}
	for w, c := range wordcnt {
		n.addWord(w, doc, c)
	}
}

func (n *Index) AddText(url, title string, r io.Reader) error {
	var b bytes.Buffer
	if _, err := io.Copy(&b, r); err != nil {
		return err
	}
	n.addString(n.newDocument(url, title), b.String(), 1)
	return nil
}

func (n *Index) AddHTML(url string, r io.Reader) error {
	title, content, err := parseHTML(r)
	if err != nil {
		return err
	}
	doc := n.newDocument(url, title)
	n.addString(doc, title, n.HTMLTitleWeight)
	n.addString(doc, content, 1)
	// Add URL components.
	url = strings.TrimPrefix(url, "http://")
	url = strings.TrimPrefix(url, "https://")
	url = strings.TrimPrefix(url, "www.")
	// The farther the component, the less its weight.
	// Also, each components weight depends on the total number of them, so
	// that "blog" in /blog/ weights more than in /blog/some-post/.
	components := strings.Split(url, "/")
	weight := n.HTMLURLComponentWeight / len(components)
	for _, v := range components {
		weight /= 2
		if weight < 1 {
			weight = 1
		}
		n.addString(doc, v, weight)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"strings"
	"text/template"

	flag "github.com/ogier/pflag"
)

var (
	cmdHelp = &Command{
		Name:        "help",
		Summary:     "Show a list of commands or help for one command",
		Usage:       "[COMMAND]",
		Description: "Show a list of commands or detailed help for one command",
		Run:         runHelp,
	}

	globalUsageTemplate  *template.Template
	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"printOption": func(shorthand, name, defvalue, usage string) string {
			format := "--%s=%s\t%s"
			/*if _, ok := flag.Value.(*stringValue); ok {
				format = "--%s=%q\t%s"
			}*/
			if len(shorthand) > 0 {
				format = "    -%s, " + format
			} else {
				format = "     %s   " + format
			}
			return fmt.Sprintf(format, shorthand, name, defvalue, usage)
		},
	}
)

func init() {
	globalUsageTemplate = template.Must(template.New("global_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Executable .Description}}

USAGE:
{{printf "\t%s" .Executable}} [global options] <command> [command options] [arguments...]

VERSION:
{{printf "\t%s" .Version}}

COMMANDS:{{range .Commands}}
{{printf "\t%s\t%s" .Name .Summary}}{{end}}

GLOBAL OPTIONS:{{range .Flags}}
{{printOption .Shorthand .Name .DefValue .Usage}}{{end}}

Run "{{.Executable}} help <command>" for more details on a specific command.
`[1:]))
	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Cmd.Name .Cmd.Summary}}

USAGE:
{{printf "\t%s %s %s" .Executable .Cmd.Name .Cmd.Usage}}

DESCRIPTION:{{range $line := descToLines .Cmd.Description}}
{{printf "\t%s" $line}}{{end}}
{{if .Cmd.Subcommands}}COMMANDS:{{range .Cmd.Subcommands}}
{{printf "\t%s\t%s" .Name .Summary}}{{end}}{{end}}

{{if .CmdFlags}}OPTIONS:{{range .CmdFlags}}
{{printOption .Shorthand .Name .DefValue .Usage}}{{end}}{{end}}

For help on global options run "{{.Executable}} help"
`[1:]))
}

func runHelp(args []string) int {
	if len(args) < 1 {
		printGlobalUsage()
		return OK
	}

	var cmd *Command

	for _, c := range commands {
		if c.Name == args[0] {
			cmd = c
			break
		}
	}

	if cmd == nil {
		stderr("Error: unknown command: %s\n", args[0])
		stderr("Run '%s help' for usage information\n", cliName)
		return ERROR_NO_COMMAND
	}

	printCommandUsage(cmd)
	return OK
}

func printGlobalUsage() {
	globalUsageTemplate.Execute(out, struct {
		Executable  string
		Commands    []*Command
		Flags       []*flag.Flag
		Description string
		Version     string
	}{
		cliName,
		commands,
		getAllFlags(),
		cliDescription,
		cliVersion,
	})
}

func printCommandUsage(cmd *Command) {
	commandUsageTemplate.Execute(out, struct {
		Executable string
		Cmd        *Command
		CmdFlags   []*flag.Flag
	}{
		cliName,
		cmd,
		getFlags(&cmd.Flags),
	})
}

func getAllFlags() (flags []*flag.Flag) {
	return getFlags(globalFlagSet)
}

func getFlags(flagset *flag.FlagSet) (flags []*flag.Flag) {
	flags = make([]*flag.Flag, 0)
	flagset.VisitAll(func(f *flag.Flag) {
		flags = append(flags, f)
	})
	return
}
<commit_msg>Help typo<commit_after>/*
Copyright 2015 Nodetemple <hostmaster@nodetemple.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"strings"
	"text/template"

	flag "github.com/ogier/pflag"
)

var (
	cmdHelp = &Command{
		Name:        "help",
		Summary:     "Show a list of commands or help for one command",
		Usage:       "[COMMAND]",
		Description: "Show a list of commands or detailed help for one command",
		Run:         runHelp,
	}

	globalUsageTemplate  *template.Template
	commandUsageTemplate *template.Template
	templFuncs           = template.FuncMap{
		"descToLines": func(s string) []string {
			return strings.Split(strings.Trim(s, "\n\t "), "\n")
		},
		"printOption": func(shorthand, name, defvalue, usage string) string {
			format := "--%s=%s\t%s"
			/*if _, ok := flag.Value.(*stringValue); ok {
				format = "--%s=%q\t%s"
			}*/
			if len(shorthand) > 0 {
				format = "    -%s, " + format
			} else {
				format = "     %s   " + format
			}
			return fmt.Sprintf(format, shorthand, name, defvalue, usage)
		},
	}
)

func init() {
	globalUsageTemplate = template.Must(template.New("global_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Executable .Description}}

USAGE:
{{printf "\t%s" .Executable}} [global options] <command> [command options] [arguments...]

VERSION:
{{printf "\t%s" .Version}}

COMMANDS:{{range .Commands}}
{{printf "\t%s\t%s" .Name .Summary}}{{end}}

GLOBAL OPTIONS:{{range .Flags}}
{{printOption .Shorthand .Name .DefValue .Usage}}{{end}}

Run "{{.Executable}} help <command>" for more details on a specific command.
`[1:]))
	commandUsageTemplate = template.Must(template.New("command_usage").Funcs(templFuncs).Parse(`
NAME:
{{printf "\t%s - %s" .Cmd.Name .Cmd.Summary}}

USAGE:
{{printf "\t%s %s %s" .Executable .Cmd.Name .Cmd.Usage}}

DESCRIPTION:{{range $line := descToLines .Cmd.Description}}
{{printf "\t%s" $line}}{{end}}
{{if .Cmd.Subcommands}}COMMANDS:{{range .Cmd.Subcommands}}
{{printf "\t%s\t%s" .Name .Summary}}{{end}}{{end}}
{{if .CmdFlags}}OPTIONS:{{range .CmdFlags}}
{{printOption .Shorthand .Name .DefValue .Usage}}{{end}}{{end}}
For help on global options run "{{.Executable}} help"
`[1:]))
}

func runHelp(args []string) int {
	if len(args) < 1 {
		printGlobalUsage()
		return OK
	}

	var cmd *Command

	for _, c := range commands {
		if c.Name == args[0] {
			cmd = c
			break
		}
	}

	if cmd == nil {
		stderr("Error: unknown command: %s\n", args[0])
		stderr("Run '%s help' for usage information\n", cliName)
		return ERROR_NO_COMMAND
	}

	printCommandUsage(cmd)
	return OK
}

func printGlobalUsage() {
	globalUsageTemplate.Execute(out, struct {
		Executable  string
		Commands    []*Command
		Flags       []*flag.Flag
		Description string
		Version     string
	}{
		cliName,
		commands,
		getAllFlags(),
		cliDescription,
		cliVersion,
	})
}

func printCommandUsage(cmd *Command) {
	commandUsageTemplate.Execute(out, struct {
		Executable string
		Cmd        *Command
		CmdFlags   []*flag.Flag
	}{
		cliName,
		cmd,
		getFlags(&cmd.Flags),
	})
}

func getAllFlags() (flags []*flag.Flag) {
	return getFlags(globalFlagSet)
}

func getFlags(flagset *flag.FlagSet) (flags []*flag.Flag) {
	flags = make([]*flag.Flag, 0)
	flagset.VisitAll(func(f *flag.Flag) {
		flags = append(flags, f)
	})
	return
}
<|endoftext|>


<commit_before>package webrtc

import (
	"fmt"
	"sync"

	"github.com/pions/datachannel"
	sugar "github.com/pions/webrtc/pkg/datachannel"
	"github.com/pions/webrtc/pkg/rtcerr"
	"github.com/pkg/errors"
)

// RTCDataChannel represents a WebRTC DataChannel
// The RTCDataChannel interface represents a network channel
// which can be used for bidirectional peer-to-peer transfers of arbitrary data
type RTCDataChannel struct {
	sync.RWMutex

	// Label represents a label that can be used to distinguish this
	// RTCDataChannel object from other RTCDataChannel objects. Scripts are
	// allowed to create multiple RTCDataChannel objects with the same label.
	Label string

	// Ordered represents if the RTCDataChannel is ordered, and false if
	// out-of-order delivery is allowed.
	Ordered bool

	// MaxPacketLifeTime represents the length of the time window (msec) during
	// which transmissions and retransmissions may occur in unreliable mode.
	MaxPacketLifeTime *uint16

	// MaxRetransmits represents the maximum number of retransmissions that are
	// attempted in unreliable mode.
	MaxRetransmits *uint16

	// Protocol represents the name of the sub-protocol used with this
	// RTCDataChannel.
	Protocol string

	// Negotiated represents whether this RTCDataChannel was negotiated by the
	// application (true), or not (false).
	Negotiated bool

	// ID represents the ID for this RTCDataChannel. The value is initially
	// null, which is what will be returned if the ID was not provided at
	// channel creation time, and the DTLS role of the SCTP transport has not
	// yet been negotiated. Otherwise, it will return the ID that was either
	// selected by the script or generated. After the ID is set to a non-null
	// value, it will not change.
	ID *uint16

	// Priority represents the priority for this RTCDataChannel. The priority is
	// assigned at channel creation time.
	Priority RTCPriorityType

	// ReadyState represents the state of the RTCDataChannel object.
	ReadyState RTCDataChannelState

	// BufferedAmount represents the number of bytes of application data
	// (UTF-8 text and binary data) that have been queued using send(). Even
	// though the data transmission can occur in parallel, the returned value
	// MUST NOT be decreased before the current task yielded back to the event
	// loop to prevent race conditions. The value does not include framing
	// overhead incurred by the protocol, or buffering done by the operating
	// system or network hardware. The value of BufferedAmount slot will only
	// increase with each call to the send() method as long as the ReadyState is
	// open; however, BufferedAmount does not reset to zero once the channel
	// closes.
	BufferedAmount uint64

	// BufferedAmountLowThreshold represents the threshold at which the
	// bufferedAmount is considered to be low. When the bufferedAmount decreases
	// from above this threshold to equal or below it, the bufferedamountlow
	// event fires. BufferedAmountLowThreshold is initially zero on each new
	// RTCDataChannel, but the application may change its value at any time.
	BufferedAmountLowThreshold uint64

	// The binaryType represents attribute MUST, on getting, return the value to
	// which it was last set. On setting, if the new value is either the string
	// "blob" or the string "arraybuffer", then set the IDL attribute to this
	// new value. Otherwise, throw a SyntaxError. When an RTCDataChannel object
	// is created, the binaryType attribute MUST be initialized to the string
	// "blob". This attribute controls how binary data is exposed to scripts.
	// binaryType                 string

	// OnOpen              func()
	// OnBufferedAmountLow func()
	// OnError             func()
	// OnClose             func()

	onMessageHandler func(sugar.Payload)
	onOpenHandler    func()

	sctpTransport *RTCSctpTransport
	dataChannel   *datachannel.DataChannel
}

// NewRTCDataChannel creates a new RTCDataChannel.
// This constructor is part of the ORTC API. It is not
// meant to be used together with the basic WebRTC API.
func NewRTCDataChannel(transport *RTCSctpTransport, params *RTCDataChannelParameters) (*RTCDataChannel, error) {
	d, err := newRTCDataChannel(params)
	if err != nil {
		return nil, err
	}

	err = d.open(transport)
	if err != nil {
		return nil, err
	}

	return d, nil
}

// newRTCDataChannel is an internal constructor for the data channel used to
// create the RTCDataChannel object before the networking is set up.
func newRTCDataChannel(params *RTCDataChannelParameters) (*RTCDataChannel, error) {
	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #5)
	if len(params.Label) > 65535 {
		return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit}
	}

	d := &RTCDataChannel{
		Label:      params.Label,
		ID:         &params.ID,
		ReadyState: RTCDataChannelStateConnecting,
	}

	return d, nil
}

// open opens the datachannel over the sctp transport
func (d *RTCDataChannel) open(sctpTransport *RTCSctpTransport) error {
	d.RLock()
	d.sctpTransport = sctpTransport

	if err := d.ensureSCTP(); err != nil {
		d.RUnlock()
		return err
	}

	cfg := &datachannel.Config{
		ChannelType:          datachannel.ChannelTypeReliable,   // TODO: Wiring
		Priority:             datachannel.ChannelPriorityNormal, // TODO: Wiring
		ReliabilityParameter: 0,                                 // TODO: Wiring
		Label:                d.Label,
	}

	dc, err := datachannel.Dial(d.sctpTransport.association, *d.ID, cfg)
	if err != nil {
		d.RUnlock()
		return err
	}

	d.ReadyState = RTCDataChannelStateOpen
	d.RUnlock()

	d.handleOpen(dc)
	return nil
}

func (d *RTCDataChannel) ensureSCTP() error {
	if d.sctpTransport == nil ||
		d.sctpTransport.association == nil {
		return errors.New("SCTP not establisched")
	}
	return nil
}

// Transport returns the RTCSctpTransport instance the RTCDataChannel is sending over.
func (d *RTCDataChannel) Transport() *RTCSctpTransport {
	d.RLock()
	defer d.RUnlock()

	return d.sctpTransport
}

// OnOpen sets an event handler which is invoked when
// the underlying data transport has been established (or re-established).
func (d *RTCDataChannel) OnOpen(f func()) {
	d.Lock()
	defer d.Unlock()
	d.onOpenHandler = f
}

func (d *RTCDataChannel) onOpen() (done chan struct{}) {
	d.RLock()
	hdlr := d.onOpenHandler
	d.RUnlock()

	done = make(chan struct{})
	if hdlr == nil {
		close(done)
		return
	}

	go func() {
		hdlr()
		close(done)
	}()

	return
}

// OnMessage sets an event handler which is invoked on a message
// arrival over the sctp transport from a remote peer.
func (d *RTCDataChannel) OnMessage(f func(p sugar.Payload)) {
	d.Lock()
	defer d.Unlock()
	d.onMessageHandler = f
}

func (d *RTCDataChannel) onMessage(p sugar.Payload) {
	d.RLock()
	hdlr := d.onMessageHandler
	d.RUnlock()

	if hdlr == nil || p == nil {
		return
	}
	hdlr(p)
}

// Onmessage sets an event handler which is invoked on a message
// arrival over the sctp transport from a remote peer.
//
// Deprecated: use OnMessage instead.
func (d *RTCDataChannel) Onmessage(f func(p sugar.Payload)) {
	d.OnMessage(f)
}

func (d *RTCDataChannel) handleOpen(dc *datachannel.DataChannel) {
	d.Lock()
	d.dataChannel = dc
	d.Unlock()

	d.onOpen()

	d.Lock()
	defer d.Unlock()

	if !defaultSettingEngine.Detach.DataChannels {
		go d.readLoop()
	}
}

func (d *RTCDataChannel) readLoop() {
	for {
		buffer := make([]byte, receiveMTU)
		n, isString, err := d.dataChannel.ReadDataChannel(buffer)
		if err != nil {
			fmt.Println("Failed to read from data channel", err)
			// TODO: Kill DataChannel/PeerConnection?
			return
		}

		if isString {
			d.onMessage(&sugar.PayloadString{Data: buffer[:n]})
			continue
		}
		d.onMessage(&sugar.PayloadBinary{Data: buffer[:n]})
	}
}

// Send sends the passed message to the DataChannel peer
func (d *RTCDataChannel) Send(payload sugar.Payload) error {
	var data []byte
	isString := false

	switch p := payload.(type) {
	case sugar.PayloadString:
		data = p.Data
		isString = true
	case sugar.PayloadBinary:
		data = p.Data
	default:
		return errors.Errorf("unknown DataChannel Payload (%s)", payload.PayloadType())
	}

	if len(data) == 0 {
		data = []byte{0}
	}

	_, err := d.dataChannel.WriteDataChannel(data, isString)
	return err
}

// Detach allows you to detach the underlying datachannel. This provides
// an idiomatic API to work with, however it disables the OnMessage callback.
// Before calling Detach you have to enable this behavior by calling
// webrtc.DetachDataChannels(). Combining detached and normal data channels
// is not supported.
// Please reffer to the data-channels-detach example and the
// pions/datachannel documentation for the correct way to handle the
// resulting DataChannel object.
func (d *RTCDataChannel) Detach() (*datachannel.DataChannel, error) {
	d.Lock()
	defer d.Unlock()

	if !defaultSettingEngine.Detach.DataChannels {
		return nil, errors.New("enable detaching by calling webrtc.DetachDataChannels()")
	}

	if d.dataChannel == nil {
		return nil, errors.New("datachannel not opened yet, try calling Detach from OnOpen")
	}

	return d.dataChannel, nil
}
<commit_msg>Make RTCDataChannel mutex private<commit_after>package webrtc

import (
	"fmt"
	"sync"

	"github.com/pions/datachannel"
	sugar "github.com/pions/webrtc/pkg/datachannel"
	"github.com/pions/webrtc/pkg/rtcerr"
	"github.com/pkg/errors"
)

// RTCDataChannel represents a WebRTC DataChannel
// The RTCDataChannel interface represents a network channel
// which can be used for bidirectional peer-to-peer transfers of arbitrary data
type RTCDataChannel struct {
	mu sync.RWMutex

	// Label represents a label that can be used to distinguish this
	// RTCDataChannel object from other RTCDataChannel objects. Scripts are
	// allowed to create multiple RTCDataChannel objects with the same label.
	Label string

	// Ordered represents if the RTCDataChannel is ordered, and false if
	// out-of-order delivery is allowed.
	Ordered bool

	// MaxPacketLifeTime represents the length of the time window (msec) during
	// which transmissions and retransmissions may occur in unreliable mode.
	MaxPacketLifeTime *uint16

	// MaxRetransmits represents the maximum number of retransmissions that are
	// attempted in unreliable mode.
	MaxRetransmits *uint16

	// Protocol represents the name of the sub-protocol used with this
	// RTCDataChannel.
	Protocol string

	// Negotiated represents whether this RTCDataChannel was negotiated by the
	// application (true), or not (false).
	Negotiated bool

	// ID represents the ID for this RTCDataChannel. The value is initially
	// null, which is what will be returned if the ID was not provided at
	// channel creation time, and the DTLS role of the SCTP transport has not
	// yet been negotiated. Otherwise, it will return the ID that was either
	// selected by the script or generated. After the ID is set to a non-null
	// value, it will not change.
	ID *uint16

	// Priority represents the priority for this RTCDataChannel. The priority is
	// assigned at channel creation time.
	Priority RTCPriorityType

	// ReadyState represents the state of the RTCDataChannel object.
	ReadyState RTCDataChannelState

	// BufferedAmount represents the number of bytes of application data
	// (UTF-8 text and binary data) that have been queued using send(). Even
	// though the data transmission can occur in parallel, the returned value
	// MUST NOT be decreased before the current task yielded back to the event
	// loop to prevent race conditions. The value does not include framing
	// overhead incurred by the protocol, or buffering done by the operating
	// system or network hardware. The value of BufferedAmount slot will only
	// increase with each call to the send() method as long as the ReadyState is
	// open; however, BufferedAmount does not reset to zero once the channel
	// closes.
	BufferedAmount uint64

	// BufferedAmountLowThreshold represents the threshold at which the
	// bufferedAmount is considered to be low. When the bufferedAmount decreases
	// from above this threshold to equal or below it, the bufferedamountlow
	// event fires. BufferedAmountLowThreshold is initially zero on each new
	// RTCDataChannel, but the application may change its value at any time.
	BufferedAmountLowThreshold uint64

	// The binaryType represents attribute MUST, on getting, return the value to
	// which it was last set. On setting, if the new value is either the string
	// "blob" or the string "arraybuffer", then set the IDL attribute to this
	// new value. Otherwise, throw a SyntaxError. When an RTCDataChannel object
	// is created, the binaryType attribute MUST be initialized to the string
	// "blob". This attribute controls how binary data is exposed to scripts.
	// binaryType                 string

	// OnOpen              func()
	// OnBufferedAmountLow func()
	// OnError             func()
	// OnClose             func()

	onMessageHandler func(sugar.Payload)
	onOpenHandler    func()

	sctpTransport *RTCSctpTransport
	dataChannel   *datachannel.DataChannel
}

// NewRTCDataChannel creates a new RTCDataChannel.
// This constructor is part of the ORTC API. It is not
// meant to be used together with the basic WebRTC API.
func NewRTCDataChannel(transport *RTCSctpTransport, params *RTCDataChannelParameters) (*RTCDataChannel, error) {
	d, err := newRTCDataChannel(params)
	if err != nil {
		return nil, err
	}

	err = d.open(transport)
	if err != nil {
		return nil, err
	}

	return d, nil
}

// newRTCDataChannel is an internal constructor for the data channel used to
// create the RTCDataChannel object before the networking is set up.
func newRTCDataChannel(params *RTCDataChannelParameters) (*RTCDataChannel, error) {
	// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #5)
	if len(params.Label) > 65535 {
		return nil, &rtcerr.TypeError{Err: ErrStringSizeLimit}
	}

	d := &RTCDataChannel{
		Label:      params.Label,
		ID:         &params.ID,
		ReadyState: RTCDataChannelStateConnecting,
	}

	return d, nil
}

// open opens the datachannel over the sctp transport
func (d *RTCDataChannel) open(sctpTransport *RTCSctpTransport) error {
	d.mu.RLock()
	d.sctpTransport = sctpTransport

	if err := d.ensureSCTP(); err != nil {
		d.mu.RUnlock()
		return err
	}

	cfg := &datachannel.Config{
		ChannelType:          datachannel.ChannelTypeReliable,   // TODO: Wiring
		Priority:             datachannel.ChannelPriorityNormal, // TODO: Wiring
		ReliabilityParameter: 0,                                 // TODO: Wiring
		Label:                d.Label,
	}

	dc, err := datachannel.Dial(d.sctpTransport.association, *d.ID, cfg)
	if err != nil {
		d.mu.RUnlock()
		return err
	}

	d.ReadyState = RTCDataChannelStateOpen
	d.mu.RUnlock()

	d.handleOpen(dc)
	return nil
}

func (d *RTCDataChannel) ensureSCTP() error {
	if d.sctpTransport == nil ||
		d.sctpTransport.association == nil {
		return errors.New("SCTP not establisched")
	}
	return nil
}

// Transport returns the RTCSctpTransport instance the RTCDataChannel is sending over.
func (d *RTCDataChannel) Transport() *RTCSctpTransport {
	d.mu.RLock()
	defer d.mu.RUnlock()

	return d.sctpTransport
}

// OnOpen sets an event handler which is invoked when
// the underlying data transport has been established (or re-established).
func (d *RTCDataChannel) OnOpen(f func()) {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.onOpenHandler = f
}

func (d *RTCDataChannel) onOpen() (done chan struct{}) {
	d.mu.RLock()
	hdlr := d.onOpenHandler
	d.mu.RUnlock()

	done = make(chan struct{})
	if hdlr == nil {
		close(done)
		return
	}

	go func() {
		hdlr()
		close(done)
	}()

	return
}

// OnMessage sets an event handler which is invoked on a message
// arrival over the sctp transport from a remote peer.
func (d *RTCDataChannel) OnMessage(f func(p sugar.Payload)) {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.onMessageHandler = f
}

func (d *RTCDataChannel) onMessage(p sugar.Payload) {
	d.mu.RLock()
	hdlr := d.onMessageHandler
	d.mu.RUnlock()

	if hdlr == nil || p == nil {
		return
	}
	hdlr(p)
}

// Onmessage sets an event handler which is invoked on a message
// arrival over the sctp transport from a remote peer.
//
// Deprecated: use OnMessage instead.
func (d *RTCDataChannel) Onmessage(f func(p sugar.Payload)) {
	d.OnMessage(f)
}

func (d *RTCDataChannel) handleOpen(dc *datachannel.DataChannel) {
	d.mu.Lock()
	d.dataChannel = dc
	d.mu.Unlock()

	d.onOpen()

	d.mu.Lock()
	defer d.mu.Unlock()

	if !defaultSettingEngine.Detach.DataChannels {
		go d.readLoop()
	}
}

func (d *RTCDataChannel) readLoop() {
	for {
		buffer := make([]byte, receiveMTU)
		n, isString, err := d.dataChannel.ReadDataChannel(buffer)
		if err != nil {
			fmt.Println("Failed to read from data channel", err)
			// TODO: Kill DataChannel/PeerConnection?
			return
		}

		if isString {
			d.onMessage(&sugar.PayloadString{Data: buffer[:n]})
			continue
		}
		d.onMessage(&sugar.PayloadBinary{Data: buffer[:n]})
	}
}

// Send sends the passed message to the DataChannel peer
func (d *RTCDataChannel) Send(payload sugar.Payload) error {
	var data []byte
	isString := false

	switch p := payload.(type) {
	case sugar.PayloadString:
		data = p.Data
		isString = true
	case sugar.PayloadBinary:
		data = p.Data
	default:
		return errors.Errorf("unknown DataChannel Payload (%s)", payload.PayloadType())
	}

	if len(data) == 0 {
		data = []byte{0}
	}

	_, err := d.dataChannel.WriteDataChannel(data, isString)
	return err
}

// Detach allows you to detach the underlying datachannel. This provides
// an idiomatic API to work with, however it disables the OnMessage callback.
// Before calling Detach you have to enable this behavior by calling
// webrtc.DetachDataChannels(). Combining detached and normal data channels
// is not supported.
// Please reffer to the data-channels-detach example and the
// pions/datachannel documentation for the correct way to handle the
// resulting DataChannel object.
func (d *RTCDataChannel) Detach() (*datachannel.DataChannel, error) {
	d.mu.Lock()
	defer d.mu.Unlock()

	if !defaultSettingEngine.Detach.DataChannels {
		return nil, errors.New("enable detaching by calling webrtc.DetachDataChannels()")
	}

	if d.dataChannel == nil {
		return nil, errors.New("datachannel not opened yet, try calling Detach from OnOpen")
	}

	return d.dataChannel, nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"bytes"
	"path/filepath"
	"strings"

	"github.com/hacdias/caddy-filemanager/file"
	"github.com/hacdias/caddy-filemanager/frontmatter"
	"github.com/spf13/hugo/parser"
)

// Editor contains the information for the editor page
type Editor struct {
	Class       string
	Mode        string
	Content     string
	FrontMatter *frontmatter.Content
}

// GetEditor gets the editor based on a FileInfo struct
func GetEditor(i *file.Info) (*Editor, error) {
	// Create a new editor variable and set the mode
	editor := new(Editor)
	editor.Mode = strings.TrimPrefix(filepath.Ext(i.Name()), ".")

	switch editor.Mode {
	case "md", "markdown", "mdown", "mmark":
		editor.Mode = "markdown"
	case "asciidoc", "adoc", "ad":
		editor.Mode = "asciidoc"
	case "rst":
		editor.Mode = "rst"
	case "html", "htm":
		editor.Mode = "html"
	case "js":
		editor.Mode = "javascript"
	}

	var page parser.Page
	var err error

	// Handle the content depending on the file extension
	switch editor.Mode {
	case "json", "toml", "yaml":
		// Defines the class and declares an error
		editor.Class = "frontmatter-only"

		// Checks if the file already has the frontmatter rune and parses it
		if frontmatter.HasRune(i.Content) {
			editor.FrontMatter, _, err = frontmatter.Pretty(i.Content)
		} else {
			editor.FrontMatter, _, err = frontmatter.Pretty(frontmatter.AppendRune(i.Content, editor.Mode))
		}

		// Check if there were any errors
		if err == nil {
			break
		}

		fallthrough
	case "markdown", "asciidoc", "rst":
		if frontmatter.HasRune(i.Content) {
			// Starts a new buffer and parses the file using Hugo's functions
			buffer := bytes.NewBuffer(i.Content)
			page, err = parser.ReadFrom(buffer)
			editor.Class = "complete"

			if err == nil {
				// Parses the page content and the frontmatter
				editor.Content = strings.TrimSpace(string(page.Content()))
				editor.FrontMatter, _, err = frontmatter.Pretty(page.FrontMatter())

				if err == nil {
					break
				}
			}
		}

		fallthrough
	default:
		editor.Class = "content-only"
		editor.Content = i.StringifyContent()
	}

	return editor, nil
}
<commit_msg>add exception to golang<commit_after>package handlers

import (
	"bytes"
	"path/filepath"
	"strings"

	"github.com/hacdias/caddy-filemanager/file"
	"github.com/hacdias/caddy-filemanager/frontmatter"
	"github.com/spf13/hugo/parser"
)

// Editor contains the information for the editor page
type Editor struct {
	Class       string
	Mode        string
	Content     string
	FrontMatter *frontmatter.Content
}

// GetEditor gets the editor based on a FileInfo struct
func GetEditor(i *file.Info) (*Editor, error) {
	// Create a new editor variable and set the mode
	editor := new(Editor)
	editor.Mode = strings.TrimPrefix(filepath.Ext(i.Name()), ".")

	switch editor.Mode {
	case "md", "markdown", "mdown", "mmark":
		editor.Mode = "markdown"
	case "asciidoc", "adoc", "ad":
		editor.Mode = "asciidoc"
	case "rst":
		editor.Mode = "rst"
	case "html", "htm":
		editor.Mode = "html"
	case "js":
		editor.Mode = "javascript"
	case "go":
		editor.Mode = "golang"
	}

	var page parser.Page
	var err error

	// Handle the content depending on the file extension
	switch editor.Mode {
	case "json", "toml", "yaml":
		// Defines the class and declares an error
		editor.Class = "frontmatter-only"

		// Checks if the file already has the frontmatter rune and parses it
		if frontmatter.HasRune(i.Content) {
			editor.FrontMatter, _, err = frontmatter.Pretty(i.Content)
		} else {
			editor.FrontMatter, _, err = frontmatter.Pretty(frontmatter.AppendRune(i.Content, editor.Mode))
		}

		// Check if there were any errors
		if err == nil {
			break
		}

		fallthrough
	case "markdown", "asciidoc", "rst":
		if frontmatter.HasRune(i.Content) {
			// Starts a new buffer and parses the file using Hugo's functions
			buffer := bytes.NewBuffer(i.Content)
			page, err = parser.ReadFrom(buffer)
			editor.Class = "complete"

			if err == nil {
				// Parses the page content and the frontmatter
				editor.Content = strings.TrimSpace(string(page.Content()))
				editor.FrontMatter, _, err = frontmatter.Pretty(page.FrontMatter())

				if err == nil {
					break
				}
			}
		}

		fallthrough
	default:
		editor.Class = "content-only"
		editor.Content = i.StringifyContent()
	}

	return editor, nil
}
<|endoftext|>


<commit_before>package list

import (
	"github.com/spf13/cobra"
	"github.com/BluePecker/JwtAuth/dialog/client"
	"fmt"
	"net/http"
	"strings"
)

func NewCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "ls",
		Short: "list user's json-web-token",
		RunE: func(cmd *cobra.Command, args []string) error {
			unixSock, err := cmd.Parent().Flags().GetString("unix-sock")
			if err != nil {
				return err
			}
			var r http.Request
			r.ParseForm()
			fmt.Println(args)
			r.Form.Add("unique", args[0])
			body := strings.TrimSpace(r.Form.Encode())
			cli := client.NewClient(unixSock)
			if body, err := cli.Post("/v1.0/token/list",
				"application/json", strings.NewReader(body)); err != nil {
				return err
			} else {
				fmt.Printf("result: %s\n", body)
			}

			return nil
		},
	}

	return cmd
}
<commit_msg>debug<commit_after>package list

import (
	"github.com/spf13/cobra"
	"github.com/BluePecker/JwtAuth/dialog/client"
	"fmt"
	"net/http"
	"strings"
)

func NewCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "ls",
		Short: "list user's json-web-token",
		RunE: func(cmd *cobra.Command, args []string) error {
			unixSock, err := cmd.Parent().Flags().GetString("unix-sock")
			if err != nil {
				return err
			}
			var r http.Request
			r.ParseForm()
			fmt.Println("args: ", args)
			r.Form.Add("unique", args[0])
			body := strings.TrimSpace(r.Form.Encode())
			cli := client.NewClient(unixSock)
			if body, err := cli.Post("/v1.0/token/list",
				"application/json", strings.NewReader(body)); err != nil {
				return err
			} else {
				fmt.Printf("result: %s\n", body)
			}

			return nil
		},
	}

	return cmd
}
<|endoftext|>


<commit_before>package autonat

import (
	"context"
	"errors"
	"math/rand"
	"sync"
	"time"

	host "github.com/libp2p/go-libp2p-host"
	peer "github.com/libp2p/go-libp2p-peer"
	ma "github.com/multiformats/go-multiaddr"
)

type NATStatus int

const (
	NATStatusUnknown NATStatus = iota
	NATStatusPublic
	NATStatusPrivate
)

var (
	AutoNATBootDelay       = 15 * time.Second
	AutoNATRefreshInterval = 15 * time.Minute

	AutoNATRequestTimeout = 60 * time.Second
)

type AutoNAT interface {
	Status() NATStatus
	PublicAddr() (ma.Multiaddr, error)
}

type AmbientAutoNAT struct {
	ctx    context.Context
	host   host.Host
	peers  map[peer.ID]struct{}
	status NATStatus
	addr   ma.Multiaddr
	mx     sync.Mutex
}

func NewAutoNAT(ctx context.Context, h host.Host) AutoNAT {
	as := &AmbientAutoNAT{
		ctx:    ctx,
		host:   h,
		peers:  make(map[peer.ID]struct{}),
		status: NATStatusUnknown,
	}

	h.Network().Notify(as)
	go as.background()

	return as
}

func (as *AmbientAutoNAT) Status() NATStatus {
	return as.status
}

func (as *AmbientAutoNAT) PublicAddr() (ma.Multiaddr, error) {
	as.mx.Lock()
	defer as.mx.Unlock()

	if as.status != NATStatusPublic {
		return nil, errors.New("NAT Status is not public")
	}

	return as.addr, nil
}

func (as *AmbientAutoNAT) background() {
	// wait a bit for the node to come online and establish some connections
	// before starting autodetection
	time.Sleep(AutoNATBootDelay)
	for {
		as.autodetect()
		select {
		case <-time.After(AutoNATRefreshInterval):
		case <-as.ctx.Done():
			return
		}
	}
}

func (as *AmbientAutoNAT) autodetect() {
	if len(as.peers) == 0 {
		log.Debugf("skipping NAT auto detection; no autonat peers")
		return
	}

	as.mx.Lock()
	peers := make([]peer.ID, 0, len(as.peers))
	for p := range as.peers {
		if len(as.host.Network().ConnsToPeer(p)) > 0 {
			peers = append(peers, p)
		}
	}

	if len(peers) == 0 {
		// we don't have any open connections, try any autonat peer that we know about
		for p := range as.peers {
			peers = append(peers, p)
		}
	}

	as.mx.Unlock()

	shufflePeers(peers)

	for _, p := range peers {
		cli := NewAutoNATClient(as.host, p)
		ctx, cancel := context.WithTimeout(as.ctx, AutoNATRequestTimeout)
		a, err := cli.Dial(ctx)
		cancel()

		switch {
		case err == nil:
			log.Debugf("NAT status is public; address through %s: %s", p.Pretty(), a.String())
			as.mx.Lock()
			as.addr = a
			as.status = NATStatusPublic
			as.mx.Unlock()
			return

		case IsDialError(err):
			log.Debugf("NAT status is private; dial error through %s: %s", p.Pretty(), err.Error())
			as.mx.Lock()
			as.status = NATStatusPrivate
			as.mx.Unlock()
			return

		default:
			log.Debugf("Error dialing through %s: %s", p.Pretty(), err.Error())
		}
	}

	as.mx.Lock()
	as.status = NATStatusUnknown
	as.mx.Unlock()
}

func shufflePeers(peers []peer.ID) {
	for i := range peers {
		j := rand.Intn(i + 1)
		peers[i], peers[j] = peers[j], peers[i]
	}
}
<commit_msg>refactor getPeers for locked scope<commit_after>package autonat

import (
	"context"
	"errors"
	"math/rand"
	"sync"
	"time"

	host "github.com/libp2p/go-libp2p-host"
	peer "github.com/libp2p/go-libp2p-peer"
	ma "github.com/multiformats/go-multiaddr"
)

type NATStatus int

const (
	NATStatusUnknown NATStatus = iota
	NATStatusPublic
	NATStatusPrivate
)

var (
	AutoNATBootDelay       = 15 * time.Second
	AutoNATRefreshInterval = 15 * time.Minute

	AutoNATRequestTimeout = 60 * time.Second
)

type AutoNAT interface {
	Status() NATStatus
	PublicAddr() (ma.Multiaddr, error)
}

type AmbientAutoNAT struct {
	ctx    context.Context
	host   host.Host
	peers  map[peer.ID]struct{}
	status NATStatus
	addr   ma.Multiaddr
	mx     sync.Mutex
}

func NewAutoNAT(ctx context.Context, h host.Host) AutoNAT {
	as := &AmbientAutoNAT{
		ctx:    ctx,
		host:   h,
		peers:  make(map[peer.ID]struct{}),
		status: NATStatusUnknown,
	}

	h.Network().Notify(as)
	go as.background()

	return as
}

func (as *AmbientAutoNAT) Status() NATStatus {
	return as.status
}

func (as *AmbientAutoNAT) PublicAddr() (ma.Multiaddr, error) {
	as.mx.Lock()
	defer as.mx.Unlock()

	if as.status != NATStatusPublic {
		return nil, errors.New("NAT Status is not public")
	}

	return as.addr, nil
}

func (as *AmbientAutoNAT) background() {
	// wait a bit for the node to come online and establish some connections
	// before starting autodetection
	time.Sleep(AutoNATBootDelay)
	for {
		as.autodetect()
		select {
		case <-time.After(AutoNATRefreshInterval):
		case <-as.ctx.Done():
			return
		}
	}
}

func (as *AmbientAutoNAT) autodetect() {
	peers := as.getPeers()

	if len(peers) == 0 {
		log.Debugf("skipping NAT auto detection; no autonat peers")
		return
	}

	for _, p := range peers {
		cli := NewAutoNATClient(as.host, p)
		ctx, cancel := context.WithTimeout(as.ctx, AutoNATRequestTimeout)
		a, err := cli.Dial(ctx)
		cancel()

		switch {
		case err == nil:
			log.Debugf("NAT status is public; address through %s: %s", p.Pretty(), a.String())
			as.mx.Lock()
			as.addr = a
			as.status = NATStatusPublic
			as.mx.Unlock()
			return

		case IsDialError(err):
			log.Debugf("NAT status is private; dial error through %s: %s", p.Pretty(), err.Error())
			as.mx.Lock()
			as.status = NATStatusPrivate
			as.mx.Unlock()
			return

		default:
			log.Debugf("Error dialing through %s: %s", p.Pretty(), err.Error())
		}
	}

	as.mx.Lock()
	as.status = NATStatusUnknown
	as.mx.Unlock()
}

func (as *AmbientAutoNAT) getPeers() []peer.ID {
	as.mx.Lock()
	defer as.mx.Unlock()

	if len(as.peers) == 0 {
		return nil
	}

	peers := make([]peer.ID, 0, len(as.peers))
	for p := range as.peers {
		if len(as.host.Network().ConnsToPeer(p)) > 0 {
			peers = append(peers, p)
		}
	}

	if len(peers) == 0 {
		// we don't have any open connections, try any autonat peer that we know about
		for p := range as.peers {
			peers = append(peers, p)
		}
	}

	shufflePeers(peers)

	return peers
}

func shufflePeers(peers []peer.ID) {
	for i := range peers {
		j := rand.Intn(i + 1)
		peers[i], peers[j] = peers[j], peers[i]
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"database/sql"
	"encoding/base64"
	"encoding/gob"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	"github.com/gorilla/securecookie"

	_ "github.com/go-sql-driver/mysql"

	"github.com/AscendTech4H/turtleauth"
)

// Credentials which stores google ids.
type Credentials struct {
	Cid     string `json:"client_id"`
	Csecret string `json:"client_secret"`
}

// User is a retrieved and authentiacted google user.
type User struct {
	Sub           string `json:"sub"`
	Name          string `json:"name"`
	GivenName     string `json:"given_name"`
	FamilyName    string `json:"family_name"`
	Profile       string `json:"profile"`
	Picture       string `json:"picture"`
	Email         string `json:"email"`
	EmailVerified string `json:"email_verified"`
	Gender        string `json:"gender"`
}

var cred Credentials
var conf *oauth2.Config
var state string

func init() {

}

func main() {
	log.Println("Starting auth server. . . ")
	var dbs string
	var addr string
	var k string
	var credfile string
	flag.StringVar(&dbs, "db", "/", "Database source string")
	flag.StringVar(&addr, "addr", ":9001", "Server port for authentication")
	flag.StringVar(&k, "key", ".authkey", "Key file")
	flag.StringVar(&credfile, "cred", ".cred", "Google oauth2 credentials file")
	flag.Parse()
	log.Println("Loading keys. . . ")
	d, err := ioutil.ReadFile(k)
	if err != nil {
		panic(err)
	}
	var keys struct {
		HashKey  []byte
		BlockKey []byte
	}
	err = json.Unmarshal(d, &keys)
	if err != nil {
		panic(err)
	}
	sc := securecookie.New(keys.HashKey, keys.BlockKey)
	sc.SetSerializer(securecookie.GobEncoder{})
	log.Println("Loading oauth credentials. . . ")
	file, err := ioutil.ReadFile(credfile)
	if err != nil {
		log.Printf("File error: %v\n", err)
		os.Exit(1)
	}
	json.Unmarshal(file, &cred)
	fmt.Println(cred)

	conf = &oauth2.Config{
		ClientID:     cred.Cid,
		ClientSecret: cred.Csecret,
		RedirectURL:  "https://git.ascendtech4h.org/auth",
		Scopes: []string{
			"https://www.googleapis.com/auth/userinfo.email", // You have to select your own scope from here -> https://developers.google.com/identity/protocols/googlescopes#google_sign-in
		},
		Endpoint: google.Endpoint,
	}
	log.Println("Connecting to DB. . . ")
	db, err := sql.Open("mysql", "/")
	if err != nil {
		panic(err)
	}
	defer db.Close()
	log.Println("Connected")
	http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("pong"))
	})
	http.HandleFunc("/perm", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Incorrect request method", http.StatusMethodNotAllowed)
		}
		var ac turtleauth.AuthCheck
		err := gob.NewDecoder(r.Body).Decode(&ac)
		if err != nil {
			http.Error(w, "Decode error", http.StatusInternalServerError)
			return
		}
		if !ac.P.Check() {
			http.Error(w, "Bad PermissionClass", http.StatusBadRequest)
			return
		}
		var uid int
		err = sc.Decode("turtleauth", ac.C.Value, &uid)
		if err != nil {
			http.Error(w, "Cookie error", http.StatusUnauthorized)
			return
		}
		res, err := db.Query(fmt.Sprintf("SELECT * FROM PERM_%s WHERE id=%d", ac.P.Name, uid))
		if err != nil {
			http.Error(w, "SQL Error", http.StatusInternalServerError)
			return
		}
		defer res.Close()
		if res.Next() {
			w.WriteHeader(http.StatusOK)
			w.Write([]byte("Auth successful"))
		} else {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Auth rejected"))
		}
	})
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			http.Error(w, "Incorrect request method", http.StatusMethodNotAllowed)
			return
		}
		err := r.ParseForm()
		if err != nil {
			http.Error(w, "Form parse error", http.StatusBadRequest)
			return
		}
		dest := r.FormValue("dest")
		if dest == "" {
			http.Error(w, "Missing destination", http.StatusBadRequest)
			return
		}
		expire := time.Now().Add(5 * time.Minute) //Delete cookie in 5 min
		http.SetCookie(w, &http.Cookie{
			Name:    "authdest",
			Value:   dest,
			Expires: expire,
		})
		key := make([]byte, 32)
		_, err = rand.Read(key)
		if err != nil {
			http.Error(w, "Random number generator failure", http.StatusInternalServerError)
			return
		}
		kstr := base64.StdEncoding.EncodeToString(key)
		cook := &http.Cookie{
			Name:    "state",
			Value:   kstr,
			Expires: expire,
		}
		http.SetCookie(w, cook)
		authaddr := conf.AuthCodeURL(kstr)
		http.Redirect(w, r, authaddr, http.StatusMovedPermanently)
	})
	http.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			http.Error(w, "Incorrect request method", http.StatusMethodNotAllowed)
			return
		}
		cook, err := r.Cookie("state")
		if err != nil {
			http.Error(w, "Error getting state cookie", http.StatusBadRequest)
			return
		}
		http.SetCookie(w, &http.Cookie{
			Name:   "state",
			Value:  "",
			MaxAge: -1, //Delete now
		})
		dest, err := r.Cookie("authdest")
		if err != nil {
			http.Error(w, "Error retrieving authdest cookie", http.StatusBadRequest)
			return
		}
		http.SetCookie(w, &http.Cookie{
			Name:   "authdest",
			Value:  "",
			MaxAge: -1, //Delete now
		})
		if r.URL.Query().Get("state") != cook.Value {
			http.Error(w, "Unmatched state", http.StatusUnauthorized)
			return
		}
		tok, err := conf.Exchange(oauth2.NoContext, cook.Value)
		if err != nil {
			http.Error(w, "Exchange error", http.StatusUnauthorized)
			log.Printf("Exchange error: %s\n", err.Error())
		}
		client := conf.Client(oauth2.NoContext, tok)
		lookup, err := client.Get("https://www.googleapis.com/oauth2/v3/userinfo")
		if err != nil {
			http.Error(w, "User info request error", http.StatusUnauthorized)
			return
		}
		defer lookup.Body.Close()
		var uinfo User
		err = json.NewDecoder(lookup.Body).Decode(&uinfo)
		if err != nil {
			http.Error(w, "User info request decode error", http.StatusInternalServerError)
			return
		}
		res, err := db.Query("SELECT id FROM users WHERE email=?", uinfo.Email)
		if err != nil {
			http.Error(w, "Database errror", http.StatusInternalServerError)
			log.Printf("Database error: %s\n", err.Error())
			return
		}
		var id int
		if !res.Next() {
			_, err = db.Exec("INSERT INTO users (email) VALUES (?)", uinfo.Email)
			if err != nil {
				http.Error(w, "Database errror", http.StatusInternalServerError)
				log.Printf("Database error: %s\n", err.Error())
				return
			}
			res, err = db.Query("SELECT id FROM users WHERE email=?", uinfo.Email)
			if err != nil {
				http.Error(w, "Database errror", http.StatusInternalServerError)
				log.Printf("Database error: %s\n", err.Error())
				return
			}
		}
		err = res.Scan(&id)
		if err != nil {
			http.Error(w, "Database errror", http.StatusInternalServerError)
			log.Printf("Database error: %s\n", err.Error())
			return
		}
		cstr, err := sc.Encode("turtleauth", &id)
		if err != nil {
			http.Error(w, "Cookie encryption error", http.StatusInternalServerError)
			log.Printf("Cookie encryption error: %s\n", err.Error())
			return
		}
		http.SetCookie(w, &http.Cookie{
			Name:  "turtleauth",
			Value: cstr,
		})
		//All good - redirect
		http.Redirect(w, r, dest.Value, http.StatusMovedPermanently)
	})
	log.Println("Starting http server")
	panic(http.ListenAndServe(addr, nil))
}
<commit_msg>Fix oauth2 redirect url<commit_after>package main

import (
	"crypto/rand"
	"database/sql"
	"encoding/base64"
	"encoding/gob"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"

	"github.com/gorilla/securecookie"

	_ "github.com/go-sql-driver/mysql"

	"github.com/AscendTech4H/turtleauth"
)

// Credentials which stores google ids.
type Credentials struct {
	Cid     string `json:"client_id"`
	Csecret string `json:"client_secret"`
}

// User is a retrieved and authentiacted google user.
type User struct {
	Sub           string `json:"sub"`
	Name          string `json:"name"`
	GivenName     string `json:"given_name"`
	FamilyName    string `json:"family_name"`
	Profile       string `json:"profile"`
	Picture       string `json:"picture"`
	Email         string `json:"email"`
	EmailVerified string `json:"email_verified"`
	Gender        string `json:"gender"`
}

var cred Credentials
var conf *oauth2.Config
var state string

func init() {

}

func main() {
	log.Println("Starting auth server. . . ")
	var dbs string
	var addr string
	var k string
	var credfile string
	flag.StringVar(&dbs, "db", "/", "Database source string")
	flag.StringVar(&addr, "addr", ":9001", "Server port for authentication")
	flag.StringVar(&k, "key", ".authkey", "Key file")
	flag.StringVar(&credfile, "cred", ".cred", "Google oauth2 credentials file")
	flag.Parse()
	log.Println("Loading keys. . . ")
	d, err := ioutil.ReadFile(k)
	if err != nil {
		panic(err)
	}
	var keys struct {
		HashKey  []byte
		BlockKey []byte
	}
	err = json.Unmarshal(d, &keys)
	if err != nil {
		panic(err)
	}
	sc := securecookie.New(keys.HashKey, keys.BlockKey)
	sc.SetSerializer(securecookie.GobEncoder{})
	log.Println("Loading oauth credentials. . . ")
	file, err := ioutil.ReadFile(credfile)
	if err != nil {
		log.Printf("File error: %v\n", err)
		os.Exit(1)
	}
	json.Unmarshal(file, &cred)
	fmt.Println(cred)

	conf = &oauth2.Config{
		ClientID:     cred.Cid,
		ClientSecret: cred.Csecret,
		RedirectURL:  "https://auth.ascendtech4h.org/auth",
		Scopes: []string{
			"https://www.googleapis.com/auth/userinfo.email", // You have to select your own scope from here -> https://developers.google.com/identity/protocols/googlescopes#google_sign-in
		},
		Endpoint: google.Endpoint,
	}
	log.Println("Connecting to DB. . . ")
	db, err := sql.Open("mysql", "/")
	if err != nil {
		panic(err)
	}
	defer db.Close()
	log.Println("Connected")
	http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("pong"))
	})
	http.HandleFunc("/perm", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost {
			http.Error(w, "Incorrect request method", http.StatusMethodNotAllowed)
		}
		var ac turtleauth.AuthCheck
		err := gob.NewDecoder(r.Body).Decode(&ac)
		if err != nil {
			http.Error(w, "Decode error", http.StatusInternalServerError)
			return
		}
		if !ac.P.Check() {
			http.Error(w, "Bad PermissionClass", http.StatusBadRequest)
			return
		}
		var uid int
		err = sc.Decode("turtleauth", ac.C.Value, &uid)
		if err != nil {
			http.Error(w, "Cookie error", http.StatusUnauthorized)
			return
		}
		res, err := db.Query(fmt.Sprintf("SELECT * FROM PERM_%s WHERE id=%d", ac.P.Name, uid))
		if err != nil {
			http.Error(w, "SQL Error", http.StatusInternalServerError)
			return
		}
		defer res.Close()
		if res.Next() {
			w.WriteHeader(http.StatusOK)
			w.Write([]byte("Auth successful"))
		} else {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Auth rejected"))
		}
	})
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			http.Error(w, "Incorrect request method", http.StatusMethodNotAllowed)
			return
		}
		err := r.ParseForm()
		if err != nil {
			http.Error(w, "Form parse error", http.StatusBadRequest)
			return
		}
		dest := r.FormValue("dest")
		if dest == "" {
			http.Error(w, "Missing destination", http.StatusBadRequest)
			return
		}
		expire := time.Now().Add(5 * time.Minute) //Delete cookie in 5 min
		http.SetCookie(w, &http.Cookie{
			Name:    "authdest",
			Value:   dest,
			Expires: expire,
		})
		key := make([]byte, 32)
		_, err = rand.Read(key)
		if err != nil {
			http.Error(w, "Random number generator failure", http.StatusInternalServerError)
			return
		}
		kstr := base64.StdEncoding.EncodeToString(key)
		cook := &http.Cookie{
			Name:    "state",
			Value:   kstr,
			Expires: expire,
		}
		http.SetCookie(w, cook)
		authaddr := conf.AuthCodeURL(kstr)
		http.Redirect(w, r, authaddr, http.StatusMovedPermanently)
	})
	http.HandleFunc("/auth", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet {
			http.Error(w, "Incorrect request method", http.StatusMethodNotAllowed)
			return
		}
		cook, err := r.Cookie("state")
		if err != nil {
			http.Error(w, "Error getting state cookie", http.StatusBadRequest)
			return
		}
		http.SetCookie(w, &http.Cookie{
			Name:   "state",
			Value:  "",
			MaxAge: -1, //Delete now
		})
		dest, err := r.Cookie("authdest")
		if err != nil {
			http.Error(w, "Error retrieving authdest cookie", http.StatusBadRequest)
			return
		}
		http.SetCookie(w, &http.Cookie{
			Name:   "authdest",
			Value:  "",
			MaxAge: -1, //Delete now
		})
		if r.URL.Query().Get("state") != cook.Value {
			http.Error(w, "Unmatched state", http.StatusUnauthorized)
			return
		}
		tok, err := conf.Exchange(oauth2.NoContext, cook.Value)
		if err != nil {
			http.Error(w, "Exchange error", http.StatusUnauthorized)
			log.Printf("Exchange error: %s\n", err.Error())
		}
		client := conf.Client(oauth2.NoContext, tok)
		lookup, err := client.Get("https://www.googleapis.com/oauth2/v3/userinfo")
		if err != nil {
			http.Error(w, "User info request error", http.StatusUnauthorized)
			return
		}
		defer lookup.Body.Close()
		var uinfo User
		err = json.NewDecoder(lookup.Body).Decode(&uinfo)
		if err != nil {
			http.Error(w, "User info request decode error", http.StatusInternalServerError)
			return
		}
		res, err := db.Query("SELECT id FROM users WHERE email=?", uinfo.Email)
		if err != nil {
			http.Error(w, "Database errror", http.StatusInternalServerError)
			log.Printf("Database error: %s\n", err.Error())
			return
		}
		var id int
		if !res.Next() {
			_, err = db.Exec("INSERT INTO users (email) VALUES (?)", uinfo.Email)
			if err != nil {
				http.Error(w, "Database errror", http.StatusInternalServerError)
				log.Printf("Database error: %s\n", err.Error())
				return
			}
			res, err = db.Query("SELECT id FROM users WHERE email=?", uinfo.Email)
			if err != nil {
				http.Error(w, "Database errror", http.StatusInternalServerError)
				log.Printf("Database error: %s\n", err.Error())
				return
			}
		}
		err = res.Scan(&id)
		if err != nil {
			http.Error(w, "Database errror", http.StatusInternalServerError)
			log.Printf("Database error: %s\n", err.Error())
			return
		}
		cstr, err := sc.Encode("turtleauth", &id)
		if err != nil {
			http.Error(w, "Cookie encryption error", http.StatusInternalServerError)
			log.Printf("Cookie encryption error: %s\n", err.Error())
			return
		}
		http.SetCookie(w, &http.Cookie{
			Name:  "turtleauth",
			Value: cstr,
		})
		//All good - redirect
		http.Redirect(w, r, dest.Value, http.StatusMovedPermanently)
	})
	log.Println("Starting http server")
	panic(http.ListenAndServe(addr, nil))
}
<|endoftext|>


<commit_before><commit_msg>Sets CORS headers<commit_after><|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"net"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsEip() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsEipCreate,
		Read:   resourceAwsEipRead,
		Update: resourceAwsEipUpdate,
		Delete: resourceAwsEipDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"vpc": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"instance": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"network_interface": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"allocation_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"association_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"public_ip": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"private_ip": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"associate_with_private_ip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	// By default, we're not in a VPC
	domainOpt := ""
	if v := d.Get("vpc"); v != nil && v.(bool) {
		domainOpt = "vpc"
	}

	allocOpts := &ec2.AllocateAddressInput{
		Domain: aws.String(domainOpt),
	}

	log.Printf("[DEBUG] EIP create configuration: %#v", allocOpts)
	allocResp, err := ec2conn.AllocateAddress(allocOpts)
	if err != nil {
		return fmt.Errorf("Error creating EIP: %s", err)
	}

	// The domain tells us if we're in a VPC or not
	d.Set("domain", allocResp.Domain)

	// Assign the eips (unique) allocation id for use later
	// the EIP api has a conditional unique ID (really), so
	// if we're in a VPC we need to save the ID as such, otherwise
	// it defaults to using the public IP
	log.Printf("[DEBUG] EIP Allocate: %#v", allocResp)
	if d.Get("domain").(string) == "vpc" {
		d.SetId(*allocResp.AllocationId)
	} else {
		d.SetId(*allocResp.PublicIp)
	}

	log.Printf("[INFO] EIP ID: %s (domain: %v)", d.Id(), *allocResp.Domain)
	return resourceAwsEipUpdate(d, meta)
}

func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	domain := resourceAwsEipDomain(d)
	id := d.Id()

	req := &ec2.DescribeAddressesInput{}

	if domain == "vpc" {
		req.AllocationIds = []*string{aws.String(id)}
	} else {
		req.PublicIps = []*string{aws.String(id)}
	}

	log.Printf(
		"[DEBUG] EIP describe configuration: %s (domain: %s)",
		req, domain)

	describeAddresses, err := ec2conn.DescribeAddresses(req)
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && (ec2err.Code() == "InvalidAllocationID.NotFound" || ec2err.Code() == "InvalidAddress.NotFound") {
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving EIP: %s", err)
	}

	// Verify AWS returned our EIP
	if len(describeAddresses.Addresses) != 1 ||
		domain == "vpc" && *describeAddresses.Addresses[0].AllocationId != id ||
		*describeAddresses.Addresses[0].PublicIp != id {
		if err != nil {
			return fmt.Errorf("Unable to find EIP: %#v", describeAddresses.Addresses)
		}
	}

	address := describeAddresses.Addresses[0]

	d.Set("association_id", address.AssociationId)
	if address.InstanceId != nil {
		d.Set("instance", address.InstanceId)
	} else {
		d.Set("instance", "")
	}
	if address.NetworkInterfaceId != nil {
		d.Set("network_interface", address.NetworkInterfaceId)
	} else {
		d.Set("network_interface", "")
	}
	d.Set("private_ip", address.PrivateIpAddress)
	d.Set("public_ip", address.PublicIp)

	// On import (domain never set, which it must've been if we created),
	// set the 'vpc' attribute depending on if we're in a VPC.
	if address.Domain != nil {
		d.Set("vpc", *address.Domain == "vpc")
	}

	d.Set("domain", address.Domain)

	// Force ID to be an Allocation ID if we're on a VPC
	// This allows users to import the EIP based on the IP if they are in a VPC
	if *address.Domain == "vpc" && net.ParseIP(id) != nil {
		log.Printf("[DEBUG] Re-assigning EIP ID (%s) to it's Allocation ID (%s)", d.Id(), *address.AllocationId)
		d.SetId(*address.AllocationId)
	}

	return nil
}

func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	domain := resourceAwsEipDomain(d)

	// Associate to instance or interface if specified
	v_instance, ok_instance := d.GetOk("instance")
	v_interface, ok_interface := d.GetOk("network_interface")

	if ok_instance || ok_interface {
		instanceId := v_instance.(string)
		networkInterfaceId := v_interface.(string)

		assocOpts := &ec2.AssociateAddressInput{
			InstanceId: aws.String(instanceId),
			PublicIp:   aws.String(d.Id()),
		}

		// more unique ID conditionals
		if domain == "vpc" {
			var privateIpAddress *string
			if v := d.Get("associate_with_private_ip").(string); v != "" {
				privateIpAddress = aws.String(v)
			}
			assocOpts = &ec2.AssociateAddressInput{
				NetworkInterfaceId: aws.String(networkInterfaceId),
				InstanceId:         aws.String(instanceId),
				AllocationId:       aws.String(d.Id()),
				PrivateIpAddress:   privateIpAddress,
			}
		}

		log.Printf("[DEBUG] EIP associate configuration: %s (domain: %s)", assocOpts, domain)

		err := resource.Retry(1*time.Minute, func() *resource.RetryError {
			_, err := ec2conn.AssociateAddress(assocOpts)
			if err != nil {
				if awsErr, ok := err.(awserr.Error); ok {
					if awsErr.Code() == "InvalidAllocationID.NotFound" {
						return resource.RetryableError(awsErr)
					}
				}
				return resource.NonRetryableError(err)
			}
			return nil
		})
		if err != nil {
			// Prevent saving instance if association failed
			// e.g. missing internet gateway in VPC
			d.Set("instance", "")
			d.Set("network_interface", "")
			return fmt.Errorf("Failure associating EIP: %s", err)
		}
	}

	return resourceAwsEipRead(d, meta)
}

func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	if err := resourceAwsEipRead(d, meta); err != nil {
		return err
	}
	if d.Id() == "" {
		// This might happen from the read
		return nil
	}

	// If we are attached to an instance or interface, detach first.
	if d.Get("instance").(string) != "" || d.Get("association_id").(string) != "" {
		log.Printf("[DEBUG] Disassociating EIP: %s", d.Id())
		var err error
		switch resourceAwsEipDomain(d) {
		case "vpc":
			_, err = ec2conn.DisassociateAddress(&ec2.DisassociateAddressInput{
				AssociationId: aws.String(d.Get("association_id").(string)),
			})
		case "standard":
			_, err = ec2conn.DisassociateAddress(&ec2.DisassociateAddressInput{
				PublicIp: aws.String(d.Get("public_ip").(string)),
			})
		}

		if err != nil {
			// First check if the association ID is not found. If this
			// is the case, then it was already disassociated somehow,
			// and that is okay. The most commmon reason for this is that
			// the instance or ENI it was attached it was destroyed.
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidAssociationID.NotFound" {
				err = nil
			}
		}

		if err != nil {
			return err
		}
	}

	domain := resourceAwsEipDomain(d)
	return resource.Retry(3*time.Minute, func() *resource.RetryError {
		var err error
		switch domain {
		case "vpc":
			log.Printf(
				"[DEBUG] EIP release (destroy) address allocation: %v",
				d.Id())
			_, err = ec2conn.ReleaseAddress(&ec2.ReleaseAddressInput{
				AllocationId: aws.String(d.Id()),
			})
		case "standard":
			log.Printf("[DEBUG] EIP release (destroy) address: %v", d.Id())
			_, err = ec2conn.ReleaseAddress(&ec2.ReleaseAddressInput{
				PublicIp: aws.String(d.Id()),
			})
		}

		if err == nil {
			return nil
		}
		if _, ok := err.(awserr.Error); !ok {
			return resource.NonRetryableError(err)
		}

		return resource.RetryableError(err)
	})
}

func resourceAwsEipDomain(d *schema.ResourceData) string {
	if v, ok := d.GetOk("domain"); ok {
		return v.(string)
	} else if strings.Contains(d.Id(), "eipalloc") {
		// We have to do this for backwards compatibility since TF 0.1
		// didn't have the "domain" computed attribute.
		return "vpc"
	}

	return "standard"
}
<commit_msg>provider/aws: Increase EIP update timeout (#14381)<commit_after>package aws

import (
	"fmt"
	"log"
	"net"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsEip() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsEipCreate,
		Read:   resourceAwsEipRead,
		Update: resourceAwsEipUpdate,
		Delete: resourceAwsEipDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"vpc": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"instance": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"network_interface": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"allocation_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"association_id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"domain": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"public_ip": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"private_ip": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"associate_with_private_ip": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceAwsEipCreate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	// By default, we're not in a VPC
	domainOpt := ""
	if v := d.Get("vpc"); v != nil && v.(bool) {
		domainOpt = "vpc"
	}

	allocOpts := &ec2.AllocateAddressInput{
		Domain: aws.String(domainOpt),
	}

	log.Printf("[DEBUG] EIP create configuration: %#v", allocOpts)
	allocResp, err := ec2conn.AllocateAddress(allocOpts)
	if err != nil {
		return fmt.Errorf("Error creating EIP: %s", err)
	}

	// The domain tells us if we're in a VPC or not
	d.Set("domain", allocResp.Domain)

	// Assign the eips (unique) allocation id for use later
	// the EIP api has a conditional unique ID (really), so
	// if we're in a VPC we need to save the ID as such, otherwise
	// it defaults to using the public IP
	log.Printf("[DEBUG] EIP Allocate: %#v", allocResp)
	if d.Get("domain").(string) == "vpc" {
		d.SetId(*allocResp.AllocationId)
	} else {
		d.SetId(*allocResp.PublicIp)
	}

	log.Printf("[INFO] EIP ID: %s (domain: %v)", d.Id(), *allocResp.Domain)
	return resourceAwsEipUpdate(d, meta)
}

func resourceAwsEipRead(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	domain := resourceAwsEipDomain(d)
	id := d.Id()

	req := &ec2.DescribeAddressesInput{}

	if domain == "vpc" {
		req.AllocationIds = []*string{aws.String(id)}
	} else {
		req.PublicIps = []*string{aws.String(id)}
	}

	log.Printf(
		"[DEBUG] EIP describe configuration: %s (domain: %s)",
		req, domain)

	describeAddresses, err := ec2conn.DescribeAddresses(req)
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && (ec2err.Code() == "InvalidAllocationID.NotFound" || ec2err.Code() == "InvalidAddress.NotFound") {
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving EIP: %s", err)
	}

	// Verify AWS returned our EIP
	if len(describeAddresses.Addresses) != 1 ||
		domain == "vpc" && *describeAddresses.Addresses[0].AllocationId != id ||
		*describeAddresses.Addresses[0].PublicIp != id {
		if err != nil {
			return fmt.Errorf("Unable to find EIP: %#v", describeAddresses.Addresses)
		}
	}

	address := describeAddresses.Addresses[0]

	d.Set("association_id", address.AssociationId)
	if address.InstanceId != nil {
		d.Set("instance", address.InstanceId)
	} else {
		d.Set("instance", "")
	}
	if address.NetworkInterfaceId != nil {
		d.Set("network_interface", address.NetworkInterfaceId)
	} else {
		d.Set("network_interface", "")
	}
	d.Set("private_ip", address.PrivateIpAddress)
	d.Set("public_ip", address.PublicIp)

	// On import (domain never set, which it must've been if we created),
	// set the 'vpc' attribute depending on if we're in a VPC.
	if address.Domain != nil {
		d.Set("vpc", *address.Domain == "vpc")
	}

	d.Set("domain", address.Domain)

	// Force ID to be an Allocation ID if we're on a VPC
	// This allows users to import the EIP based on the IP if they are in a VPC
	if *address.Domain == "vpc" && net.ParseIP(id) != nil {
		log.Printf("[DEBUG] Re-assigning EIP ID (%s) to it's Allocation ID (%s)", d.Id(), *address.AllocationId)
		d.SetId(*address.AllocationId)
	}

	return nil
}

func resourceAwsEipUpdate(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	domain := resourceAwsEipDomain(d)

	// Associate to instance or interface if specified
	v_instance, ok_instance := d.GetOk("instance")
	v_interface, ok_interface := d.GetOk("network_interface")

	if ok_instance || ok_interface {
		instanceId := v_instance.(string)
		networkInterfaceId := v_interface.(string)

		assocOpts := &ec2.AssociateAddressInput{
			InstanceId: aws.String(instanceId),
			PublicIp:   aws.String(d.Id()),
		}

		// more unique ID conditionals
		if domain == "vpc" {
			var privateIpAddress *string
			if v := d.Get("associate_with_private_ip").(string); v != "" {
				privateIpAddress = aws.String(v)
			}
			assocOpts = &ec2.AssociateAddressInput{
				NetworkInterfaceId: aws.String(networkInterfaceId),
				InstanceId:         aws.String(instanceId),
				AllocationId:       aws.String(d.Id()),
				PrivateIpAddress:   privateIpAddress,
			}
		}

		log.Printf("[DEBUG] EIP associate configuration: %s (domain: %s)", assocOpts, domain)

		err := resource.Retry(5*time.Minute, func() *resource.RetryError {
			_, err := ec2conn.AssociateAddress(assocOpts)
			if err != nil {
				if awsErr, ok := err.(awserr.Error); ok {
					if awsErr.Code() == "InvalidAllocationID.NotFound" {
						return resource.RetryableError(awsErr)
					}
				}
				return resource.NonRetryableError(err)
			}
			return nil
		})
		if err != nil {
			// Prevent saving instance if association failed
			// e.g. missing internet gateway in VPC
			d.Set("instance", "")
			d.Set("network_interface", "")
			return fmt.Errorf("Failure associating EIP: %s", err)
		}
	}

	return resourceAwsEipRead(d, meta)
}

func resourceAwsEipDelete(d *schema.ResourceData, meta interface{}) error {
	ec2conn := meta.(*AWSClient).ec2conn

	if err := resourceAwsEipRead(d, meta); err != nil {
		return err
	}
	if d.Id() == "" {
		// This might happen from the read
		return nil
	}

	// If we are attached to an instance or interface, detach first.
	if d.Get("instance").(string) != "" || d.Get("association_id").(string) != "" {
		log.Printf("[DEBUG] Disassociating EIP: %s", d.Id())
		var err error
		switch resourceAwsEipDomain(d) {
		case "vpc":
			_, err = ec2conn.DisassociateAddress(&ec2.DisassociateAddressInput{
				AssociationId: aws.String(d.Get("association_id").(string)),
			})
		case "standard":
			_, err = ec2conn.DisassociateAddress(&ec2.DisassociateAddressInput{
				PublicIp: aws.String(d.Get("public_ip").(string)),
			})
		}

		if err != nil {
			// First check if the association ID is not found. If this
			// is the case, then it was already disassociated somehow,
			// and that is okay. The most commmon reason for this is that
			// the instance or ENI it was attached it was destroyed.
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidAssociationID.NotFound" {
				err = nil
			}
		}

		if err != nil {
			return err
		}
	}

	domain := resourceAwsEipDomain(d)
	return resource.Retry(3*time.Minute, func() *resource.RetryError {
		var err error
		switch domain {
		case "vpc":
			log.Printf(
				"[DEBUG] EIP release (destroy) address allocation: %v",
				d.Id())
			_, err = ec2conn.ReleaseAddress(&ec2.ReleaseAddressInput{
				AllocationId: aws.String(d.Id()),
			})
		case "standard":
			log.Printf("[DEBUG] EIP release (destroy) address: %v", d.Id())
			_, err = ec2conn.ReleaseAddress(&ec2.ReleaseAddressInput{
				PublicIp: aws.String(d.Id()),
			})
		}

		if err == nil {
			return nil
		}
		if _, ok := err.(awserr.Error); !ok {
			return resource.NonRetryableError(err)
		}

		return resource.RetryableError(err)
	})
}

func resourceAwsEipDomain(d *schema.ResourceData) string {
	if v, ok := d.GetOk("domain"); ok {
		return v.(string)
	} else if strings.Contains(d.Id(), "eipalloc") {
		// We have to do this for backwards compatibility since TF 0.1
		// didn't have the "domain" computed attribute.
		return "vpc"
	}

	return "standard"
}
<|endoftext|>


<commit_before>package server

import (
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/juju/errors"
	"github.com/ngaut/log"
)

const (
	etcdTimeout = time.Second * 3
)

// Server is the pd server.
type Server struct {
	cfg *Config

	listener net.Listener

	client *clientv3.Client

	isLeader int64
	// leader value saved in etcd leader key.
	// Every write will use this to check leader validation.
	leaderValue string

	wg sync.WaitGroup

	connsLock sync.Mutex
	conns     map[*conn]struct{}

	closed int64

	// for tso
	ts            atomic.Value
	lastSavedTime time.Time

	// for id allocator, we can use one allocator for
	// node, store, region and peer, because we just need
	// a unique ID.
	idAlloc *idAllocator

	// for raft cluster
	clusterLock sync.RWMutex
	clusters    map[uint64]*raftCluster

	msgID uint64
}

// NewServer creates the pd server with given configuration.
func NewServer(cfg *Config) (*Server, error) {
	cfg.adjust()

	log.Infof("create etcd v3 client with endpoints %v", cfg.EtcdAddrs)
	client, err := clientv3.New(clientv3.Config{
		Endpoints:   cfg.EtcdAddrs,
		DialTimeout: etcdTimeout,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}

	log.Infof("listening address %s", cfg.Addr)
	l, err := net.Listen("tcp", cfg.Addr)
	if err != nil {
		client.Close()
		return nil, errors.Trace(err)
	}

	s := &Server{
		cfg:      cfg,
		listener: l,
		client:   client,
		isLeader: 0,
		conns:    make(map[*conn]struct{}),
		closed:   0,
		clusters: make(map[uint64]*raftCluster),
	}

	s.idAlloc = &idAllocator{s: s}

	return s, nil
}

// Close closes the server.
func (s *Server) Close() {
	if !atomic.CompareAndSwapInt64(&s.closed, 0, 1) {
		// server is already closed
		return
	}

	log.Info("closing server")

	s.enableLeader(false)

	if s.listener != nil {
		s.listener.Close()
	}

	if s.client != nil {
		s.client.Close()
	}

	s.wg.Wait()
}

// IsClosed checks whether server is closed or not.
func (s *Server) IsClosed() bool {
	return atomic.LoadInt64(&s.closed) == 1
}

// ListeningAddr returns listen address.
func (s *Server) ListeningAddr() string {
	return s.listener.Addr().String()
}

// Run runs the pd server.
func (s *Server) Run() error {
	// We use "127.0.0.1:0" for test and will set correct listening
	// address before run, so we set leader value here.
	s.leaderValue = s.marshalLeader()

	s.wg.Add(1)
	go s.leaderLoop()

	for {
		conn, err := s.listener.Accept()
		if err != nil {
			log.Errorf("accept err %s", err)
			break
		}

		if !s.IsLeader() {
			log.Infof("server %s is not leader, close connection directly", s.cfg.Addr)
			continue
		}

		c := newConn(s, conn)
		s.wg.Add(1)
		go c.run()
	}

	return nil
}

func (s *Server) closeAllConnections() {
	s.connsLock.Lock()
	defer s.connsLock.Unlock()

	if len(s.conns) == 0 {
		return
	}

	// TODO: should we send an error message before close?
	for conn := range s.conns {
		conn.Close()
	}

	s.conns = make(map[*conn]struct{})
}
<commit_msg>close connection if pd-server's role is not leader<commit_after>package server

import (
	"net"
	"sync"
	"sync/atomic"
	"time"

	"github.com/coreos/etcd/clientv3"
	"github.com/juju/errors"
	"github.com/ngaut/log"
)

const (
	etcdTimeout = time.Second * 3
)

// Server is the pd server.
type Server struct {
	cfg *Config

	listener net.Listener

	client *clientv3.Client

	isLeader int64
	// leader value saved in etcd leader key.
	// Every write will use this to check leader validation.
	leaderValue string

	wg sync.WaitGroup

	connsLock sync.Mutex
	conns     map[*conn]struct{}

	closed int64

	// for tso
	ts            atomic.Value
	lastSavedTime time.Time

	// for id allocator, we can use one allocator for
	// node, store, region and peer, because we just need
	// a unique ID.
	idAlloc *idAllocator

	// for raft cluster
	clusterLock sync.RWMutex
	clusters    map[uint64]*raftCluster

	msgID uint64
}

// NewServer creates the pd server with given configuration.
func NewServer(cfg *Config) (*Server, error) {
	cfg.adjust()

	log.Infof("create etcd v3 client with endpoints %v", cfg.EtcdAddrs)
	client, err := clientv3.New(clientv3.Config{
		Endpoints:   cfg.EtcdAddrs,
		DialTimeout: etcdTimeout,
	})
	if err != nil {
		return nil, errors.Trace(err)
	}

	log.Infof("listening address %s", cfg.Addr)
	l, err := net.Listen("tcp", cfg.Addr)
	if err != nil {
		client.Close()
		return nil, errors.Trace(err)
	}

	s := &Server{
		cfg:      cfg,
		listener: l,
		client:   client,
		isLeader: 0,
		conns:    make(map[*conn]struct{}),
		closed:   0,
		clusters: make(map[uint64]*raftCluster),
	}

	s.idAlloc = &idAllocator{s: s}

	return s, nil
}

// Close closes the server.
func (s *Server) Close() {
	if !atomic.CompareAndSwapInt64(&s.closed, 0, 1) {
		// server is already closed
		return
	}

	log.Info("closing server")

	s.enableLeader(false)

	if s.listener != nil {
		s.listener.Close()
	}

	if s.client != nil {
		s.client.Close()
	}

	s.wg.Wait()
}

// IsClosed checks whether server is closed or not.
func (s *Server) IsClosed() bool {
	return atomic.LoadInt64(&s.closed) == 1
}

// ListeningAddr returns listen address.
func (s *Server) ListeningAddr() string {
	return s.listener.Addr().String()
}

// Run runs the pd server.
func (s *Server) Run() error {
	// We use "127.0.0.1:0" for test and will set correct listening
	// address before run, so we set leader value here.
	s.leaderValue = s.marshalLeader()

	s.wg.Add(1)
	go s.leaderLoop()

	for {
		conn, err := s.listener.Accept()
		if err != nil {
			log.Errorf("accept err %s", err)
			break
		}

		if !s.IsLeader() {
			log.Infof("server %s is not leader, close connection directly", s.cfg.Addr)
			conn.Close()
			continue
		}

		c := newConn(s, conn)
		s.wg.Add(1)
		go c.run()
	}

	return nil
}

func (s *Server) closeAllConnections() {
	s.connsLock.Lock()
	defer s.connsLock.Unlock()

	if len(s.conns) == 0 {
		return
	}

	// TODO: should we send an error message before close?
	for conn := range s.conns {
		conn.Close()
	}

	s.conns = make(map[*conn]struct{})
}
<|endoftext|>


<commit_before>package server

import (
	"os"
	"path"
	"time"

	"golang.org/x/net/context"

	"github.com/barakmich/agro"
	"github.com/barakmich/agro/blockset"
	"github.com/barakmich/agro/models"

	// Register drivers
	_ "github.com/barakmich/agro/metadata/temp"
	_ "github.com/barakmich/agro/storage/block"
	_ "github.com/barakmich/agro/storage/inode"
)

var _ agro.Server = &server{}

type server struct {
	cold         agro.BlockStore
	mds          agro.MetadataService
	inodes       agro.INodeStore
	closeChans   []chan interface{}
	internalAddr string
}

func NewMemoryServer() agro.Server {
	cfg := agro.Config{}
	mds, _ := agro.CreateMetadataService("temp", cfg)
	inodes, _ := agro.CreateINodeStore("temp", cfg)
	gmd, _ := mds.GlobalMetadata()
	cold, _ := agro.CreateBlockStore("temp", cfg, gmd)
	return &server{
		cold:   cold,
		mds:    mds,
		inodes: inodes,
	}
}

func (s *server) Create(path agro.Path, md models.Metadata) (f agro.File, err error) {
	// Truncate the file if it already exists. This is equivalent to creating
	// a new (empty) inode with the path that we're going to overwrite later.
	n := models.NewEmptyInode()
	n.Filenames = []string{path.Path}
	volid, err := s.mds.GetVolumeID(path.Volume)
	n.Volume = uint64(volid)
	if err != nil {
		return nil, err
	}
	n.Permissions = &md
	globals, err := s.mds.GlobalMetadata()
	if err != nil {
		return nil, err
	}
	bs, err := blockset.CreateBlocksetFromSpec(globals.DefaultBlockSpec, s.cold)
	if err != nil {
		return nil, err
	}
	clog.Tracef("Create file %s at inode %d:%d with block length %d", path, n.Volume, n.Inode, bs.Length())
	return &file{
		path:    path,
		inode:   n,
		srv:     s,
		blocks:  bs,
		blkSize: int64(globals.BlockSize),
	}, nil
}

func (s *server) Open(p agro.Path) (agro.File, error) {
	ref, err := s.inodeRefForPath(p)
	if err != nil {
		return nil, err
	}

	inode, err := s.inodes.GetINode(context.TODO(), ref)
	if err != nil {
		return nil, err
	}

	// TODO(jzelinskie): check metadata for permission

	return s.newFile(p, inode)
}

func (s *server) inodeRefForPath(p agro.Path) (agro.INodeRef, error) {
	dir, _, err := s.mds.Getdir(p)
	if err != nil {
		return agro.INodeRef{}, err
	}

	volID, err := s.mds.GetVolumeID(p.Volume)
	if err != nil {
		return agro.INodeRef{}, err
	}

	_, filename := path.Split(p.Path)
	inodeID, ok := dir.Files[filename]
	if !ok {
		return agro.INodeRef{}, os.ErrNotExist
	}

	return agro.INodeRef{volID, agro.INodeID(inodeID)}, nil
}

type fileInfo struct {
	inode *models.INode
	path  agro.Path
}

func (fi fileInfo) Name() string {
	return fi.inode.Filenames[0]
}

func (fi fileInfo) Size() int64 {
	return int64(fi.inode.Filesize)
}

func (fi fileInfo) Mode() os.FileMode {
	return os.FileMode(fi.inode.Permissions.Mode)
}

func (fi fileInfo) ModTime() time.Time {
	return time.Unix(int64(fi.inode.Permissions.Mtime), 0)
}

func (fi fileInfo) IsDir() bool {
	return fi.path.IsDir()
}

func (fi fileInfo) Sys() interface{} {
	return fi
}

func (s *server) Lstat(path agro.Path) (os.FileInfo, error) {
	ref, err := s.inodeRefForPath(path)
	if err != nil {
		return nil, err
	}

	inode, err := s.inodes.GetINode(context.TODO(), ref)
	if err != nil {
		return nil, err
	}

	return fileInfo{inode, path}, nil
}

func (s *server) CreateVolume(vol string) error {
	err := s.mds.CreateVolume(vol)
	if err == agro.ErrAgain {
		return s.CreateVolume(vol)
	}
	return err
}

func (s *server) GetVolumes() ([]string, error) {
	return s.mds.GetVolumes()
}

func (s *server) Close() error {
	for _, c := range s.closeChans {
		close(c)
	}
	err := s.mds.Close()
	if err != nil {
		return err
	}
	err = s.inodes.Close()
	if err != nil {
		return err
	}
	err = s.cold.Close()
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>change mtime to be nanoseconds<commit_after>package server

import (
	"os"
	"path"
	"time"

	"golang.org/x/net/context"

	"github.com/barakmich/agro"
	"github.com/barakmich/agro/blockset"
	"github.com/barakmich/agro/models"

	// Register drivers
	_ "github.com/barakmich/agro/metadata/temp"
	_ "github.com/barakmich/agro/storage/block"
	_ "github.com/barakmich/agro/storage/inode"
)

var _ agro.Server = &server{}

type server struct {
	cold         agro.BlockStore
	mds          agro.MetadataService
	inodes       agro.INodeStore
	closeChans   []chan interface{}
	internalAddr string
}

func NewMemoryServer() agro.Server {
	cfg := agro.Config{}
	mds, _ := agro.CreateMetadataService("temp", cfg)
	inodes, _ := agro.CreateINodeStore("temp", cfg)
	gmd, _ := mds.GlobalMetadata()
	cold, _ := agro.CreateBlockStore("temp", cfg, gmd)
	return &server{
		cold:   cold,
		mds:    mds,
		inodes: inodes,
	}
}

func (s *server) Create(path agro.Path, md models.Metadata) (f agro.File, err error) {
	// Truncate the file if it already exists. This is equivalent to creating
	// a new (empty) inode with the path that we're going to overwrite later.
	n := models.NewEmptyInode()
	n.Filenames = []string{path.Path}
	volid, err := s.mds.GetVolumeID(path.Volume)
	n.Volume = uint64(volid)
	if err != nil {
		return nil, err
	}
	n.Permissions = &md
	globals, err := s.mds.GlobalMetadata()
	if err != nil {
		return nil, err
	}
	bs, err := blockset.CreateBlocksetFromSpec(globals.DefaultBlockSpec, s.cold)
	if err != nil {
		return nil, err
	}
	clog.Tracef("Create file %s at inode %d:%d with block length %d", path, n.Volume, n.Inode, bs.Length())
	return &file{
		path:    path,
		inode:   n,
		srv:     s,
		blocks:  bs,
		blkSize: int64(globals.BlockSize),
	}, nil
}

func (s *server) Open(p agro.Path) (agro.File, error) {
	ref, err := s.inodeRefForPath(p)
	if err != nil {
		return nil, err
	}

	inode, err := s.inodes.GetINode(context.TODO(), ref)
	if err != nil {
		return nil, err
	}

	// TODO(jzelinskie): check metadata for permission

	return s.newFile(p, inode)
}

func (s *server) inodeRefForPath(p agro.Path) (agro.INodeRef, error) {
	dir, _, err := s.mds.Getdir(p)
	if err != nil {
		return agro.INodeRef{}, err
	}

	volID, err := s.mds.GetVolumeID(p.Volume)
	if err != nil {
		return agro.INodeRef{}, err
	}

	_, filename := path.Split(p.Path)
	inodeID, ok := dir.Files[filename]
	if !ok {
		return agro.INodeRef{}, os.ErrNotExist
	}

	return agro.INodeRef{volID, agro.INodeID(inodeID)}, nil
}

type fileInfo struct {
	inode *models.INode
	path  agro.Path
}

func (fi fileInfo) Name() string {
	return fi.inode.Filenames[0]
}

func (fi fileInfo) Size() int64 {
	return int64(fi.inode.Filesize)
}

func (fi fileInfo) Mode() os.FileMode {
	return os.FileMode(fi.inode.Permissions.Mode)
}

func (fi fileInfo) ModTime() time.Time {
	return time.Unix(0, int64(fi.inode.Permissions.Mtime))
}

func (fi fileInfo) IsDir() bool {
	return fi.path.IsDir()
}

func (fi fileInfo) Sys() interface{} {
	return fi
}

func (s *server) Lstat(path agro.Path) (os.FileInfo, error) {
	ref, err := s.inodeRefForPath(path)
	if err != nil {
		return nil, err
	}

	inode, err := s.inodes.GetINode(context.TODO(), ref)
	if err != nil {
		return nil, err
	}

	return fileInfo{inode, path}, nil
}

func (s *server) CreateVolume(vol string) error {
	err := s.mds.CreateVolume(vol)
	if err == agro.ErrAgain {
		return s.CreateVolume(vol)
	}
	return err
}

func (s *server) GetVolumes() ([]string, error) {
	return s.mds.GetVolumes()
}

func (s *server) Close() error {
	for _, c := range s.closeChans {
		close(c)
	}
	err := s.mds.Close()
	if err != nil {
		return err
	}
	err = s.inodes.Close()
	if err != nil {
		return err
	}
	err = s.cold.Close()
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package drawer

import (
	"image"
	"image/color"
	"image/draw"
)

// A convinience function that sets all of the pixels in img to color
func Fill(img draw.Image, color color.Color) {
	draw.Draw(img, img.Bounds(), &image.Uniform{color}, image.ZP, draw.Src)
}
<commit_msg>Fix color to RGBA conversion and add alpha blending<commit_after>package drawer

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
)

// A convinience function that sets all of the pixels in img to color
func Fill(img draw.Image, color color.Color) {
	draw.Draw(img, img.Bounds(), &image.Uniform{color}, image.ZP, draw.Src)
}

func ColorToRGBA(c color.Color) color.RGBA {
	r, g, b, a := c.RGBA()
	return color.RGBA{uint8(r / 0x101), uint8(g / 0x101), uint8(b / 0x101), uint8(a / 0x101)}
}

func Blend(img draw.Image, x int, y int, c color.Color) {
	dst := ColorToRGBA(img.At(x, y))
	src := ColorToRGBA(c)

	fmt.Println("dst:", dst, "src:", src)

	//	dst: {0 255 255 255} src: {255 0 0 74}
	//	col: {1 0 0 147}

	alpha := src.A + dst.A*(1-src.A)
	r := (src.R + dst.R*(1-src.A))
	g := (src.G + dst.G*(1-src.A))
	b := (src.B + dst.B*(1-src.A))

	col := color.RGBA{R: r, G: g, B: b, A: alpha}
	fmt.Println("col:", col)

	img.Set(x, y, col)
}
<|endoftext|>