<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/signal"
	"sync"

	"github.com/containerd/console"
	"github.com/opencontainers/runc/libcontainer"
	"github.com/opencontainers/runc/libcontainer/utils"
)

type tty struct {
	epoller     *console.Epoller
	console     *console.EpollConsole
	hostConsole console.Console
	closers     []io.Closer
	postStart   []io.Closer
	wg          sync.WaitGroup
	consoleC    chan error
}

func (t *tty) copyIO(w io.Writer, r io.ReadCloser) {
	defer t.wg.Done()
	_, _ = io.Copy(w, r)
	_ = r.Close()
}

// setup pipes for the process so that advanced features like c/r are able to easily checkpoint
// and restore the process's IO without depending on a host specific path or device
func setupProcessPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) {
	i, err := p.InitializeIO(rootuid, rootgid)
	if err != nil {
		return nil, err
	}
	t := &tty{
		closers: []io.Closer{
			i.Stdin,
			i.Stdout,
			i.Stderr,
		},
	}
	// add the process's io to the post start closers if they support close
	for _, cc := range []interface{}{
		p.Stdin,
		p.Stdout,
		p.Stderr,
	} {
		if c, ok := cc.(io.Closer); ok {
			t.postStart = append(t.postStart, c)
		}
	}
	go func() {
		_, _ = io.Copy(i.Stdin, os.Stdin)
		_ = i.Stdin.Close()
	}()
	t.wg.Add(2)
	go t.copyIO(os.Stdout, i.Stdout)
	go t.copyIO(os.Stderr, i.Stderr)
	return t, nil
}

func inheritStdio(process *libcontainer.Process) {
	process.Stdin = os.Stdin
	process.Stdout = os.Stdout
	process.Stderr = os.Stderr
}

func (t *tty) initHostConsole() error {
	// Usually all three (stdin, stdout, and stderr) streams are open to
	// the terminal, but they might be redirected, so try them all.
	for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} {
		c, err := console.ConsoleFromFile(s)
		if err == nil {
			t.hostConsole = c
			return nil
		}
		if errors.Is(err, console.ErrNotAConsole) {
			continue
		}
		// should not happen
		return fmt.Errorf("unable to get console: %w", err)
	}
	// If all streams are redirected, but we still have a controlling
	// terminal, it can be obtained by opening /dev/tty.
	tty, err := os.Open("/dev/tty")
	if err != nil {
		return err
	}
	c, err := console.ConsoleFromFile(tty)
	if err != nil {
		return fmt.Errorf("unable to get console: %w", err)
	}

	t.hostConsole = c
	return nil
}

func (t *tty) recvtty(socket *os.File) (Err error) {
	f, err := utils.RecvFd(socket)
	if err != nil {
		return err
	}
	cons, err := console.ConsoleFromFile(f)
	if err != nil {
		return err
	}
	err = console.ClearONLCR(cons.Fd())
	if err != nil {
		return err
	}
	epoller, err := console.NewEpoller()
	if err != nil {
		return err
	}
	epollConsole, err := epoller.Add(cons)
	if err != nil {
		return err
	}
	defer func() {
		if Err != nil {
			_ = epollConsole.Close()
		}
	}()
	go func() { _ = epoller.Wait() }()
	go func() { _, _ = io.Copy(epollConsole, os.Stdin) }()
	t.wg.Add(1)
	go t.copyIO(os.Stdout, epollConsole)

	// Set raw mode for the controlling terminal.
	if err := t.hostConsole.SetRaw(); err != nil {
		return fmt.Errorf("failed to set the terminal from the stdin: %w", err)
	}
	go handleInterrupt(t.hostConsole)

	t.epoller = epoller
	t.console = epollConsole
	t.closers = []io.Closer{epollConsole}
	return nil
}

func handleInterrupt(c console.Console) {
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	<-sigchan
	_ = c.Reset()
	os.Exit(0)
}

func (t *tty) waitConsole() error {
	if t.consoleC != nil {
		return <-t.consoleC
	}
	return nil
}

// ClosePostStart closes any fds that are provided to the container and dup2'd
// so that we no longer have copy in our process.
func (t *tty) ClosePostStart() {
	for _, c := range t.postStart {
		_ = c.Close()
	}
}

// Close closes all open fds for the tty and/or restores the original
// stdin state to what it was prior to the container execution
func (t *tty) Close() error {
	// ensure that our side of the fds are always closed
	for _, c := range t.postStart {
		_ = c.Close()
	}
	// the process is gone at this point, shutting down the console if we have
	// one and wait for all IO to be finished
	if t.console != nil && t.epoller != nil {
		_ = t.console.Shutdown(t.epoller.CloseConsole)
	}
	t.wg.Wait()
	for _, c := range t.closers {
		_ = c.Close()
	}
	if t.hostConsole != nil {
		_ = t.hostConsole.Reset()
	}
	return nil
}

func (t *tty) resize() error {
	if t.console == nil || t.hostConsole == nil {
		return nil
	}
	return t.console.ResizeFrom(t.hostConsole)
}
<commit_msg>tty: Close: rm return value<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"os/signal"
	"sync"

	"github.com/containerd/console"
	"github.com/opencontainers/runc/libcontainer"
	"github.com/opencontainers/runc/libcontainer/utils"
)

type tty struct {
	epoller     *console.Epoller
	console     *console.EpollConsole
	hostConsole console.Console
	closers     []io.Closer
	postStart   []io.Closer
	wg          sync.WaitGroup
	consoleC    chan error
}

func (t *tty) copyIO(w io.Writer, r io.ReadCloser) {
	defer t.wg.Done()
	_, _ = io.Copy(w, r)
	_ = r.Close()
}

// setup pipes for the process so that advanced features like c/r are able to easily checkpoint
// and restore the process's IO without depending on a host specific path or device
func setupProcessPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) {
	i, err := p.InitializeIO(rootuid, rootgid)
	if err != nil {
		return nil, err
	}
	t := &tty{
		closers: []io.Closer{
			i.Stdin,
			i.Stdout,
			i.Stderr,
		},
	}
	// add the process's io to the post start closers if they support close
	for _, cc := range []interface{}{
		p.Stdin,
		p.Stdout,
		p.Stderr,
	} {
		if c, ok := cc.(io.Closer); ok {
			t.postStart = append(t.postStart, c)
		}
	}
	go func() {
		_, _ = io.Copy(i.Stdin, os.Stdin)
		_ = i.Stdin.Close()
	}()
	t.wg.Add(2)
	go t.copyIO(os.Stdout, i.Stdout)
	go t.copyIO(os.Stderr, i.Stderr)
	return t, nil
}

func inheritStdio(process *libcontainer.Process) {
	process.Stdin = os.Stdin
	process.Stdout = os.Stdout
	process.Stderr = os.Stderr
}

func (t *tty) initHostConsole() error {
	// Usually all three (stdin, stdout, and stderr) streams are open to
	// the terminal, but they might be redirected, so try them all.
	for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} {
		c, err := console.ConsoleFromFile(s)
		if err == nil {
			t.hostConsole = c
			return nil
		}
		if errors.Is(err, console.ErrNotAConsole) {
			continue
		}
		// should not happen
		return fmt.Errorf("unable to get console: %w", err)
	}
	// If all streams are redirected, but we still have a controlling
	// terminal, it can be obtained by opening /dev/tty.
	tty, err := os.Open("/dev/tty")
	if err != nil {
		return err
	}
	c, err := console.ConsoleFromFile(tty)
	if err != nil {
		return fmt.Errorf("unable to get console: %w", err)
	}

	t.hostConsole = c
	return nil
}

func (t *tty) recvtty(socket *os.File) (Err error) {
	f, err := utils.RecvFd(socket)
	if err != nil {
		return err
	}
	cons, err := console.ConsoleFromFile(f)
	if err != nil {
		return err
	}
	err = console.ClearONLCR(cons.Fd())
	if err != nil {
		return err
	}
	epoller, err := console.NewEpoller()
	if err != nil {
		return err
	}
	epollConsole, err := epoller.Add(cons)
	if err != nil {
		return err
	}
	defer func() {
		if Err != nil {
			_ = epollConsole.Close()
		}
	}()
	go func() { _ = epoller.Wait() }()
	go func() { _, _ = io.Copy(epollConsole, os.Stdin) }()
	t.wg.Add(1)
	go t.copyIO(os.Stdout, epollConsole)

	// Set raw mode for the controlling terminal.
	if err := t.hostConsole.SetRaw(); err != nil {
		return fmt.Errorf("failed to set the terminal from the stdin: %w", err)
	}
	go handleInterrupt(t.hostConsole)

	t.epoller = epoller
	t.console = epollConsole
	t.closers = []io.Closer{epollConsole}
	return nil
}

func handleInterrupt(c console.Console) {
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)
	<-sigchan
	_ = c.Reset()
	os.Exit(0)
}

func (t *tty) waitConsole() error {
	if t.consoleC != nil {
		return <-t.consoleC
	}
	return nil
}

// ClosePostStart closes any fds that are provided to the container and dup2'd
// so that we no longer have copy in our process.
func (t *tty) ClosePostStart() {
	for _, c := range t.postStart {
		_ = c.Close()
	}
}

// Close closes all open fds for the tty and/or restores the original
// stdin state to what it was prior to the container execution
func (t *tty) Close() {
	// ensure that our side of the fds are always closed
	for _, c := range t.postStart {
		_ = c.Close()
	}
	// the process is gone at this point, shutting down the console if we have
	// one and wait for all IO to be finished
	if t.console != nil && t.epoller != nil {
		_ = t.console.Shutdown(t.epoller.CloseConsole)
	}
	t.wg.Wait()
	for _, c := range t.closers {
		_ = c.Close()
	}
	if t.hostConsole != nil {
		_ = t.hostConsole.Reset()
	}
}

func (t *tty) resize() error {
	if t.console == nil || t.hostConsole == nil {
		return nil
	}
	return t.console.ResizeFrom(t.hostConsole)
}
<|endoftext|>


<commit_before>// Package udp implements UDP test helpers. It lets you assert that certain
// strings must or must not be sent to a given local UDP listener.
package udp

import (
	"net"
	"strings"
	"testing"
	"time"
)

var (
	addr     *string
	listener *net.UDPConn
	Timeout  time.Duration = time.Millisecond
)

type fn func()

// SetAddr sets the UDP port that will be listened on.
func SetAddr(a string) {
	addr = &a
}

func start(t *testing.T) {
	resAddr, err := net.ResolveUDPAddr("udp", *addr)
	if err != nil {
		t.Fatal(err)
	}
	listener, err = net.ListenUDP("udp", resAddr)
	if err != nil {
		t.Fatal(err)
	}
}

func stop(t *testing.T) {
	if err := listener.Close(); err != nil {
		t.Fatal(err)
	}
}

func getMessage(t *testing.T, body fn) string {
	start(t)
	defer stop(t)

	result := make(chan string)

	go func() {
		message := make([]byte, 1024*32)
		listener.SetReadDeadline(time.Now().Add(Timeout))
		n, _, _ := listener.ReadFrom(message)
		result <- string(message[0:n])
	}()

	body()

	return <-result
}

func get(t *testing.T, match string, body fn) (got string, equals bool, contains bool) {
	got = getMessage(t, body)
	equals = got == match
	contains = strings.Contains(got, match)
	return got, equals, contains
}

// ShouldReceiveOnly will fire a test error if the given function doesn't send
// exactly the given string over UDP.
func ShouldReceiveOnly(t *testing.T, expected string, body fn) {
	got, equals, _ := get(t, expected, body)
	if !equals {
		t.Errorf("Expected %#v but got %#v instead", expected, got)
	}
}

// ShouldNotReceiveOnly will fire a test error if the given function sends
// exactly the given string over UDP.
func ShouldNotReceiveOnly(t *testing.T, notExpected string, body fn) {
	_, equals, _ := get(t, notExpected, body)
	if equals {
		t.Errorf("Expected not to get %v but did", notExpected)
	}
}

// ShouldReceive will fire a test error if the given function doesn't send the
// given string over UDP.
func ShouldReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if !contains {
		t.Errorf("Expected to find %#v but got %#v instead", expected, got)
	}
}

// ShouldNotReceive will fire a test error if the given function sends the
// given string over UDP.
func ShouldNotReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if contains {
		t.Errorf("Expected not to find %#v but got %#v", expected, got)
	}
}

// ShouldReceiveAll will fire a test error unless all of the given strings are
// sent over UDP.
func ShouldReceiveAll(t *testing.T, expected []string, body fn) {
	got := getMessage(t, body)
	for _, str := range expected {
		if !strings.Contains(got, str) {
			t.Errorf("Expected to find %#v but got %#v instead", str, got)
		}
	}
}

// ShouldNotReceiveAny will fire a test error if any of the given strings are
// sent over UDP.
func ShouldNotReceiveAny(t *testing.T, unexpected []string, body fn) {
	got := getMessage(t, body)
	for _, str := range unexpected {
		if strings.Contains(got, str) {
			t.Errorf("Expected not to find %#v but got %#v", str, got)
		}
	}
}

func ShouldReceiveAllAndNotReceiveAny(t *testing.T, expected []string, unexpected []string, body fn) {
	got := getMessage(t, body)
	for _, str := range expected {
		if !strings.Contains(got, str) {
			t.Errorf("Expected to find %#v but got %#v instead", str, got)
		}
	}
	for _, str := range unexpected {
		if strings.Contains(got, str) {
			t.Errorf("Expected not to find %#v but got %#v", str, got)
		}
	}
}
<commit_msg>Nicer error messages.<commit_after>// Package udp implements UDP test helpers. It lets you assert that certain
// strings must or must not be sent to a given local UDP listener.
package udp

import (
	"net"
	"runtime"
	"strings"
	"testing"
	"time"
)

var (
	addr     *string
	listener *net.UDPConn
	Timeout  time.Duration = time.Millisecond
)

type fn func()

// SetAddr sets the UDP port that will be listened on.
func SetAddr(a string) {
	addr = &a
}

func start(t *testing.T) {
	resAddr, err := net.ResolveUDPAddr("udp", *addr)
	if err != nil {
		t.Fatal(err)
	}
	listener, err = net.ListenUDP("udp", resAddr)
	if err != nil {
		t.Fatal(err)
	}
}

func stop(t *testing.T) {
	if err := listener.Close(); err != nil {
		t.Fatal(err)
	}
}

func getMessage(t *testing.T, body fn) string {
	start(t)
	defer stop(t)

	result := make(chan string)

	go func() {
		message := make([]byte, 1024*32)
		listener.SetReadDeadline(time.Now().Add(Timeout))
		n, _, _ := listener.ReadFrom(message)
		result <- string(message[0:n])
	}()

	body()

	return <-result
}

func get(t *testing.T, match string, body fn) (got string, equals bool, contains bool) {
	got = getMessage(t, body)
	equals = got == match
	contains = strings.Contains(got, match)
	return got, equals, contains
}

func printLocation(t *testing.T) {
	_, file, line, _ := runtime.Caller(2)
	t.Errorf("At: %s:%d", file, line)
}

// ShouldReceiveOnly will fire a test error if the given function doesn't send
// exactly the given string over UDP.
func ShouldReceiveOnly(t *testing.T, expected string, body fn) {
	got, equals, _ := get(t, expected, body)
	if !equals {
		printLocation(t)
		t.Errorf("Expected: %s", expected)
		t.Errorf("But got: %s", got)
	}
}

// ShouldNotReceiveOnly will fire a test error if the given function sends
// exactly the given string over UDP.
func ShouldNotReceiveOnly(t *testing.T, notExpected string, body fn) {
	_, equals, _ := get(t, notExpected, body)
	if equals {
		printLocation(t)
		t.Errorf("Expected not to get: %s", notExpected)
	}
}

// ShouldReceive will fire a test error if the given function doesn't send the
// given string over UDP.
func ShouldReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if !contains {
		printLocation(t)
		t.Errorf("Expected to find: %s", expected)
		t.Errorf("But got: %s", got)
	}
}

// ShouldNotReceive will fire a test error if the given function sends the
// given string over UDP.
func ShouldNotReceive(t *testing.T, expected string, body fn) {
	got, _, contains := get(t, expected, body)
	if contains {
		printLocation(t)
		t.Errorf("Expected not to find: %s", expected)
		t.Errorf("But got: %s", got)
	}
}

// ShouldReceiveAll will fire a test error unless all of the given strings are
// sent over UDP.
func ShouldReceiveAll(t *testing.T, expected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range expected {
		if !strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected to find: %s", str)
		}
	}

	if failed {
		t.Errorf("But got: %s", got)
	}
}

// ShouldNotReceiveAny will fire a test error if any of the given strings are
// sent over UDP.
func ShouldNotReceiveAny(t *testing.T, unexpected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range unexpected {
		if strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected not to find: %s", str)
		}
	}

	if failed {
		t.Errorf("But got: %s", got)
	}
}

func ShouldReceiveAllAndNotReceiveAny(t *testing.T, expected []string, unexpected []string, body fn) {
	got := getMessage(t, body)
	failed := false

	for _, str := range expected {
		if !strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected to find: %s", str)
		}
	}
	for _, str := range unexpected {
		if strings.Contains(got, str) {
			if !failed {
				printLocation(t)
				failed = true
			}
			t.Errorf("Expected not to find: %s", str)
		}
	}

	if failed {
		t.Errorf("but got: %s", got)
	}
}
<|endoftext|>


<commit_before>package main

// Slack outgoing webhooks are handled here. Requests come in and are run through
// the markov chain to generate a response, which is sent back to Slack.
//
// Create an outgoing webhook in your Slack here:
// https://my.slack.com/services/new/outgoing-webhook

import (
	"encoding/json"
	"log"
	"strconv"
	"math/rand"
	"net/http"
	"strings"
	"time"
)

type WebhookResponse struct {
	Username string `json:"username"`
	Text     string `json:"text"`
}

func init() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		incomingText := r.PostFormValue("text")
		if incomingText != "" && r.PostFormValue("user_id") != "" && r.PostFormValue("user_id") != "USLACKBOT"{
			text := parseText(incomingText)
			//log.Printf("Handling incoming request: %s", text)

			if text != "" {
				markovChain.Write(text)
			}

			go func() {
				markovChain.Save(stateFile)
			}()

			if rand.Intn(100) < responseChance || strings.Contains(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
				var response WebhookResponse
				response.Username = botUsername
				if strings.Contains(incomingText, "TG") && strings.HasPrefix(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
					responseChance -= 1
					if responseChance < 0 {
						responseChance = 0
					}
					response.Text = "Okay :( je suis à "+strconv.Itoa(responseChance)+"%"
				} else if strings.Contains(incomingText, "BS") && strings.HasPrefix(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
					responseChance += 1
					if responseChance > 100 {
						responseChance = 100
					}
					response.Text = "Okay :D je suis à "+strconv.Itoa(responseChance)+"%"
				} else if strings.Contains(incomingText, "moral") && strings.HasPrefix(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
					response.Text = "Environ "+strconv.Itoa(responseChance)+"% mon capitaine !"
				} else {
					response.Text = markovChain.Generate(numWords)
				}
				//log.Printf("Sending response: %s", response.Text)

				b, err := json.Marshal(response)
				if err != nil {
					log.Fatal(err)
				}

				time.Sleep(5 * time.Second)
				w.Write(b)
			}
		}
	})
}

func StartServer(addr string) {
	log.Printf("Starting HTTP server on %s", addr)
	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>Add "poil" as argument to fine tune response chance<commit_after>package main

// Slack outgoing webhooks are handled here. Requests come in and are run through
// the markov chain to generate a response, which is sent back to Slack.
//
// Create an outgoing webhook in your Slack here:
// https://my.slack.com/services/new/outgoing-webhook

import (
	"encoding/json"
	"log"
	"strconv"
	"math/rand"
	"net/http"
	"strings"
	"time"
)

type WebhookResponse struct {
	Username string `json:"username"`
	Text     string `json:"text"`
}

func init() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		incomingText := r.PostFormValue("text")
		if incomingText != "" && r.PostFormValue("user_id") != "" && r.PostFormValue("user_id") != "USLACKBOT"{
			text := parseText(incomingText)
			//log.Printf("Handling incoming request: %s", text)

			if text != "" {
				markovChain.Write(text)
			}

			go func() {
				markovChain.Save(stateFile)
			}()

			if rand.Intn(100) < responseChance || strings.Contains(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
				var response WebhookResponse
				response.Username = botUsername
				if strings.Contains(incomingText, "TG") && strings.HasPrefix(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
					if strings.Contains(incomingText, "poil") {
						responseChance -= 1
					} else{
						responseChance -= 5
					}
					if responseChance < 0 {
						responseChance = 0
					}
					response.Text = "Okay :( je suis à "+strconv.Itoa(responseChance)+"%"
				} else if strings.Contains(incomingText, "BS") && strings.HasPrefix(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
					if strings.Contains(incomingText, "poil") {
						responseChance += 1
					} else{
						responseChance += 5
					}
					if responseChance > 100 {
						responseChance = 100
					}
					response.Text = "Okay :D je suis à "+strconv.Itoa(responseChance)+"%"
				} else if strings.Contains(incomingText, "moral") && strings.HasPrefix(strings.ToLower(incomingText), strings.ToLower(botUsername)) {
					response.Text = "Environ "+strconv.Itoa(responseChance)+"% mon capitaine !"
				} else {
					response.Text = markovChain.Generate(numWords)
				}
				//log.Printf("Sending response: %s", response.Text)

				b, err := json.Marshal(response)
				if err != nil {
					log.Fatal(err)
				}

				time.Sleep(5 * time.Second)
				w.Write(b)
			}
		}
	})
}

func StartServer(addr string) {
	log.Printf("Starting HTTP server on %s", addr)
	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

//import "github.com/JamesDunne/go-util/base"
import "github.com/JamesDunne/go-util/web"

type ImageViewModel struct {
	ID             int64   `json:"id"`
	Base62ID       string  `json:"base62id"`
	Title          string  `json:"title"`
	Kind           string  `json:"kind"`
	ImageURL       string  `json:"imageURL"`
	ThumbURL       string  `json:"thumbURL"`
	Submitter      string  `json:"submitter,omitempty"`
	CollectionName string  `json:"collectionName,omitempty"`
	SourceURL      *string `json:"sourceURL,omitempty"`
	RedirectToID   *int64  `json:"redirectToID,omitempty"`
	IsClean        bool    `json:"isClean"`
}

func queryBit() (list []*ImageViewModel, err error) {
	// Query i.bittwiddlers.org
	breq, err := http.NewRequest("GET", "https://i.bittwiddlers.org/api/v1/all", nil)
	if err != nil {
		return nil, err
	}

	breq.Header.Set("Authorization", os.Getenv("BIT_AUTH"))
	brsp, err := http.DefaultClient.Do(breq)
	if err != nil {
		log.Printf("ERROR: %s\n", err)
		return nil, err
	}

	list = make([]*ImageViewModel, 0, 1000)
	json.NewDecoder(brsp.Body).Decode(
		&struct {
			Result struct {
				List *[]*ImageViewModel `json:"list"`
			} `json:"result"`
		}{
			Result: struct {
				List *[]*ImageViewModel `json:"list"`
			}{
				List: &list,
			},
		},
	)

	return list, nil
}

func replyText(rsp http.ResponseWriter, text string) {
	json.NewEncoder(rsp).Encode(struct {
		Text string `json:"text"`
	}{
		Text: text,
	})
}

func processRequest(rsp http.ResponseWriter, req *http.Request) *web.Error {
	if err := req.ParseForm(); err != nil {
		log.Printf("Could not parse form: %s\n", err)
		return web.AsError(err, http.StatusBadRequest)
	}

	// TODO: validate 'token'
	//req.PostForm.Get("token")

	// Don't accept messages not intended for us:
	if req.PostForm.Get("trigger_word") != "bitsbot" {
		rsp.WriteHeader(http.StatusOK)
		return nil
	}

	// Prevent infinite echos:
	if req.PostForm.Get("user_name") == "slackbot" {
		rsp.WriteHeader(http.StatusOK)
		return nil
	}

	// Log incoming text:
	log.Printf(
		"#%s <%s (%s)>: %s\n",
		req.PostForm.Get("channel_name"),
		req.PostForm.Get("user_name"),
		req.PostForm.Get("user_id"),
		req.PostForm.Get("text"),
	)

	// NOTE(jsd): "@bitsbot" does not trigger with outgoing webhooks via trigger words.
	// Strip "bitsbot" prefix off text:
	text := strings.Trim(req.PostForm.Get("text"), " \t\n")
	if strings.HasPrefix(text, "bitsbot") {
		text = strings.TrimLeft(text[len("bitsbot"):], " :\t\n")
	}

	// Text is HTML encoded otherwise.

	// Debug tool for user "jdunne":
	if strings.HasPrefix(text, "json=") && req.PostForm.Get("user_id") == "U03PV154T" {
		// Remove angle brackets around URLs:
		text = strings.Replace(text, "<", "", -1)
		text = strings.Replace(text, ">", "", -1)

		// Unmarshal JSON:
		o := make(map[string]interface{})
		err := json.Unmarshal([]byte(text[len("json="):]), &o)
		if err != nil {
			log.Printf("ERROR: %s\n", err)
			goto otherwise
		}

		// Echo incoming JSON data as our response:
		rsp.Header().Set("Content-Type", "application/json")
		rsp.WriteHeader(http.StatusOK)
		json.NewEncoder(rsp).Encode(o)
		return nil
	}

otherwise:
	// Query i.bittwiddlers.org for the list of images:
	list, err := queryBit()
	if err != nil {
		log.Printf("ERROR: %s\n", err)
		return nil
	}

	// Search by keyword:
	keywords := strings.FieldsFunc(
		strings.ToLower(text),
		func(c rune) bool { return strings.ContainsRune(" \n\t:,;.[]!()$%^&*/<>'\"", c) },
	)
	log.Printf("  keywords: %v\n", keywords)

	highest := -1
	highest_idxs := make([]int, 0, 20)
	for idx, img := range list {
		if img.Kind != "gif" && img.Kind != "jpeg" && img.Kind != "png" {
			continue
		}

		titleLower := strings.ToLower(img.Title)

		words := strings.FieldsFunc(
			titleLower,
			func(c rune) bool { return strings.ContainsRune(" \n\t:,;.[]!()$%^&*/<>'\"", c) },
		)

		h := -2

		// Add points for each keyword match:
		last_word_idx := -1
		for _, keyword := range keywords {
			for word_idx, word := range words {
				if word == keyword {
					h += 10
					if last_word_idx > -1 {
						// Penalize distance (word count) from last word found (helps phrases match better):
						h -= ((word_idx - last_word_idx) + 1)
					}
					h = (h * 20) / 16
					last_word_idx = word_idx

					// Only trigger once per keyword:
					break
				}
			}
		}

		if h > -2 {
			log.Printf("  %4d %s\n", h, img.Title)

			if h > highest {
				highest = h
				// Build a new list of winners at this index:
				highest_idxs = highest_idxs[:0]
				highest_idxs = append(highest_idxs, idx)
			} else if h == highest {
				// Add to the winning pool:
				highest_idxs = append(highest_idxs, idx)
			}
		}
	}

	winning_idx := -1
	if len(highest_idxs) == 0 {
		log.Printf("  No match!\n")
		replyText(rsp, "No match")
		return nil
	} else if len(highest_idxs) == 1 {
		log.Printf("  Single match!\n")
		winning_idx = highest_idxs[0]
	} else {
		log.Printf("  %d winners at %d score; randomly selecting a winner\n", len(highest_idxs), highest)
		for _, idx := range highest_idxs {
			img := list[idx]
			log.Printf("    %s\n", img.Title)
		}

		// Initialize a pseudo-random source:
		timestamp := int64(0)
		timestamp_float, err := strconv.ParseFloat(req.PostFormValue("timestamp"), 64)
		if err != nil {
			timestamp = time.Now().UnixNano()
		} else {
			timestamp = int64(timestamp_float)
		}

		// Select a random winner:
		r := rand.New(rand.NewSource(timestamp))
		winning_idx = highest_idxs[r.Intn(len(highest_idxs))]
	}

	img := list[winning_idx]
	log.Printf("  %s\n", img.Title)

	// Write JSON response with attached image:
	rsp.Header().Set("Content-Type", "application/json")
	rsp.WriteHeader(http.StatusOK)
	o, err := json.Marshal(struct {
		Text        string `json:"text"`
		Attachments []struct {
			Fallback string `json:"fallback"`
			ImageURL string `json:"image_url"`
		} `json:"attachments"`
	}{
		Text: img.Title,
		Attachments: []struct {
			Fallback string `json:"fallback"`
			ImageURL string `json:"image_url"`
		}{
			struct {
				Fallback string `json:"fallback"`
				ImageURL string `json:"image_url"`
			}{
				Fallback: img.Title,
				ImageURL: "http://i.bittwiddlers.org" + img.ImageURL,
			},
		},
	})
	log.Printf("%s\n", string(o))
	if err != nil {
		log.Printf("ERROR: %s\n", err)
		return nil
	}
	rsp.Write(o)

	return nil
}
<commit_msg>Disabled extra logging.<commit_after>package main

import (
	"encoding/json"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

//import "github.com/JamesDunne/go-util/base"
import "github.com/JamesDunne/go-util/web"

type ImageViewModel struct {
	ID             int64   `json:"id"`
	Base62ID       string  `json:"base62id"`
	Title          string  `json:"title"`
	Kind           string  `json:"kind"`
	ImageURL       string  `json:"imageURL"`
	ThumbURL       string  `json:"thumbURL"`
	Submitter      string  `json:"submitter,omitempty"`
	CollectionName string  `json:"collectionName,omitempty"`
	SourceURL      *string `json:"sourceURL,omitempty"`
	RedirectToID   *int64  `json:"redirectToID,omitempty"`
	IsClean        bool    `json:"isClean"`
}

func queryBit() (list []*ImageViewModel, err error) {
	// Query i.bittwiddlers.org
	breq, err := http.NewRequest("GET", "https://i.bittwiddlers.org/api/v1/all", nil)
	if err != nil {
		return nil, err
	}

	breq.Header.Set("Authorization", os.Getenv("BIT_AUTH"))
	brsp, err := http.DefaultClient.Do(breq)
	if err != nil {
		log.Printf("ERROR: %s\n", err)
		return nil, err
	}

	list = make([]*ImageViewModel, 0, 1000)
	json.NewDecoder(brsp.Body).Decode(
		&struct {
			Result struct {
				List *[]*ImageViewModel `json:"list"`
			} `json:"result"`
		}{
			Result: struct {
				List *[]*ImageViewModel `json:"list"`
			}{
				List: &list,
			},
		},
	)

	return list, nil
}

func replyText(rsp http.ResponseWriter, text string) {
	json.NewEncoder(rsp).Encode(struct {
		Text string `json:"text"`
	}{
		Text: text,
	})
}

func processRequest(rsp http.ResponseWriter, req *http.Request) *web.Error {
	if err := req.ParseForm(); err != nil {
		log.Printf("Could not parse form: %s\n", err)
		return web.AsError(err, http.StatusBadRequest)
	}

	// TODO: validate 'token'
	//req.PostForm.Get("token")

	// Don't accept messages not intended for us:
	if req.PostForm.Get("trigger_word") != "bitsbot" {
		rsp.WriteHeader(http.StatusOK)
		return nil
	}

	// Prevent infinite echos:
	if req.PostForm.Get("user_name") == "slackbot" {
		rsp.WriteHeader(http.StatusOK)
		return nil
	}

	// Log incoming text:
	//	log.Printf(
	//		"#%s <%s (%s)>: %s\n",
	//		req.PostForm.Get("channel_name"),
	//		req.PostForm.Get("user_name"),
	//		req.PostForm.Get("user_id"),
	//		req.PostForm.Get("text"),
	//	)

	// NOTE(jsd): "@bitsbot" does not trigger with outgoing webhooks via trigger words.
	// Strip "bitsbot" prefix off text:
	text := strings.Trim(req.PostForm.Get("text"), " \t\n")
	if strings.HasPrefix(text, "bitsbot") {
		text = strings.TrimLeft(text[len("bitsbot"):], " :\t\n")
	}

	// Text is HTML encoded otherwise.

	// Debug tool for user "jdunne":
	if strings.HasPrefix(text, "json=") && req.PostForm.Get("user_id") == "U03PV154T" {
		// Remove angle brackets around URLs:
		text = strings.Replace(text, "<", "", -1)
		text = strings.Replace(text, ">", "", -1)

		// Unmarshal JSON:
		o := make(map[string]interface{})
		err := json.Unmarshal([]byte(text[len("json="):]), &o)
		if err != nil {
			log.Printf("ERROR: %s\n", err)
			goto otherwise
		}

		// Echo incoming JSON data as our response:
		rsp.Header().Set("Content-Type", "application/json")
		rsp.WriteHeader(http.StatusOK)
		json.NewEncoder(rsp).Encode(o)
		return nil
	}

otherwise:
	// Query i.bittwiddlers.org for the list of images:
	list, err := queryBit()
	if err != nil {
		log.Printf("ERROR: %s\n", err)
		return nil
	}

	// Search by keyword:
	keywords := strings.FieldsFunc(
		strings.ToLower(text),
		func(c rune) bool { return strings.ContainsRune(" \n\t:,;.[]!()$%^&*/<>'\"", c) },
	)
	//log.Printf("  keywords: %v\n", keywords)

	highest := -1
	highest_idxs := make([]int, 0, 20)
	for idx, img := range list {
		if img.Kind != "gif" && img.Kind != "jpeg" && img.Kind != "png" {
			continue
		}

		titleLower := strings.ToLower(img.Title)

		words := strings.FieldsFunc(
			titleLower,
			func(c rune) bool { return strings.ContainsRune(" \n\t:,;.[]!()$%^&*/<>'\"", c) },
		)

		h := -2

		// Add points for each keyword match:
		last_word_idx := -1
		for _, keyword := range keywords {
			for word_idx, word := range words {
				if word == keyword {
					h += 10
					if last_word_idx > -1 {
						// Penalize distance (word count) from last word found (helps phrases match better):
						h -= ((word_idx - last_word_idx) + 1)
					}
					h = (h * 20) / 16
					last_word_idx = word_idx

					// Only trigger once per keyword:
					break
				}
			}
		}

		if h > -2 {
			//log.Printf("  %4d %s\n", h, img.Title)

			if h > highest {
				highest = h
				// Build a new list of winners at this index:
				highest_idxs = highest_idxs[:0]
				highest_idxs = append(highest_idxs, idx)
			} else if h == highest {
				// Add to the winning pool:
				highest_idxs = append(highest_idxs, idx)
			}
		}
	}

	winning_idx := -1
	if len(highest_idxs) == 0 {
		//log.Printf("  No match!\n")
		replyText(rsp, "No match")
		return nil
	} else if len(highest_idxs) == 1 {
		//log.Printf("  Single match!\n")
		winning_idx = highest_idxs[0]
	} else {
		//log.Printf("  %d winners at %d score; randomly selecting a winner\n", len(highest_idxs), highest)
		//		for _, idx := range highest_idxs {
		//			img := list[idx]
		//			log.Printf("    %s\n", img.Title)
		//		}

		// Initialize a pseudo-random source:
		timestamp := int64(0)
		timestamp_float, err := strconv.ParseFloat(req.PostFormValue("timestamp"), 64)
		if err != nil {
			timestamp = time.Now().UnixNano()
		} else {
			timestamp = int64(timestamp_float)
		}

		// Select a random winner:
		r := rand.New(rand.NewSource(timestamp))
		winning_idx = highest_idxs[r.Intn(len(highest_idxs))]
	}

	img := list[winning_idx]
	//log.Printf("  %s\n", img.Title)

	// Write JSON response with attached image:
	rsp.Header().Set("Content-Type", "application/json")
	rsp.WriteHeader(http.StatusOK)
	o, err := json.Marshal(struct {
		Text        string `json:"text"`
		Attachments []struct {
			Fallback string `json:"fallback"`
			ImageURL string `json:"image_url"`
		} `json:"attachments"`
	}{
		Text: img.Title,
		Attachments: []struct {
			Fallback string `json:"fallback"`
			ImageURL string `json:"image_url"`
		}{
			struct {
				Fallback string `json:"fallback"`
				ImageURL string `json:"image_url"`
			}{
				Fallback: img.Title,
				ImageURL: "http://i.bittwiddlers.org" + img.ImageURL,
			},
		},
	})
	//log.Printf("%s\n", string(o))
	if err != nil {
		log.Printf("ERROR: %s\n", err)
		return nil
	}
	rsp.Write(o)

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package web

import (
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"path/filepath"
	"log"
	"regexp"
	"time"
)

type RequestHandler struct {
	Writer http.ResponseWriter
	HTTP *http.Request
	Server *Server
	Vars []string
}

func (req *RequestHandler) HTTPError(n int, err ...error) {
	if err != nil && req.Server.settings.Debug {
		log.Printf("HTTPError %d: %s", n, err[0])  // whine
	}
	http.Error(req.Writer, http.StatusText(n), n)
}

func (req *RequestHandler) NotFound() {
	http.NotFound(req.Writer, req.HTTP)
}

func (req *RequestHandler) Redirect(url string) {
	http.Redirect(req.Writer, req.HTTP, url, http.StatusFound)
}

func (req *RequestHandler) Render(t string, a interface{}) error {
	if req.Server.templates == nil {
		e := errors.New("TemplatePath not set in web.Settings")
		if req.Server.settings.Debug {
			log.Println(e)
		}
		return e
	}

	err := req.Server.templates.ExecuteTemplate(req.Writer, t, a)
	if err != nil && req.Server.settings.Debug {
		log.Println(err)
	}
	return err
}

func (req *RequestHandler) ServeFile(name string) {
	http.ServeFile(req.Writer, req.HTTP, name)
}

func (req *RequestHandler) SetHeader(k string, v string) {
	req.Writer.Header().Set(k, v)
}

func (req *RequestHandler) Write(f string, a ...interface{}) (int, error) {
	return fmt.Fprintf(req.Writer, f, a...)
}

type HandlerFunc func(req RequestHandler)
type Handler struct {
	Re string
	Fn HandlerFunc
}

type route struct {
	re *regexp.Regexp
	fn HandlerFunc
}

type Settings struct {
	Debug bool
	XHeaders bool
	TemplatePath string
	ReadTimeout time.Duration
	WriteTimeout time.Duration
}

type Server struct {
	routes []route
	settings *Settings
	templates *template.Template
}

func execute(fn func(RequestHandler), req RequestHandler) {
	var now time.Time
	if req.Server.settings.Debug {
		now = time.Now()
	}
	if req.Server.settings.XHeaders {
		addr := req.HTTP.Header.Get("X-Real-IP")
		if addr == "" {
			addr = req.HTTP.Header.Get("X-Forwarded-For")
		}

		if addr != "" {
			req.HTTP.RemoteAddr = addr
		}
	}
	fn(req)  // execute the HandlerFunc
	if req.Server.settings.Debug {
		log.Printf("%s %s (%s) %dµs",
				req.HTTP.Method,
				req.HTTP.URL.Path,
				req.HTTP.RemoteAddr,
				time.Since(now)/time.Microsecond)
	}
}

func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	for _, p := range srv.routes {
		vars := p.re.FindStringSubmatch(r.URL.Path)
		if len(vars) >= 1 {
			execute(p.fn, RequestHandler{w, r, srv, vars})
			return
		}
	}
	http.NotFound(w, r)
}

func Application(addr string, h []Handler, s *Settings) (*Server, error) {
	var t *template.Template
	if s.TemplatePath != "" {
		path := filepath.Join(s.TemplatePath, "*.html")
		t = template.Must(template.ParseGlob(path))
	}
	r := make([]route, len(h))
	for n, handler := range h {
		r[n] = route{regexp.MustCompile(handler.Re), handler.Fn}
	}
	if s.Debug {
		log.Println("Starting server on", addr)
	}
	rtimeout := 0*time.Second  // Keep-alive might be your enemy here
	if s.ReadTimeout >= 1 {
		rtimeout = s.ReadTimeout
	}
	wtimeout := 0*time.Second
	if s.WriteTimeout >= 1 {
		wtimeout = s.WriteTimeout
	}
	srv := Server{r, s, t}
	x := &http.Server{Addr: addr, Handler: &srv,
				ReadTimeout: rtimeout, WriteTimeout:wtimeout}
	err := x.ListenAndServe()
	if err != nil && s.Debug {
		log.Println("Error:", err)
	}
	return &srv, err
}
<commit_msg>time.Since<commit_after>// Copyright 2013 Alexandre Fiori
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package web

import (
	"errors"
	"fmt"
	"html/template"
	"net/http"
	"path/filepath"
	"log"
	"regexp"
	"time"
)

type RequestHandler struct {
	Writer http.ResponseWriter
	HTTP *http.Request
	Server *Server
	Vars []string
}

func (req *RequestHandler) HTTPError(n int, err ...error) {
	if err != nil && req.Server.settings.Debug {
		log.Printf("HTTPError %d: %s", n, err[0])  // whine
	}
	http.Error(req.Writer, http.StatusText(n), n)
}

func (req *RequestHandler) NotFound() {
	http.NotFound(req.Writer, req.HTTP)
}

func (req *RequestHandler) Redirect(url string) {
	http.Redirect(req.Writer, req.HTTP, url, http.StatusFound)
}

func (req *RequestHandler) Render(t string, a interface{}) error {
	if req.Server.templates == nil {
		e := errors.New("TemplatePath not set in web.Settings")
		if req.Server.settings.Debug {
			log.Println(e)
		}
		return e
	}

	err := req.Server.templates.ExecuteTemplate(req.Writer, t, a)
	if err != nil && req.Server.settings.Debug {
		log.Println(err)
	}
	return err
}

func (req *RequestHandler) ServeFile(name string) {
	http.ServeFile(req.Writer, req.HTTP, name)
}

func (req *RequestHandler) SetHeader(k string, v string) {
	req.Writer.Header().Set(k, v)
}

func (req *RequestHandler) Write(f string, a ...interface{}) (int, error) {
	return fmt.Fprintf(req.Writer, f, a...)
}

type HandlerFunc func(req RequestHandler)
type Handler struct {
	Re string
	Fn HandlerFunc
}

type route struct {
	re *regexp.Regexp
	fn HandlerFunc
}

type Settings struct {
	Debug bool
	XHeaders bool
	TemplatePath string
	ReadTimeout time.Duration
	WriteTimeout time.Duration
}

type Server struct {
	routes []route
	settings *Settings
	templates *template.Template
}

func execute(fn func(RequestHandler), req RequestHandler) {
	var now time.Time
	if req.Server.settings.Debug {
		now = time.Now()
	}
	if req.Server.settings.XHeaders {
		addr := req.HTTP.Header.Get("X-Real-IP")
		if addr == "" {
			addr = req.HTTP.Header.Get("X-Forwarded-For")
		}

		if addr != "" {
			req.HTTP.RemoteAddr = addr
		}
	}
	fn(req)  // execute the HandlerFunc
	if req.Server.settings.Debug {
		log.Printf("%s %s (%s) %s",
				req.HTTP.Method,
				req.HTTP.URL.Path,
				req.HTTP.RemoteAddr,
				time.Since(now))
	}
}

func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	for _, p := range srv.routes {
		vars := p.re.FindStringSubmatch(r.URL.Path)
		if len(vars) >= 1 {
			execute(p.fn, RequestHandler{w, r, srv, vars})
			return
		}
	}
	http.NotFound(w, r)
}

func Application(addr string, h []Handler, s *Settings) (*Server, error) {
	var t *template.Template
	if s.TemplatePath != "" {
		path := filepath.Join(s.TemplatePath, "*.html")
		t = template.Must(template.ParseGlob(path))
	}
	r := make([]route, len(h))
	for n, handler := range h {
		r[n] = route{regexp.MustCompile(handler.Re), handler.Fn}
	}
	if s.Debug {
		log.Println("Starting server on", addr)
	}
	rtimeout := 0*time.Second  // Keep-alive might be your enemy here
	if s.ReadTimeout >= 1 {
		rtimeout = s.ReadTimeout
	}
	wtimeout := 0*time.Second
	if s.WriteTimeout >= 1 {
		wtimeout = s.WriteTimeout
	}
	srv := Server{r, s, t}
	x := &http.Server{Addr: addr, Handler: &srv,
				ReadTimeout: rtimeout, WriteTimeout:wtimeout}
	err := x.ListenAndServe()
	if err != nil && s.Debug {
		log.Println("Error:", err)
	}
	return &srv, err
}
<|endoftext|>


<commit_before>package main

// Import formatting and IO libraries
import (
	"html/template"
	"io/ioutil"
	"net/http"
)

// Define a structure to hold our page
type Page struct {
	Title string
	Body  []byte // IO libs expect a byte slice rather than a string
}

// Add a save method to our Page struct so we can persist our data
// This method's signature reads: "This is a method named save that takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type error."
func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

// Load pages too
func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

var templates = template.Must(template.ParseFiles("edit.html", "view.html"))
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err = templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
	t.Execute(w, p)
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/view/"):]
	p, err := loadPage(title)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}
	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/edit/"):]
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/save/"):]
	body := r.FormValue("body")
	p := &Page{Title: title, Body: []byte(body)}
	err := p.save()
        if err != nil {
          http.Error(w, err.Error(), http.StatusInternalServerError)
          return
        }
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

func main() {
	http.HandleFunc("/view/", viewHandler)
	http.HandleFunc("/edit/", editHandler)
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
}
<commit_msg>Fix syntax errors.<commit_after>package main

// Import formatting and IO libraries
import (
	"html/template"
	"io/ioutil"
	"net/http"
)

// Define a structure to hold our page
type Page struct {
	Title string
	Body  []byte // IO libs expect a byte slice rather than a string
}

// Add a save method to our Page struct so we can persist our data
// This method's signature reads: "This is a method named save that takes as its receiver p, a pointer to Page . It takes no parameters, and returns a value of type error."
func (p *Page) save() error {
	filename := p.Title + ".txt"
	return ioutil.WriteFile(filename, p.Body, 0600)
}

// Load pages too
func loadPage(title string) (*Page, error) {
	filename := title + ".txt"
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return &Page{Title: title, Body: body}, nil
}

var templates = template.Must(template.ParseFiles("edit.html", "view.html"))
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/view/"):]
	p, err := loadPage(title)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}
	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/edit/"):]
	p, err := loadPage(title)
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request) {
	title := r.URL.Path[len("/save/"):]
	body := r.FormValue("body")
	p := &Page{Title: title, Body: []byte(body)}
	err := p.save()
        if err != nil {
          http.Error(w, err.Error(), http.StatusInternalServerError)
          return
        }
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

func main() {
	http.HandleFunc("/view/", viewHandler)
	http.HandleFunc("/edit/", editHandler)
	http.HandleFunc("/save/", saveHandler)
	http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package main

import (
//	"database/sql"
	"html/template"
//	"log"
	"net/http"
)

type Attrib struct {
	AttAbbr string
	AttDisp string
}

type Slot struct {
	SlotAbbr string
	SlotDisp string
}

type IType struct {
	TypeAbbr string
	TypeDisp string
}

type Effect struct {
	EffAbbr string
	EffDisp string
}

type Resist struct {
	ResAbbr string
	ResDisp string
}

type Flag struct {
	FlagAbbr string
	FlagDisp string
}

type Supp struct {
	SuppAbbr string
	SuppDisp string
}

type Page struct {
	Date    string
	Results []string
	Attribs []Attrib
	Slots   []Slot
	Types   []IType
	Effects []Effect
	Resists []Resist
	Flags   []Flag
	Supps   []Supp
}

func fillStructs() Page {
	p := Page{
        Date: "2020-12-29",
    }

	db := OpenDB()
    defer db.Close()

	query := "SELECT MAX(last_id) FROM items"
    stmt, err := db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    err = stmt.QueryRow().Scan(&p.Date)
	ChkErr(err)

    query = "SELECT attrib_abbr, attrib_display FROM attribs"
	stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

	rows, err := stmt.Query()
    ChkErr(err)
    defer rows.Close()

	for rows.Next() {
		var a Attrib
		err = rows.Scan(&a.AttAbbr, &a.AttDisp)
		ChkErr(err)
		p.Attribs = append(p.Attribs, a)
	}

	query = "SELECT slot_abbr, slot_display FROM slots"
	stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
		var s Slot
		err = rows.Scan(&s.SlotAbbr, &s.SlotDisp)
		ChkErr(err)
		p.Slots = append(p.Slots, s)
	}

	query = "SELECT type_abbr, type_display FROM item_types"
	stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
		var t IType
		err = rows.Scan(&t.TypeAbbr, &t.TypeDisp)
		ChkErr(err)
		p.Types = append(p.Types, t)
	}

	query = "SELECT effect_abbr, effect_display FROM effects"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var e Effect
        err = rows.Scan(&e.EffAbbr, &e.EffDisp)
        ChkErr(err)
        p.Effects = append(p.Effects, e)
    }

	query = "SELECT resist_abbr, resist_display FROM resists"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var r Resist
        err = rows.Scan(&r.ResAbbr, &r.ResDisp)
        ChkErr(err)
        p.Resists = append(p.Resists, r)
    }

	query = "SELECT flag_abbr, flag_display FROM flags"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var f Flag
        err = rows.Scan(&f.FlagAbbr, &f.FlagDisp)
        ChkErr(err)
        p.Flags = append(p.Flags, f)
    }

	query = "SELECT supp_abbr, supp_display FROM supps"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var s Supp
        err = rows.Scan(&s.SuppAbbr, &s.SuppDisp)
        ChkErr(err)
        p.Supps = append(p.Supps, s)
    }

	return p
}

var tmpl = template.Must(template.ParseFiles(
    "html/index.html",
))

func eqHandler(w http.ResponseWriter, r *http.Request) {
	p := fillStructs()
	if r.Method == "POST" {
		p.Results = FindItem(r.PostFormValue("itemName"), "short_stats")
	}
	err := tmpl.Execute(w, p)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

<commit_msg>began breaking out search into component parts<commit_after>package main

import (
//	"database/sql"
	"html/template"
//	"log"
	"net/http"
)

type Attrib struct {
	AttAbbr string
	AttDisp string
}

type Slot struct {
	SlotAbbr string
	SlotDisp string
}

type IType struct {
	TypeAbbr string
	TypeDisp string
}

type Effect struct {
	EffAbbr string
	EffDisp string
}

type Resist struct {
	ResAbbr string
	ResDisp string
}

type Flag struct {
	FlagAbbr string
	FlagDisp string
}

type Supp struct {
	SuppAbbr string
	SuppDisp string
}

type Page struct {
	Date    string
	Results []string
	Attribs []Attrib
	Slots   []Slot
	Types   []IType
	Effects []Effect
	Resists []Resist
	Flags   []Flag
	Supps   []Supp
}

func fillStructs() Page {
	p := Page{
        Date: "2020-12-29",
    }

	db := OpenDB()
    defer db.Close()

	query := "SELECT MAX(last_id) FROM items"
    stmt, err := db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    err = stmt.QueryRow().Scan(&p.Date)
	ChkErr(err)

    query = "SELECT attrib_abbr, attrib_display FROM attribs"
	stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

	rows, err := stmt.Query()
    ChkErr(err)
    defer rows.Close()

	for rows.Next() {
		var a Attrib
		err = rows.Scan(&a.AttAbbr, &a.AttDisp)
		ChkErr(err)
		p.Attribs = append(p.Attribs, a)
	}

	query = "SELECT slot_abbr, slot_display FROM slots"
	stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
		var s Slot
		err = rows.Scan(&s.SlotAbbr, &s.SlotDisp)
		ChkErr(err)
		p.Slots = append(p.Slots, s)
	}

	query = "SELECT type_abbr, type_display FROM item_types"
	stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
		var t IType
		err = rows.Scan(&t.TypeAbbr, &t.TypeDisp)
		ChkErr(err)
		p.Types = append(p.Types, t)
	}

	query = "SELECT effect_abbr, effect_display FROM effects"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var e Effect
        err = rows.Scan(&e.EffAbbr, &e.EffDisp)
        ChkErr(err)
        p.Effects = append(p.Effects, e)
    }

	query = "SELECT resist_abbr, resist_display FROM resists"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var r Resist
        err = rows.Scan(&r.ResAbbr, &r.ResDisp)
        ChkErr(err)
        p.Resists = append(p.Resists, r)
    }

	query = "SELECT flag_abbr, flag_display FROM flags"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var f Flag
        err = rows.Scan(&f.FlagAbbr, &f.FlagDisp)
        ChkErr(err)
        p.Flags = append(p.Flags, f)
    }

	query = "SELECT supp_abbr, supp_display FROM supps"
    stmt, err = db.Prepare(query)
    ChkErr(err)
    defer stmt.Close()

    rows, err = stmt.Query()
    ChkErr(err)
    defer rows.Close()

    for rows.Next() {
        var s Supp
        err = rows.Scan(&s.SuppAbbr, &s.SuppDisp)
        ChkErr(err)
        p.Supps = append(p.Supps, s)
    }

	return p
}

func fillResults(r *http.Request) []string {
	var res []string
	sql := "SELECT long_stats FROM items WHERE "
	if r.PostFormValue("itemName") != "" {
		sql += "item_name LIKE ?"
		res = FindItem(r.PostFormValue("itemName"), "long_stats")
	}
	return res
}

var tmpl = template.Must(template.ParseFiles(
    "html/index.html",
))

func eqHandler(w http.ResponseWriter, r *http.Request) {
	p := fillStructs()
	if r.Method == "POST" {
		p.Results = fillResults(r)
	}
	err := tmpl.Execute(w, p)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

<|endoftext|>


<commit_before>// +build windows

package gopass

import "syscall"
import "unsafe"
import "unicode/utf16"

func getch() byte {
	modkernel32 := syscall.NewLazyDLL("kernel32.dll")
	procReadConsole := modkernel32.NewProc("ReadConsoleW")
	procGetConsoleMode := modkernel32.NewProc("GetConsoleMode")
	procSetConsoleMode := modkernel32.NewProc("SetConsoleMode")

	var mode uint32
	pMode := &mode
	procGetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pMode)))

	var echoMode, lineMode uint32
	echoMode = 4
	lineMode = 2
	var newMode uint32
	newMode = mode ^ (echoMode | lineMode)

	procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(newMode))

	line := make([]uint16, 1)
	pLine := &line[0]
	var n uint16
	procReadConsole.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pLine)), uintptr(len(line)), uintptr(unsafe.Pointer(&n)))

	b := []byte(string(utf16.Decode(line)))

	procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(mode))

	// Not sure how this could happen, but it did for someone
	if len(b) > 0 {
		return b[0]
	} else {
		return 13
	}
}
<commit_msg>Fixes #17<commit_after>// +build windows

package gopass

import "syscall"
import "unsafe"
import "unicode/utf16"

func getch() byte {
	modkernel32 := syscall.NewLazyDLL("kernel32.dll")
	procReadConsole := modkernel32.NewProc("ReadConsoleW")
	procGetConsoleMode := modkernel32.NewProc("GetConsoleMode")
	procSetConsoleMode := modkernel32.NewProc("SetConsoleMode")

	var mode uint32
	pMode := &mode
	procGetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pMode)))

	var echoMode, lineMode uint32
	echoMode = 4
	lineMode = 2
	var newMode uint32
	newMode = mode &^ (echoMode | lineMode)

	procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(newMode))

	line := make([]uint16, 1)
	pLine := &line[0]
	var n uint16
	procReadConsole.Call(uintptr(syscall.Stdin), uintptr(unsafe.Pointer(pLine)), uintptr(len(line)), uintptr(unsafe.Pointer(&n)))

	b := []byte(string(utf16.Decode(line)))

	procSetConsoleMode.Call(uintptr(syscall.Stdin), uintptr(mode))

	// Not sure how this could happen, but it did for someone
	if len(b) > 0 {
		return b[0]
	} else {
		return 13
	}
}
<|endoftext|>


<commit_before>package scene

import (
	"image"

	"github.com/pankona/gomo-simra/examples/sample3/scene/config"
	"github.com/pankona/gomo-simra/simra"
)

// Ball represents a ball
type Ball struct {
	simra.Sprite
	// direction is radian.
	direction float64
	speed     float64
}

// Background represents a sprite for background
type Background struct {
	simra.Sprite
}

// Stage1 represents scene of Stage1.
type Stage1 struct {
	models     Models
	ball       Ball
	background Background
	isTouching bool
}

func (ball *Ball) getPosition() (x, y float32) {
	x = 0
	y = 0
	return x, y
}

func (ball *Ball) setPosition(x, y float32) {
	ball.Sprite.X = x
	ball.Sprite.Y = y
}

func (ball *Ball) getRotate() float32 {
	return ball.Sprite.R
}

func (ball *Ball) setRotate(r float32) {
	ball.Sprite.R = r
}

func (ball *Ball) setDirection(d float64) {
	ball.direction = d
}

func (ball *Ball) move() {
	if ball.direction > 0 && ball.direction < 180 {
		ball.speed += 9.8 / 60
	} else {
		ball.speed -= 9.8 / 60

	}

	/*
		ball.Sprite.X += float32(math.Cos(ball.direction*math.Pi/180) * ball.speed)
		ball.Sprite.Y += float32(math.Sin(ball.direction*math.Pi/180) * ball.speed)
	*/
	ball.Sprite.Y += float32(ball.speed)
	if ball.Sprite.Y < 0 {
		ball.Sprite.Y = 0
		ball.speed = 0
	}

	if ball.Sprite.Y > config.ScreenHeight {
		ball.Sprite.Y = config.ScreenHeight
		ball.speed = 0
	}
	//	simra.LogDebug("cos90, sin90", math.Cos(90*math.Pi/180), math.Sin(90*math.Pi/180))
}

// Initialize initializes Stage1 scene
// This is called from simra.
// simra.GetInstance().SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (scene *Stage1) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.ScreenWidth, config.ScreenHeight)

	// add global touch listener to catch touch end event
	simra.GetInstance().AddTouchListener(scene)

	// TODO: when goes to next scene, remove global touch listener
	// simra.GetInstance().RemoveTouchListener(Stage1)

	// initialize sprites
	scene.initSprites()

	scene.registerModels()

	simra.LogDebug("[OUT]")
}

// OnTouchBegin is called when Stage1 scene is Touched.
func (scene *Stage1) OnTouchBegin(x, y float32) {
	scene.isTouching = true
}

// OnTouchMove is called when Stage1 scene is Touched and moved.
func (scene *Stage1) OnTouchMove(x, y float32) {
	// nop
}

// OnTouchEnd is called when Stage1 scene is Touched and it is released.
func (scene *Stage1) OnTouchEnd(x, y float32) {
	scene.isTouching = false
}

func (scene *Stage1) initSprites() {

	// set size of background
	scene.background.W = config.ScreenWidth
	scene.background.H = config.ScreenHeight

	// put center of screen
	scene.background.X = config.ScreenWidth / 2
	scene.background.Y = config.ScreenHeight / 2
	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background.Sprite)

	// set size of ball
	scene.ball.W = float32(48)
	scene.ball.H = float32(48)

	// put center of screen at start
	scene.ball.X = config.ScreenWidth / 2
	scene.ball.Y = config.ScreenHeight / 2

	simra.GetInstance().AddSprite("ball.png",
		image.Rect(0, 0, int(scene.ball.W), int(scene.ball.H)),
		&scene.ball.Sprite)
}

func (scene *Stage1) registerModels() {
	scene.ball.speed = 1
	scene.ball.direction = 90
	scene.models.RegisterBall(&scene.ball)
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (scene *Stage1) Drive() {
	scene.models.Progress(scene.isTouching)
}
<commit_msg>[#67] make background instance as array<commit_after>package scene

import (
	"image"

	"github.com/pankona/gomo-simra/examples/sample3/scene/config"
	"github.com/pankona/gomo-simra/simra"
)

// Ball represents a ball
type Ball struct {
	simra.Sprite
	// direction is radian.
	direction float64
	speed     float64
}

// Background represents a sprite for background
type Background struct {
	simra.Sprite
}

// Stage1 represents scene of Stage1.
type Stage1 struct {
	models     Models
	ball       Ball
	background [2]Background
	isTouching bool
}

func (ball *Ball) getPosition() (x, y float32) {
	x = 0
	y = 0
	return x, y
}

func (ball *Ball) setPosition(x, y float32) {
	ball.Sprite.X = x
	ball.Sprite.Y = y
}

func (ball *Ball) getRotate() float32 {
	return ball.Sprite.R
}

func (ball *Ball) setRotate(r float32) {
	ball.Sprite.R = r
}

func (ball *Ball) setDirection(d float64) {
	ball.direction = d
}

func (ball *Ball) move() {
	if ball.direction > 0 && ball.direction < 180 {
		ball.speed += 9.8 / 60
	} else {
		ball.speed -= 9.8 / 60

	}

	/*
		ball.Sprite.X += float32(math.Cos(ball.direction*math.Pi/180) * ball.speed)
		ball.Sprite.Y += float32(math.Sin(ball.direction*math.Pi/180) * ball.speed)
	*/
	ball.Sprite.Y += float32(ball.speed)
	if ball.Sprite.Y < 0 {
		ball.Sprite.Y = 0
		ball.speed = 0
	}

	if ball.Sprite.Y > config.ScreenHeight {
		ball.Sprite.Y = config.ScreenHeight
		ball.speed = 0
	}
	//	simra.LogDebug("cos90, sin90", math.Cos(90*math.Pi/180), math.Sin(90*math.Pi/180))
}

// Initialize initializes Stage1 scene
// This is called from simra.
// simra.GetInstance().SetDesiredScreenSize should be called to determine
// screen size of this scene.
func (scene *Stage1) Initialize() {
	simra.LogDebug("[IN]")

	simra.GetInstance().SetDesiredScreenSize(config.ScreenWidth, config.ScreenHeight)

	// add global touch listener to catch touch end event
	simra.GetInstance().AddTouchListener(scene)

	// TODO: when goes to next scene, remove global touch listener
	// simra.GetInstance().RemoveTouchListener(Stage1)

	// initialize sprites
	scene.initSprites()

	scene.registerModels()

	simra.LogDebug("[OUT]")
}

// OnTouchBegin is called when Stage1 scene is Touched.
func (scene *Stage1) OnTouchBegin(x, y float32) {
	scene.isTouching = true
}

// OnTouchMove is called when Stage1 scene is Touched and moved.
func (scene *Stage1) OnTouchMove(x, y float32) {
	// nop
}

// OnTouchEnd is called when Stage1 scene is Touched and it is released.
func (scene *Stage1) OnTouchEnd(x, y float32) {
	scene.isTouching = false
}

func (scene *Stage1) initSprites() {

	// set size of background
	scene.background[0].W = config.ScreenWidth
	scene.background[0].H = config.ScreenHeight

	// put center of screen
	scene.background[0].X = config.ScreenWidth / 2
	scene.background[0].Y = config.ScreenHeight / 2
	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background[0].Sprite)

	// set size of background
	scene.background[1].W = config.ScreenWidth
	scene.background[1].H = config.ScreenHeight

	// put out of screen
	scene.background[1].X = config.ScreenWidth/2 + config.ScreenWidth
	scene.background[1].Y = config.ScreenHeight / 2
	simra.GetInstance().AddSprite("bg.png",
		image.Rect(0, 0, config.ScreenWidth, config.ScreenHeight),
		&scene.background[1].Sprite)

	// set size of ball
	scene.ball.W = float32(48)
	scene.ball.H = float32(48)

	// put center of screen at start
	scene.ball.X = config.ScreenWidth / 2
	scene.ball.Y = config.ScreenHeight / 2

	simra.GetInstance().AddSprite("ball.png",
		image.Rect(0, 0, int(scene.ball.W), int(scene.ball.H)),
		&scene.ball.Sprite)
}

func (scene *Stage1) registerModels() {
	scene.ball.speed = 1
	scene.ball.direction = 90
	scene.models.RegisterBall(&scene.ball)
}

// Drive is called from simra.
// This is used to update sprites position.
// This will be called 60 times per sec.
func (scene *Stage1) Drive() {
	scene.models.Progress(scene.isTouching)
}
<|endoftext|>


<commit_before>// PluginManger manages loading, unloading, and swapping
// of plugins
package control

import (
	"crypto/rsa"
	"errors"
	"fmt"
	"log"
	"strconv"
	"sync"
	"time"

	"github.com/intelsdilabs/pulse/control/plugin"
)

const (
	// loadedPlugin States
	DetectedState pluginState = "detected"
	LoadingState  pluginState = "loading"
	LoadedState   pluginState = "loaded"
	UnloadedState pluginState = "unloaded"
)

type pluginState string

type loadedPlugins struct {
	table       *[]*loadedPlugin
	mutex       *sync.Mutex
	currentIter int
}

func newLoadedPlugins() *loadedPlugins {
	var t []*loadedPlugin
	return &loadedPlugins{
		table:       &t,
		mutex:       new(sync.Mutex),
		currentIter: 0,
	}
}

// adds a loadedPlugin pointer to the loadedPlugins table
func (l *loadedPlugins) Append(lp *loadedPlugin) error {

	l.mutex.Lock()
	defer l.mutex.Unlock()

	// make sure we don't already  have a pointer to this plugin in the table
	for i, pl := range *l.table {
		if lp == pl {
			return errors.New("plugin already loaded at index " + strconv.Itoa(i))
		}
	}

	// append
	newLoadedPlugins := append(*l.table, lp)
	// overwrite
	l.table = &newLoadedPlugins

	return nil
}

// returns a copy of the table
func (l *loadedPlugins) Table() []*loadedPlugin {
	return *l.table
}

// used to transactionally retrieve a loadedPlugin pointer from the table
func (l *loadedPlugins) Get(index int) (*loadedPlugin, error) {
	l.Lock()
	defer l.Unlock()

	if index > len(*l.table)-1 {
		return nil, errors.New("index out of range")
	}

	return (*l.table)[index], nil
}

// used to lock the plugin table externally,
// when iterating in unsafe scenarios
func (l *loadedPlugins) Lock() {
	l.mutex.Lock()
}

func (l *loadedPlugins) Unlock() {
	l.mutex.Unlock()
}

/* we need an atomic read / write transaction for the splice when removing a plugin,
   as the plugin is found by its index in the table.  By having the default Splice
   method block, we protect against accidental use.  Using nonblocking requires explicit
   invocation.
*/
func (l *loadedPlugins) splice(index int) {
	lp := append((*l.table)[:index], (*l.table)[index+1:]...)
	l.table = &lp
}

// splice unsafely
func (l *loadedPlugins) NonblockingSplice(index int) {
	l.splice(index)
}

// atomic splice
func (l *loadedPlugins) Splice(index int) {

	l.mutex.Lock()
	l.splice(index)
	l.mutex.Unlock()

}

// returns the item of a certain index in the table.
// to be used when iterating over the table
func (l *loadedPlugins) Item() (int, *loadedPlugin) {
	i := l.currentIter - 1
	return i, (*l.table)[i]
}

// Returns true until the "end" of the table is reached.
// used to iterate over the table:
func (l *loadedPlugins) Next() bool {
	l.currentIter++
	if l.currentIter > len(*l.table) {
		l.currentIter = 0
		return false
	}
	return true
}

// the struct representing a plugin that is loaded into Pulse
type loadedPlugin struct {
	Meta       plugin.PluginMeta
	Path       string
	Type       plugin.PluginType
	State      pluginState
	Token      string
	LoadedTime time.Time
}

// returns plugin name
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) Name() string {
	return lp.Meta.Name
}

// returns plugin version
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) Version() int {
	return lp.Meta.Version
}

// returns plugin type as a string
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) TypeName() string {
	return lp.Type.String()
}

// returns current plugin state
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) Status() string {
	return string(lp.State)
}

// returns a unix timestamp of the LoadTime of a plugin
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) LoadedTimestamp() int64 {
	return lp.LoadedTime.Unix()
}

// the struct representing the object responsible for
// loading and unloading plugins
type pluginManager struct {
	loadedPlugins *loadedPlugins

	privKey *rsa.PrivateKey
	pubKey  *rsa.PublicKey
}

func newPluginManager() *pluginManager {
	p := &pluginManager{
		loadedPlugins: newLoadedPlugins(),
	}
	return p
}

// Returns loaded plugins
func (p *pluginManager) LoadedPlugins() *loadedPlugins {
	return p.loadedPlugins
}

// Load is the method for loading a plugin and
// saving plugin into the LoadedPlugins array
func (p *pluginManager) LoadPlugin(path string) (*loadedPlugin, error) {
	log.Printf("Attempting to load: %s\v", path)
	lPlugin := new(loadedPlugin)
	lPlugin.Path = path
	lPlugin.State = DetectedState

	ePlugin, err := plugin.NewExecutablePlugin(p.generateArgs(false), lPlugin.Path, true)

	log.Println(ePlugin)

	if err != nil {
		log.Println(err)
		return nil, err
	}

	err = ePlugin.Start()
	if err != nil {
		log.Println("Start error" + err.Error())
		return nil, err
	}

	var resp *plugin.Response
	resp, err = ePlugin.WaitForResponse(time.Second * 3)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	if resp.Type == plugin.CollectorPluginType {
		ap, err := newAvailablePlugin(resp)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		col := ap.Client.(plugin.CollectorPlugin)
		args := new(plugin.GetMetricTypesArgs)
		var reply *plugin.GetMetricTypesReply
		//TODO update metric catalog with metric types below
		_ = col.GetMetricTypes(*args, reply)
	}
	ePlugin.Kill()

	// if err != nil {
	// 	log.Println(err)
	// 	return nil, err
	// }

	if resp.State != plugin.PluginSuccess {
		log.Printf("Plugin loading did not succeed: %s\n", resp.ErrorMessage)
		return nil, fmt.Errorf("Plugin loading did not succeed: %s\n", resp.ErrorMessage)
	}

	lPlugin.Meta = resp.Meta
	lPlugin.Type = resp.Type
	lPlugin.Token = resp.Token
	lPlugin.LoadedTime = time.Now()
	lPlugin.State = LoadedState

	err = p.LoadedPlugins().Append(lPlugin)
	if err != nil {
		return nil, err
	}

	return lPlugin, nil
}

// unloads a plugin from the LoadedPlugins table
func (p *pluginManager) UnloadPlugin(pl CatalogedPlugin) error {

	// We hold the mutex here to safely splice out the plugin from the table.
	// Using a stale index can be slightly dangerous (unloading incorrect plugin).
	p.LoadedPlugins().Lock()
	defer p.LoadedPlugins().Unlock()

	var (
		index  int
		plugin *loadedPlugin
		found  bool
	)

	// find it in the list
	for p.LoadedPlugins().Next() {
		if !found {
			i, lp := p.LoadedPlugins().Item()
			// plugin key is its name && version
			if pl.Name() == lp.Meta.Name && pl.Version() == lp.Meta.Version {
				index = i
				plugin = lp
				// use bool for found becase we cannot check against default type values
				// index of given plugin may be 0
				found = true
			}
		} else {
			// break out of the loop once we find the plugin we're looking for
			break
		}
	}

	if !found {
		return errors.New("plugin [" + pl.Name() + "] -- [" + strconv.Itoa(pl.Version()) + "] not found (has it already been unloaded?)")
	}

	if plugin.State != LoadedState {
		return errors.New("Plugin must be in a LoadedState")
	}

	// splice out the given plugin
	p.LoadedPlugins().NonblockingSplice(index)

	return nil
}

func (p *pluginManager) generateArgs(daemon bool) plugin.Arg {
	a := plugin.Arg{
		ControlPubKey: p.pubKey,
		PluginLogPath: "/tmp/pulse-plugin.log",
		RunAsDaemon:   daemon,
	}
	return a
}
<commit_msg>Consistency on use of Lock() and Unlock()<commit_after>// PluginManger manages loading, unloading, and swapping
// of plugins
package control

import (
	"crypto/rsa"
	"errors"
	"fmt"
	"log"
	"strconv"
	"sync"
	"time"

	"github.com/intelsdilabs/pulse/control/plugin"
)

const (
	// loadedPlugin States
	DetectedState pluginState = "detected"
	LoadingState  pluginState = "loading"
	LoadedState   pluginState = "loaded"
	UnloadedState pluginState = "unloaded"
)

type pluginState string

type loadedPlugins struct {
	table       *[]*loadedPlugin
	mutex       *sync.Mutex
	currentIter int
}

func newLoadedPlugins() *loadedPlugins {
	var t []*loadedPlugin
	return &loadedPlugins{
		table:       &t,
		mutex:       new(sync.Mutex),
		currentIter: 0,
	}
}

// adds a loadedPlugin pointer to the loadedPlugins table
func (l *loadedPlugins) Append(lp *loadedPlugin) error {

	l.Lock()
	defer l.Unlock()

	// make sure we don't already  have a pointer to this plugin in the table
	for i, pl := range *l.table {
		if lp == pl {
			return errors.New("plugin already loaded at index " + strconv.Itoa(i))
		}
	}

	// append
	newLoadedPlugins := append(*l.table, lp)
	// overwrite
	l.table = &newLoadedPlugins

	return nil
}

// returns a copy of the table
func (l *loadedPlugins) Table() []*loadedPlugin {
	return *l.table
}

// used to transactionally retrieve a loadedPlugin pointer from the table
func (l *loadedPlugins) Get(index int) (*loadedPlugin, error) {
	l.Lock()
	defer l.Unlock()

	if index > len(*l.table)-1 {
		return nil, errors.New("index out of range")
	}

	return (*l.table)[index], nil
}

// used to lock the plugin table externally,
// when iterating in unsafe scenarios
func (l *loadedPlugins) Lock() {
	l.mutex.Lock()
}

func (l *loadedPlugins) Unlock() {
	l.mutex.Unlock()
}

/* we need an atomic read / write transaction for the splice when removing a plugin,
   as the plugin is found by its index in the table.  By having the default Splice
   method block, we protect against accidental use.  Using nonblocking requires explicit
   invocation.
*/
func (l *loadedPlugins) splice(index int) {
	lp := append((*l.table)[:index], (*l.table)[index+1:]...)
	l.table = &lp
}

// splice unsafely
func (l *loadedPlugins) NonblockingSplice(index int) {
	l.splice(index)
}

// atomic splice
func (l *loadedPlugins) Splice(index int) {

	l.Lock()
	l.splice(index)
	l.Unlock()

}

// returns the item of a certain index in the table.
// to be used when iterating over the table
func (l *loadedPlugins) Item() (int, *loadedPlugin) {
	i := l.currentIter - 1
	return i, (*l.table)[i]
}

// Returns true until the "end" of the table is reached.
// used to iterate over the table:
func (l *loadedPlugins) Next() bool {
	l.currentIter++
	if l.currentIter > len(*l.table) {
		l.currentIter = 0
		return false
	}
	return true
}

// the struct representing a plugin that is loaded into Pulse
type loadedPlugin struct {
	Meta       plugin.PluginMeta
	Path       string
	Type       plugin.PluginType
	State      pluginState
	Token      string
	LoadedTime time.Time
}

// returns plugin name
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) Name() string {
	return lp.Meta.Name
}

// returns plugin version
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) Version() int {
	return lp.Meta.Version
}

// returns plugin type as a string
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) TypeName() string {
	return lp.Type.String()
}

// returns current plugin state
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) Status() string {
	return string(lp.State)
}

// returns a unix timestamp of the LoadTime of a plugin
// implements the CatalogedPlugin interface
func (lp *loadedPlugin) LoadedTimestamp() int64 {
	return lp.LoadedTime.Unix()
}

// the struct representing the object responsible for
// loading and unloading plugins
type pluginManager struct {
	loadedPlugins *loadedPlugins

	privKey *rsa.PrivateKey
	pubKey  *rsa.PublicKey
}

func newPluginManager() *pluginManager {
	p := &pluginManager{
		loadedPlugins: newLoadedPlugins(),
	}
	return p
}

// Returns loaded plugins
func (p *pluginManager) LoadedPlugins() *loadedPlugins {
	return p.loadedPlugins
}

// Load is the method for loading a plugin and
// saving plugin into the LoadedPlugins array
func (p *pluginManager) LoadPlugin(path string) (*loadedPlugin, error) {
	log.Printf("Attempting to load: %s\v", path)
	lPlugin := new(loadedPlugin)
	lPlugin.Path = path
	lPlugin.State = DetectedState

	ePlugin, err := plugin.NewExecutablePlugin(p.generateArgs(false), lPlugin.Path, true)

	log.Println(ePlugin)

	if err != nil {
		log.Println(err)
		return nil, err
	}

	err = ePlugin.Start()
	if err != nil {
		log.Println("Start error" + err.Error())
		return nil, err
	}

	var resp *plugin.Response
	resp, err = ePlugin.WaitForResponse(time.Second * 3)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	if resp.Type == plugin.CollectorPluginType {
		ap, err := newAvailablePlugin(resp)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		col := ap.Client.(plugin.CollectorPlugin)
		args := new(plugin.GetMetricTypesArgs)
		var reply *plugin.GetMetricTypesReply
		//TODO update metric catalog with metric types below
		_ = col.GetMetricTypes(*args, reply)
	}
	ePlugin.Kill()

	// if err != nil {
	// 	log.Println(err)
	// 	return nil, err
	// }

	if resp.State != plugin.PluginSuccess {
		log.Printf("Plugin loading did not succeed: %s\n", resp.ErrorMessage)
		return nil, fmt.Errorf("Plugin loading did not succeed: %s\n", resp.ErrorMessage)
	}

	lPlugin.Meta = resp.Meta
	lPlugin.Type = resp.Type
	lPlugin.Token = resp.Token
	lPlugin.LoadedTime = time.Now()
	lPlugin.State = LoadedState

	err = p.LoadedPlugins().Append(lPlugin)
	if err != nil {
		return nil, err
	}

	return lPlugin, nil
}

// unloads a plugin from the LoadedPlugins table
func (p *pluginManager) UnloadPlugin(pl CatalogedPlugin) error {

	// We hold the mutex here to safely splice out the plugin from the table.
	// Using a stale index can be slightly dangerous (unloading incorrect plugin).
	p.LoadedPlugins().Lock()
	defer p.LoadedPlugins().Unlock()

	var (
		index  int
		plugin *loadedPlugin
		found  bool
	)

	// find it in the list
	for p.LoadedPlugins().Next() {
		if !found {
			i, lp := p.LoadedPlugins().Item()
			// plugin key is its name && version
			if pl.Name() == lp.Meta.Name && pl.Version() == lp.Meta.Version {
				index = i
				plugin = lp
				// use bool for found becase we cannot check against default type values
				// index of given plugin may be 0
				found = true
			}
		} else {
			// break out of the loop once we find the plugin we're looking for
			break
		}
	}

	if !found {
		return errors.New("plugin [" + pl.Name() + "] -- [" + strconv.Itoa(pl.Version()) + "] not found (has it already been unloaded?)")
	}

	if plugin.State != LoadedState {
		return errors.New("Plugin must be in a LoadedState")
	}

	// splice out the given plugin
	p.LoadedPlugins().NonblockingSplice(index)

	return nil
}

func (p *pluginManager) generateArgs(daemon bool) plugin.Arg {
	a := plugin.Arg{
		ControlPubKey: p.pubKey,
		PluginLogPath: "/tmp/pulse-plugin.log",
		RunAsDaemon:   daemon,
	}
	return a
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package upgrades

import (
	"github.com/juju/errors"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/utils"
	"github.com/juju/juju/version"
)

// stepsFor126 returns upgrade steps for Juju 1.26.
func stepsFor126() []Step {
	return []Step{}
}

// stateStepsFor126 returns upgrade steps for Juju 1.26 that manipulate state directly.
func stateStepsFor126() []Step {
	return []Step{
		&upgradeStep{
			description: "add the version field to all settings docs",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				return state.MigrateSettingsSchema(context.State())
			},
		},
		&upgradeStep{
			description: "add status to filesystem",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				return state.AddFilesystemStatus(context.State())
			},
		},
		&upgradeStep{
			description: "upgrade model config",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				// TODO(axw) updateModelConfig should be
				// called for all upgrades, to decouple this
				// package from provider-specific upgrades.
				st := context.State()
				return upgradeModelConfig(st, st, environs.GlobalProviderRegistry())
			},
		},
		//TODO(perrito666) make this an unconditional upgrade step.
		// it would be ideal not to have to modify this package whenever we add provider upgrade steps.
		&upgradeStep{
			description: "provider side upgrades",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				st := context.State()
				env, err := utils.GetEnviron(st)
				if err != nil {
					return errors.Annotate(err, "getting provider for upgrade")
				}
				return upgradeProviderChanges(env, st, version.Number{Major: 1, Minor: 26})
			},
		},
		//TODO(perrito666) make this an unconditional upgrade step.
		// it would be ideal not to have to modify this package whenever we add provider upgrade steps.
		&upgradeStep{
			description: "provider side upgrades",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				st := context.State()
				env, err := utils.GetEnvironment(st)
				if err != nil {
					return errors.Annotate(err, "getting provider for upgrade")
				}
				return upgradeProviderChanges(env, st, version.Number{Major: 1, Minor: 26})
			},
		},
		&upgradeStep{
			description: "update machine preferred addresses",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				return state.AddPreferredAddressesToMachines(context.State())
			},
		},
	}
}
<commit_msg>Fix conflicts<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package upgrades

import (
	"github.com/juju/errors"

	"github.com/juju/juju/environs"
	"github.com/juju/juju/state"
	"github.com/juju/juju/state/utils"
	"github.com/juju/juju/version"
)

// stepsFor126 returns upgrade steps for Juju 1.26.
func stepsFor126() []Step {
	return []Step{}
}

// stateStepsFor126 returns upgrade steps for Juju 1.26 that manipulate state directly.
func stateStepsFor126() []Step {
	return []Step{
		&upgradeStep{
			description: "add the version field to all settings docs",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				return state.MigrateSettingsSchema(context.State())
			},
		},
		&upgradeStep{
			description: "add status to filesystem",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				return state.AddFilesystemStatus(context.State())
			},
		},
		&upgradeStep{
			description: "upgrade model config",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				// TODO(axw) updateModelConfig should be
				// called for all upgrades, to decouple this
				// package from provider-specific upgrades.
				st := context.State()
				return upgradeModelConfig(st, st, environs.GlobalProviderRegistry())
			},
		},
		//TODO(perrito666) make this an unconditional upgrade step.
		// it would be ideal not to have to modify this package whenever we add provider upgrade steps.
		&upgradeStep{
			description: "provider side upgrades",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				st := context.State()
				env, err := utils.GetEnviron(st)
				if err != nil {
					return errors.Annotate(err, "getting provider for upgrade")
				}
				return upgradeProviderChanges(env, st, version.Number{Major: 1, Minor: 26})
			},
		},
		&upgradeStep{
			description: "update machine preferred addresses",
			targets:     []Target{DatabaseMaster},
			run: func(context Context) error {
				return state.AddPreferredAddressesToMachines(context.State())
			},
		},
	}
}
<|endoftext|>