<commit_before>package processing

import (
	"github.com/alevinval/fingerprints/internal/matrix"
)

type MinutiaeType byte

const (
	Termination MinutiaeType = iota
	Bifurcation
	Unknown
)

type Minutiae struct {
	X     int
	Y     int
	Angle float64
	Type  MinutiaeType
}

func ExtractMinutiae(skeleton *matrix.M, filteredDirectional *matrix.M, segmented *matrix.M) []Minutiae {
	minutiaes := []Minutiae{}
	bounds := skeleton.Bounds()
	for y := bounds.Min.Y + 1; y < bounds.Max.Y-1; y++ {
		for x := bounds.Min.X + 1; x < bounds.Max.X-1; x++ {
			if segmented.At(x, y) == 0 {
				continue
			}
			minutiaeType := matchMinutiaeType(skeleton, x, y)
			if minutiaeType != Unknown {
				minutiae := Minutiae{
					X:     x,
					Y:     y,
					Angle: filteredDirectional.At(x, y),
					Type:  minutiaeType,
				}
				minutiaes = append(minutiaes, minutiae)
			}
		}
	}
	return minutiaes
}

func matchMinutiaeType(in *matrix.M, x, y int) MinutiaeType {
	p0 := in.At(x-1, y-1) > 0
	p1 := in.At(x, y-1) > 0
	p2 := in.At(x+1, y-1) > 0
	p3 := in.At(x+1, y) > 0
	p4 := in.At(x+1, y+1) > 0
	p5 := in.At(x, y+1) > 0
	p6 := in.At(x-1, y+1) > 0
	p7 := in.At(x-1, y) > 0
	pc := in.At(x, y) > 0
	f := func(pc, p0, p1, p2, p3, p4, p5, p6, p7 bool) bool {
		return pc && p0 && p1 && p2 && p3 && p4 && p5 && p6 && p7
	}

	/*
		p0 p1 p2
		p7 pc p3
		p6 p5 p4
	*/
	isBifurcation := (
	// Diagonals
	f(pc, p0, p3, p5, !p1, !p2, !p4, !p6, !p7) ||
		f(pc, p4, p1, p7, !p0, !p2, !p3, !p5, !p6) ||
		f(pc, p2, p7, p5, !p0, !p1, !p3, !p4, !p6) ||
		f(pc, p6, p1, p3, !p0, !p2, !p4, !p5, !p7) ||
		// Verticals/Horizontals
		f(pc, p1, p6, p4, !p0, !p2, !p3, !p5, !p7) ||
		f(pc, p3, p0, p6, !p1, !p2, !p4, !p5, !p7) ||
		f(pc, p5, p0, p2, !p1, !p3, !p4, !p6, !p7) ||
		f(pc, p6, p2, p4, !p0, !p1, !p3, !p5, !p7) ||
		// Perpendiculars clock and counter-clock wise
		f(pc, p1, p3, p5, !p0, !p2, !p4, !p6, !p7) ||
		f(pc, p1, p7, p5, !p0, !p2, !p3, !p4, !p6) ||
		f(pc, p3, p7, p5, !p0, !p1, !p2, !p4, !p6) ||
		f(pc, p3, p7, p1, !p0, !p2, !p4, !p5, !p6) ||
		f(pc, p5, p7, p1, !p0, !p2, !p3, !p4, !p6) ||
		f(pc, p5, p3, p1, !p0, !p2, !p4, !p6, !p7) ||
		f(pc, p7, p1, p3, !p0, !p2, !p4, !p5, !p6) ||
		f(pc, p7, p5, p3, !p0, !p2, !p3, !p4, !p6))

	isTermination := (f(pc, p0, !p1, !p2, !p3, !p4, !p5, !p6, !p7) ||
		f(pc, p1, !p0, !p2, !p3, !p4, !p5, !p6, !p7) ||
		f(pc, p2, !p0, !p1, !p3, !p4, !p5, !p6, !p7) ||
		f(pc, p3, !p0, !p1, !p2, !p4, !p5, !p6, !p7) ||
		f(pc, p4, !p0, !p1, !p2, !p3, !p5, !p6, !p7) ||
		f(pc, p5, !p0, !p1, !p2, !p3, !p4, !p6, !p7) ||
		f(pc, p6, !p0, !p1, !p2, !p3, !p4, !p5, !p7) ||
		f(pc, p7, !p0, !p1, !p2, !p3, !p4, !p5, !p6))

	if isBifurcation {
		return Bifurcation
	} else if isTermination {
		return Termination
	} else {
		return Unknown
	}
}
<commit_msg>fix overlook<commit_after>package processing

import (
	"github.com/alevinval/fingerprints/internal/matrix"
)

type MinutiaeType byte

const (
	Termination MinutiaeType = iota
	Bifurcation
	Unknown
)

type Minutiae struct {
	X     int
	Y     int
	Angle float64
	Type  MinutiaeType
}

func ExtractMinutiae(skeleton *matrix.M, filteredDirectional *matrix.M, segmented *matrix.M) []Minutiae {
	minutiaes := []Minutiae{}
	bounds := skeleton.Bounds()
	for y := bounds.Min.Y + 1; y < bounds.Max.Y-1; y++ {
		for x := bounds.Min.X + 1; x < bounds.Max.X-1; x++ {
			if segmented.At(x, y) == 0 {
				continue
			}
			minutiaeType := matchMinutiaeType(skeleton, x, y)
			if minutiaeType != Unknown {
				minutiae := Minutiae{
					X:     x,
					Y:     y,
					Angle: filteredDirectional.At(x, y),
					Type:  minutiaeType,
				}
				minutiaes = append(minutiaes, minutiae)
			}
		}
	}
	return minutiaes
}

func matchMinutiaeType(in *matrix.M, x, y int) MinutiaeType {
	p0 := in.At(x-1, y-1) > 0
	p1 := in.At(x, y-1) > 0
	p2 := in.At(x+1, y-1) > 0
	p3 := in.At(x+1, y) > 0
	p4 := in.At(x+1, y+1) > 0
	p5 := in.At(x, y+1) > 0
	p6 := in.At(x-1, y+1) > 0
	p7 := in.At(x-1, y) > 0
	pc := in.At(x, y) > 0
	f := func(pc, p0, p1, p2, p3, p4, p5, p6, p7 bool) bool {
		return pc && p0 && p1 && p2 && p3 && p4 && p5 && p6 && p7
	}

	/*
		p0 p1 p2
		p7 pc p3
		p6 p5 p4
	*/
	isBifurcation := (
	// Diagonals
	f(pc, p0, p3, p5, !p1, !p2, !p4, !p6, !p7) ||
		f(pc, p4, p1, p7, !p0, !p2, !p3, !p5, !p6) ||
		f(pc, p2, p7, p5, !p0, !p1, !p3, !p4, !p6) ||
		f(pc, p6, p1, p3, !p0, !p2, !p4, !p5, !p7) ||
		// Verticals/Horizontals
		f(pc, p1, p6, p4, !p0, !p2, !p3, !p5, !p7) ||
		f(pc, p3, p0, p6, !p1, !p2, !p4, !p5, !p7) ||
		f(pc, p5, p0, p2, !p1, !p3, !p4, !p6, !p7) ||
		f(pc, p6, p2, p4, !p0, !p1, !p3, !p5, !p7) ||
		// Perpendiculars clock and counter-clock wise
		f(pc, p1, p3, p5, !p0, !p2, !p4, !p6, !p7) ||
		f(pc, p1, p7, p5, !p0, !p2, !p3, !p4, !p6) ||
		f(pc, p3, p7, p5, !p0, !p1, !p2, !p4, !p6) ||
		f(pc, p3, p7, p1, !p0, !p2, !p4, !p5, !p6) ||
		f(pc, p5, p7, p1, !p0, !p2, !p3, !p4, !p6) ||
		f(pc, p5, p3, p1, !p0, !p2, !p4, !p6, !p7) ||
		f(pc, p7, p1, p3, !p0, !p2, !p4, !p5, !p6) ||
		f(pc, p7, p5, p3, !p0, !p1, !p2, !p4, !p6))

	isTermination := (f(pc, p0, !p1, !p2, !p3, !p4, !p5, !p6, !p7) ||
		f(pc, p1, !p0, !p2, !p3, !p4, !p5, !p6, !p7) ||
		f(pc, p2, !p0, !p1, !p3, !p4, !p5, !p6, !p7) ||
		f(pc, p3, !p0, !p1, !p2, !p4, !p5, !p6, !p7) ||
		f(pc, p4, !p0, !p1, !p2, !p3, !p5, !p6, !p7) ||
		f(pc, p5, !p0, !p1, !p2, !p3, !p4, !p6, !p7) ||
		f(pc, p6, !p0, !p1, !p2, !p3, !p4, !p5, !p7) ||
		f(pc, p7, !p0, !p1, !p2, !p3, !p4, !p5, !p6))

	if isBifurcation {
		return Bifurcation
	} else if isTermination {
		return Termination
	} else {
		return Unknown
	}
}
<|endoftext|>


<commit_before>package readpassword

import (
	"os"

	"github.com/rfjakob/gocryptfs/internal/exitcodes"
	"github.com/rfjakob/gocryptfs/internal/tlog"

	"github.com/xaionaro-go/cryptoWallet"
	"github.com/xaionaro-go/cryptoWallet/vendors"
)

const (
	// TrezorPayloadLen is the length of the payload data passed to Trezor's
	// CipherKeyValue function.
	TrezorPayloadLen        = 32
	trezorNonce             = "" // the "nonce" is optional and has no use in here
	trezorKeyName           = "gocryptfs"
	trezorKeyDerivationPath = `m/10019'/0'`
)

func trezorGetPin(title, description, ok, cancel string) ([]byte, error) {
	return Once("", title), nil
}
func trezorGetConfirm(title, description, ok, cancel string) (bool, error) {
	return false, nil // do not retry on connection failure
}

// Trezor reads 32 deterministically derived bytes from a
// SatoshiLabs Trezor USB security module.
// The bytes are pseudorandom binary data and may contain null bytes.
// This function either succeeds and returns 32 bytes or calls os.Exit to end
// the application.
func Trezor(payload []byte) []byte {
	if len(payload) != TrezorPayloadLen {
		tlog.Fatal.Printf("Invalid TrezorPayload length: wanted %d, got %d bytes\n", TrezorPayloadLen, len(payload))
		os.Exit(exitcodes.LoadConf)
	}

	// Find all trezor devices
	trezors := cryptoWallet.Find(cryptoWallet.Filter{
		VendorID:   &[]uint16{vendors.GetVendorID("satoshilabs")}[0],
		ProductIDs: []uint16{1 /* Trezor One */},
	})

	// ATM, we require to one and only one trezor device to be connected.
	// The support of multiple trezor devices is not implemented, yet.
	if len(trezors) == 0 {
		tlog.Fatal.Printf("Trezor device is not found. Check the connection.")
		os.Exit(exitcodes.TrezorError)
	}
	if len(trezors) > 1 {
		tlog.Fatal.Printf("It's more than one Trezor device connected. This case is not implemented, yet. The number of currently connected devices: %v.", len(trezors))
		os.Exit(exitcodes.TrezorError)
	}

	// Using the first found device
	trezor := trezors[0]

	// Trezor may ask for PIN or Passphrase. Setting the handler for this case.
	trezor.SetGetPinFunc(trezorGetPin)

	// In some cases (like lost connection to the Trezor device and cannot
	// reconnect) it's required to get a confirmation from the user to
	// retry to reconnect. Setting the handler for this case.
	trezor.SetGetConfirmFunc(trezorGetConfirm)

	// To reset the state of the device and check if it's initialized.
	// If device is not initialized then trezor.Reset() will return an
	// error.
	err := trezor.Reset()
	if err != nil {
		tlog.Fatal.Printf("Cannot reset the Trezor device. Error: %v", err.Error())
		os.Exit(exitcodes.TrezorError)
	}

	// To generate a deterministic key we trying to decrypt our
	// predefined constant key using the Trezor device. The resulting key
	// will depend on next variables:
	// * the Trezor master key;
	// * the passphrase (passed to the Trezor).
	//
	// The right key will be received only if both values (mentioned
	// above) are correct.
	//
	// Note:
	// Also the resulting key depends on this values (that we defined as
	// constants above):
	// * the key derivation path;
	// * the "encrypted" payload;
	// * the nonce;
	// * the key name.
	key, err := trezor.DecryptKey(trezorKeyDerivationPath, payload, []byte(trezorNonce), trezorKeyName)
	if err != nil {
		tlog.Fatal.Printf("Cannot get the key from the Trezor device. Error description:\n\t%v", err.Error())
		os.Exit(exitcodes.TrezorError)
	}

	// Everything ok
	return key
}
<commit_msg>trezor: add sanity checks for decrypted value<commit_after>package readpassword

import (
	"bytes"
	"log"
	"os"

	"github.com/rfjakob/gocryptfs/internal/exitcodes"
	"github.com/rfjakob/gocryptfs/internal/tlog"

	"github.com/xaionaro-go/cryptoWallet"
	"github.com/xaionaro-go/cryptoWallet/vendors"
)

const (
	// TrezorPayloadLen is the length of the payload data passed to Trezor's
	// CipherKeyValue function.
	TrezorPayloadLen        = 32
	trezorNonce             = "" // the "nonce" is optional and has no use in here
	trezorKeyName           = "gocryptfs"
	trezorKeyDerivationPath = `m/10019'/0'`
)

func trezorGetPin(title, description, ok, cancel string) ([]byte, error) {
	return Once("", title), nil
}
func trezorGetConfirm(title, description, ok, cancel string) (bool, error) {
	return false, nil // do not retry on connection failure
}

// Trezor reads 32 deterministically derived bytes from a
// SatoshiLabs Trezor USB security module.
// The bytes are pseudorandom binary data and may contain null bytes.
// This function either succeeds and returns 32 bytes or calls os.Exit to end
// the application.
func Trezor(payload []byte) []byte {
	if len(payload) != TrezorPayloadLen {
		tlog.Fatal.Printf("Invalid TrezorPayload length: wanted %d, got %d bytes\n", TrezorPayloadLen, len(payload))
		os.Exit(exitcodes.LoadConf)
	}

	// Find all trezor devices
	trezors := cryptoWallet.Find(cryptoWallet.Filter{
		VendorID:   &[]uint16{vendors.GetVendorID("satoshilabs")}[0],
		ProductIDs: []uint16{1 /* Trezor One */},
	})

	// ATM, we require to one and only one trezor device to be connected.
	// The support of multiple trezor devices is not implemented, yet.
	if len(trezors) == 0 {
		tlog.Fatal.Printf("Trezor device is not found. Check the connection.")
		os.Exit(exitcodes.TrezorError)
	}
	if len(trezors) > 1 {
		tlog.Fatal.Printf("It's more than one Trezor device connected. This case is not implemented, yet. The number of currently connected devices: %v.", len(trezors))
		os.Exit(exitcodes.TrezorError)
	}

	// Using the first found device
	trezor := trezors[0]

	// Trezor may ask for PIN or Passphrase. Setting the handler for this case.
	trezor.SetGetPinFunc(trezorGetPin)

	// In some cases (like lost connection to the Trezor device and cannot
	// reconnect) it's required to get a confirmation from the user to
	// retry to reconnect. Setting the handler for this case.
	trezor.SetGetConfirmFunc(trezorGetConfirm)

	// To reset the state of the device and check if it's initialized.
	// If device is not initialized then trezor.Reset() will return an
	// error.
	err := trezor.Reset()
	if err != nil {
		tlog.Fatal.Printf("Cannot reset the Trezor device. Error: %v", err.Error())
		os.Exit(exitcodes.TrezorError)
	}

	// To generate a deterministic key we trying to decrypt our
	// predefined constant key using the Trezor device. The resulting key
	// will depend on next variables:
	// * the Trezor master key;
	// * the passphrase (passed to the Trezor).
	//
	// The right key will be received only if both values (mentioned
	// above) are correct.
	//
	// Note:
	// Also the resulting key depends on this values (that we defined as
	// constants above):
	// * the key derivation path;
	// * the "encrypted" payload;
	// * the nonce;
	// * the key name.
	key, err := trezor.DecryptKey(trezorKeyDerivationPath, payload, []byte(trezorNonce), trezorKeyName)
	if err != nil {
		tlog.Fatal.Printf("Cannot get the key from the Trezor device. Error description:\n\t%v", err.Error())
		os.Exit(exitcodes.TrezorError)
	}

	// Sanity checks
	if len(key) != TrezorPayloadLen {
		log.Panicf("BUG: decrypted value has wrong length %d", len(key))
	}
	if bytes.Equal(key, payload) {
		log.Panicf("BUG: payload and decrypted value are identical")
	}
	zero := make([]byte, TrezorPayloadLen)
	if bytes.Equal(key, zero) {
		log.Panicf("BUG: decrypted value is all-zero")
	}

	// Everything ok
	return key
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"testing"
)

func TestConcurrency(t *testing.T) {
	for i := 0; i < 200; i++ {
		s := strconv.Itoa(i)
		fmt.Println("Setting", s)
		_, err := http.PostForm("http://localhost:3001/set/"+s, url.Values{"value": {s}})
		if err != nil {
			fmt.Println("Error setting ", s, ": ", err)
		}
	}
}
<commit_msg>bigger test<commit_after>package main

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"testing"
)

func TestConcurrency(t *testing.T) {
	for i := 0; i < 500; i++ {
		s := strconv.Itoa(i)
		fmt.Println("Setting", s)
		_, err := http.PostForm("http://localhost:3001/set/"+s, url.Values{"value": {s}})
		if err != nil {
			fmt.Println("Error setting ", s, ": ", err)
		}
	}
}
<|endoftext|>


<commit_before>/*
Package builtin implements some built-in functions for gosl (Go Language
Script Language, github.com/daviddengcn/gosl)

For use of convinience as a script language, the parameters are commonly
defined as an interface{}.
*/
package builtin

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"syscall"
)

/*
S converts anything into a string.
*/
func S(v interface{}) string {
	return fmt.Sprint(v)
}

/*
I converts anything into an int. When the value is malformed, if the optional
default value is specified, it is converted to int and returned; otherwise,
0 is returned.
*/
func I(v interface{}, def ...interface{}) int {
	if i, ok := v.(int); ok {
		return i
	}
	if i, ok := v.(int64); ok {
		return int(i)
	}

	i, err := strconv.Atoi(S(v))
	if err != nil && len(def) > 0 {
		return I(def[0])
	}
	return i
}

func execCode(err error) int {
	if exiterr, ok := err.(*exec.ExitError); ok {
		if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
			return status.ExitStatus()
		}
	}
	return 0
}

/*
Exec runs a command. exe is the path to the executable and args are arugment
passed to it.

If the command is executed successfuly without mistake, (nil, 0)
will be returned. Otherwise, the error and error code will be returned.

Stdout/stderr are directed the current stdout/stderr.
*/
func Exec(exe interface{}, args ...string) (error, int) {
	cmd := exec.Command(S(exe), args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err := cmd.Run()
	return err, execCode(err)
}

/*
ExecWithStdout is similar to Exec but the stdout is captured and returned as
the first return value.
*/
func ExecWithStdout(exe interface{}, args ...string) (stdout string, err error, errCode int) {
	var stdoutBuf bytes.Buffer

	cmd := exec.Command(S(exe), args...)
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err = cmd.Run()

	return string(stdoutBuf.Bytes()), err, execCode(err)
}

/*
ExecWithStdout is similar to Exec but the stdout/stderr are captured and
returned as the first/second return values.
*/
func ExecWithStdErrOut(exe interface{}, args ...string) (stdout, stderr string, err error, errCode int) {
	var stdoutBuf, stderrBuf bytes.Buffer

	cmd := exec.Command(S(exe), args...)
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = &stderrBuf
	cmd.Stdin = os.Stdin
	err = cmd.Run()

	return string(stdoutBuf.Bytes()), string(stderrBuf.Bytes()), err, execCode(err)
}

/*
Bash runs a command with bash. Return values are defined in Exec.
*/
func Bash(cmd interface{}) (error, int) {
	return Exec("bash", "-c", S(cmd))
}

/*
BashWithStdout is similar to Bash but with stdout captured and returned as a
string.
*/
func BashWithStdout(cmd interface{}) (string, error, int) {
	return ExecWithStdout("bash", "-c", S(cmd))
}
<commit_msg>Add Eval/BashEval/Pwd<commit_after>/*
Package builtin implements some built-in functions for gosl (Go Language
Script Language, github.com/daviddengcn/gosl)

For use of convinience as a script language, the parameters are commonly
defined as an interface{}.
*/
package builtin

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
)

/*
S converts anything into a string.
*/
func S(v interface{}) string {
	return fmt.Sprint(v)
}

/*
I converts anything into an int. When the value is malformed, if the optional
default value is specified, it is converted to int and returned; otherwise,
0 is returned.
*/
func I(v interface{}, def ...interface{}) int {
	if i, ok := v.(int); ok {
		return i
	}
	if i, ok := v.(int64); ok {
		return int(i)
	}

	i, err := strconv.Atoi(S(v))
	if err != nil && len(def) > 0 {
		return I(def[0])
	}
	return i
}

func execCode(err error) int {
	if exiterr, ok := err.(*exec.ExitError); ok {
		if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
			return status.ExitStatus()
		}
	}
	return 0
}

/*
Exec runs a command. exe is the path to the executable and args are arugment
passed to it.

If the command is executed successfuly without mistake, (nil, 0)
will be returned. Otherwise, the error and error code will be returned.

Stdout/stderr are directed the current stdout/stderr.
*/
func Exec(exe interface{}, args ...string) (error, int) {
	cmd := exec.Command(S(exe), args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err := cmd.Run()
	return err, execCode(err)
}

/*
ExecWithStdout is similar to Exec but the stdout is captured and returned as
the first return value.
*/
func ExecWithStdout(exe interface{}, args ...string) (stdout string, err error, errCode int) {
	var stdoutBuf bytes.Buffer

	cmd := exec.Command(S(exe), args...)
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	err = cmd.Run()

	return string(stdoutBuf.Bytes()), err, execCode(err)
}

/*
ExecWithStdout is similar to Exec but the stdout/stderr are captured and
returned as the first/second return values.
*/
func ExecWithStdErrOut(exe interface{}, args ...string) (stdout, stderr string, err error, errCode int) {
	var stdoutBuf, stderrBuf bytes.Buffer

	cmd := exec.Command(S(exe), args...)
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = &stderrBuf
	cmd.Stdin = os.Stdin
	err = cmd.Run()

	return string(stdoutBuf.Bytes()), string(stderrBuf.Bytes()), err, execCode(err)
}

/*
Eval is similar to ExecWithStdout but with stdout captured and returned as a
string. Trainling newlines are deleted.
*/
func Eval(exe interface{}, args ...string) string {
	out, _, _ := ExecWithStdout(exe, args...)
	return strings.TrimRight(out, "\r\n")
}

/*
Bash runs a command with bash. Return values are defined in Exec.
*/
func Bash(cmd interface{}) (error, int) {
	return Exec("bash", "-c", S(cmd))
}

/*
BashWithStdout is similar to Bash but with stdout captured and returned as a
string.
*/
func BashWithStdout(cmd interface{}) (string, error, int) {
	return ExecWithStdout("bash", "-c", S(cmd))
}

/*
BashEval is similar to BashWithStdout but with stdout captured and returned
as a string. Trainling newlines are deleted.
*/
func BashEval(cmd interface{}) string {
	out, _, _ := BashWithStdout(cmd)
	return strings.TrimRight(out, "\r\n")
}

/*
Similar to os.Getwd() but no error returned.
*/
func Pwd() string {
	pwd, _ := os.Getwd()
	return pwd
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"image"
	_ "image/png" // The _ means to import a package purely for its initialization side effects.
	"log"
	"net"
	"os"
	"runtime"
	"time"

	"github.com/udhos/fugo/future"
	"github.com/udhos/fugo/msg"
	"github.com/udhos/fugo/unit"
	"github.com/udhos/fugo/version"
)

type world struct {
	playerTab      []*player
	playerAdd      chan *player
	playerDel      chan *player
	input          chan inputMsg
	updateInterval time.Duration
	missileList    []*msg.Missile
	teams          [2]team
	cannonWidth    float64
	cannonHeight   float64
	missileWidth   float64
	missileHeight  float64
}

type team struct {
	count int // player count
	score int // team score
}

type inputMsg struct {
	player *player
	msg    interface{}
}

type player struct {
	conn         net.Conn
	output       chan msg.Update
	fuelStart    time.Time
	cannonStart  time.Time
	cannonSpeed  float32
	cannonCoordX float32
	cannonLife   float32
	cannonID     int
	team         int
}

func main() {

	log.Printf("arena version " + version.Version + " runtime " + runtime.Version())

	var addr string

	flag.StringVar(&addr, "addr", ":8080", "listen address")

	flag.Parse()

	w := world{
		playerTab:      []*player{},
		playerAdd:      make(chan *player),
		playerDel:      make(chan *player),
		updateInterval: 1000 * time.Millisecond,
		input:          make(chan inputMsg),
	}

	cannon := "assets/ship.png"
	var errCanSz error
	w.cannonWidth, w.cannonHeight, errCanSz = loadSize(cannon, unit.ScaleCannon)
	if errCanSz != nil {
		log.Printf("collision will NOT work: %v", errCanSz)
	}
	log.Printf("cannon: %s: %vx%v", cannon, w.cannonWidth, w.cannonHeight)

	missile := "assets/rocket.png"
	var errMisSz error
	w.missileWidth, w.missileHeight, errMisSz = loadSize(missile, unit.ScaleMissile)
	if errMisSz != nil {
		log.Printf("collision will NOT work: %v", errMisSz)
	}
	log.Printf("missile: %s: %vx%v", missile, w.missileWidth, w.missileHeight)

	if errListen := listenAndServe(&w, addr); errListen != nil {
		log.Printf("main: listen: %v", errListen)
		return
	}

	if errDisc := lanDiscovery(addr); errDisc != nil {
		log.Printf("main: discovery: %v", errDisc)
		return
	}

	missileID := 0
	cannonID := 0

	tickerUpdate := time.NewTicker(w.updateInterval)
	tickerCollision := time.NewTicker(100 * time.Millisecond)

	log.Printf("main: entering service loop")
SERVICE:
	for {
		select {
		case p := <-w.playerAdd:
			p.team = 0
			if w.teams[0].count > w.teams[1].count {
				p.team = 1
			}
			log.Printf("player add: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			w.playerTab = append(w.playerTab, p)

			playerFuelSet(p, time.Now(), 5) // reset fuel to 50%
			p.cannonStart = p.fuelStart
			p.cannonSpeed = float32(.15) // 15%
			p.cannonCoordX = .5          // 50%
			p.cannonID = cannonID
			p.cannonLife = 1 // 100%
			cannonID++
			w.teams[p.team].count++
		case p := <-w.playerDel:
			log.Printf("player del: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			for i, pl := range w.playerTab {
				if pl == p {
					//w.playerTab = append(w.playerTab[:i], w.playerTab[i+1:]...)
					if i < len(w.playerTab)-1 {
						w.playerTab[i] = w.playerTab[len(w.playerTab)-1]
					}
					w.playerTab = w.playerTab[:len(w.playerTab)-1]
					w.teams[p.team].count--
					log.Printf("player removed: %v", p)
					continue SERVICE
				}
			}
			log.Printf("player not found: %v", p)
		case i := <-w.input:
			//log.Printf("input: %v", i)

			switch m := i.msg.(type) {
			case msg.Button:
				log.Printf("input button: %v", m)

				if i.player.cannonLife <= 0 {
					continue // cannon destroyed
				}

				if m.ID == msg.ButtonTurn {
					p := i.player
					updateCannon(p, time.Now())
					p.cannonSpeed = -p.cannonSpeed
					updateWorld(&w, false)
					continue SERVICE
				}

				now := time.Now()
				fuel := playerFuel(i.player, now)

				if m.ID != msg.ButtonFire {
					continue SERVICE // non-fire button
				}

				if fuel < 1 {
					continue SERVICE // not enough fuel
				}

				playerFuelConsume(i.player, now, 1)

				updateCannon(i.player, now)
				miss1 := &msg.Missile{
					ID:     missileID,
					CoordX: i.player.cannonCoordX,
					Speed:  .5, // 50% every 1 second
					Team:   i.player.team,
					Start:  now,
				}
				missileID++
				w.missileList = append(w.missileList, miss1)

				log.Printf("input fire - fuel was=%v is=%v missiles=%d", fuel, playerFuel(i.player, now), len(w.missileList))

				updateWorld(&w, true)
			}

		case <-tickerUpdate.C:
			//log.Printf("tick: %v", t)

			updateWorld(&w, false)
		case <-tickerCollision.C:
			if detectCollision(&w, time.Now()) {
				updateWorld(&w, false)
			}
		}
	}
}

func loadSize(name string, scale float64) (float64, float64, error) {
	bogus := image.Rect(0, 0, 10, 10)
	w, h := unit.BoxSize(bogus, scale)

	f, errOpen := os.Open(name)
	if errOpen != nil {
		return w, h, fmt.Errorf("loadSize: open: %s: %v", name, errOpen)
	}
	defer f.Close()
	img, _, errDec := image.Decode(f)
	if errDec != nil {
		return w, h, fmt.Errorf("loadSize: decode: %s: %v", name, errDec)
	}
	i, ok := img.(*image.NRGBA)
	if !ok {
		return w, h, fmt.Errorf("loadSize: %s: not NRGBA", name)
	}

	w, h = unit.BoxSize(i, scale)
	b := i.Bounds()

	log.Printf("loadSize: %s: %vx%v => %vx%v", name, b.Max.X, b.Max.Y, w, h)

	return w, h, nil
}

func updateCannon(p *player, now time.Time) {
	p.cannonCoordX, p.cannonSpeed = future.CannonX(p.cannonCoordX, p.cannonSpeed, time.Since(p.cannonStart))
	p.cannonStart = now
}

func removeMissile(w *world, i int) {
	last := len(w.missileList) - 1
	if i < last {
		w.missileList[i] = w.missileList[last]
	}
	w.missileList = w.missileList[:last]
}

func updateWorld(w *world, fire bool) {
	now := time.Now()

	for _, p := range w.playerTab {
		updateCannon(p, now)
	}

	for i := 0; i < len(w.missileList); i++ {
		m := w.missileList[i]
		m.CoordY = future.MissileY(m.CoordY, m.Speed, time.Since(m.Start))
		m.Start = now
		if m.CoordY >= 1 {
			removeMissile(w, i)
			i--
		}
	}

	for _, p := range w.playerTab {
		sendUpdatesToPlayer(w, p, now, fire)
	}
}

func playerFuel(p *player, now time.Time) float32 {
	return future.Fuel(0, now.Sub(p.fuelStart))
}

func playerFuelSet(p *player, now time.Time, fuel float32) {
	p.fuelStart = now.Add(-time.Duration(float32(time.Second) * fuel / future.FuelRechargeRate))
}

func playerFuelConsume(p *player, now time.Time, amount float32) {
	fuel := playerFuel(p, now)
	playerFuelSet(p, now, fuel-amount)
}

func sendUpdatesToPlayer(w *world, p *player, now time.Time, fire bool) {
	update := msg.Update{
		Fuel:          playerFuel(p, now),
		Interval:      w.updateInterval,
		WorldMissiles: w.missileList,
		Team:          p.team,
		Scores:        [2]int{w.teams[0].score, w.teams[1].score},
		FireSound:     fire,
	}

	for _, p1 := range w.playerTab {
		cannon := msg.Cannon{
			ID:     p1.cannonID,
			Start:  p1.cannonStart,
			CoordX: p1.cannonCoordX,
			Speed:  p1.cannonSpeed,
			Team:   p1.team,
			Life:   p1.cannonLife,
			Player: p1 == p,
		}
		update.Cannons = append(update.Cannons, &cannon)
	}

	//log.Printf("sending updates to player %v", p)

	p.output <- update
}

func listenAndServe(w *world, addr string) error {

	proto := "tcp"

	log.Printf("serving on %s %s", proto, addr)

	listener, errListen := net.Listen(proto, addr)
	if errListen != nil {
		return fmt.Errorf("listenAndServe: %s: %v", addr, errListen)
	}

	gob.Register(msg.Update{})
	gob.Register(msg.Button{})

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Printf("accept on TCP %s: %s", addr, err)
				continue
			}
			c, _ := conn.(*net.TCPConn)
			go connHandler(w, c)
		}
	}()

	return nil
}

func connHandler(w *world, conn *net.TCPConn) {
	log.Printf("handler for connection %v", conn.RemoteAddr())

	defer conn.Close()

	p := &player{
		conn:   conn,
		output: make(chan msg.Update),
	}

	w.playerAdd <- p // register player
	quitWriter := make(chan struct{})

	go func() {
		// copy from socket into input channel
		dec := gob.NewDecoder(conn)
		for {
			var m msg.Button
			if err := dec.Decode(&m); err != nil {
				log.Printf("handler: Decode: %v", err)
				break
			}
			w.input <- inputMsg{player: p, msg: m}
		}
		close(quitWriter) // send quit request to output goroutine
		log.Printf("handler: reader goroutine exiting")
	}()

	// copy from output channel into socket
	enc := gob.NewEncoder(conn)
LOOP:
	for {
		select {
		case <-quitWriter:
			log.Printf("handler: quit request")
			break LOOP
		case m := <-p.output:
			if err := enc.Encode(&m); err != nil {
				log.Printf("handler: Encode: %v", err)
				break LOOP
			}
		}
	}
	w.playerDel <- p // deregister player
	log.Printf("handler: writer goroutine exiting")
}
<commit_msg>Count connections.<commit_after>package main

import (
	"encoding/gob"
	"flag"
	"fmt"
	"image"
	_ "image/png" // The _ means to import a package purely for its initialization side effects.
	"log"
	"net"
	"os"
	"runtime"
	"sync/atomic"
	"time"

	"github.com/udhos/fugo/future"
	"github.com/udhos/fugo/msg"
	"github.com/udhos/fugo/unit"
	"github.com/udhos/fugo/version"
)

type world struct {
	playerTab      []*player
	playerAdd      chan *player
	playerDel      chan *player
	input          chan inputMsg
	updateInterval time.Duration
	missileList    []*msg.Missile
	teams          [2]team
	cannonWidth    float64
	cannonHeight   float64
	missileWidth   float64
	missileHeight  float64
	countConn      int32
}

type team struct {
	count int // player count
	score int // team score
}

type inputMsg struct {
	player *player
	msg    interface{}
}

type player struct {
	conn         net.Conn
	output       chan msg.Update
	fuelStart    time.Time
	cannonStart  time.Time
	cannonSpeed  float32
	cannonCoordX float32
	cannonLife   float32
	cannonID     int
	team         int
}

func main() {

	log.Printf("arena version " + version.Version + " runtime " + runtime.Version())

	var addr string

	flag.StringVar(&addr, "addr", ":8080", "listen address")

	flag.Parse()

	w := world{
		playerTab:      []*player{},
		playerAdd:      make(chan *player),
		playerDel:      make(chan *player),
		updateInterval: 1000 * time.Millisecond,
		input:          make(chan inputMsg),
	}

	cannon := "assets/ship.png"
	var errCanSz error
	w.cannonWidth, w.cannonHeight, errCanSz = loadSize(cannon, unit.ScaleCannon)
	if errCanSz != nil {
		log.Printf("collision will NOT work: %v", errCanSz)
	}
	log.Printf("cannon: %s: %vx%v", cannon, w.cannonWidth, w.cannonHeight)

	missile := "assets/rocket.png"
	var errMisSz error
	w.missileWidth, w.missileHeight, errMisSz = loadSize(missile, unit.ScaleMissile)
	if errMisSz != nil {
		log.Printf("collision will NOT work: %v", errMisSz)
	}
	log.Printf("missile: %s: %vx%v", missile, w.missileWidth, w.missileHeight)

	if errListen := listenAndServe(&w, addr); errListen != nil {
		log.Printf("main: listen: %v", errListen)
		return
	}

	if errDisc := lanDiscovery(addr); errDisc != nil {
		log.Printf("main: discovery: %v", errDisc)
		return
	}

	missileID := 0
	cannonID := 0

	tickerUpdate := time.NewTicker(w.updateInterval)
	tickerCollision := time.NewTicker(100 * time.Millisecond)

	log.Printf("main: entering service loop")
SERVICE:
	for {
		select {
		case p := <-w.playerAdd:
			p.team = 0
			if w.teams[0].count > w.teams[1].count {
				p.team = 1
			}
			log.Printf("player add: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			w.playerTab = append(w.playerTab, p)

			playerFuelSet(p, time.Now(), 5) // reset fuel to 50%
			p.cannonStart = p.fuelStart
			p.cannonSpeed = float32(.15) // 15%
			p.cannonCoordX = .5          // 50%
			p.cannonID = cannonID
			p.cannonLife = 1 // 100%
			cannonID++
			w.teams[p.team].count++
		case p := <-w.playerDel:
			log.Printf("player del: %v team=%d team0=%d team1=%d", p, p.team, w.teams[0].count, w.teams[1].count)
			for i, pl := range w.playerTab {
				if pl == p {
					//w.playerTab = append(w.playerTab[:i], w.playerTab[i+1:]...)
					if i < len(w.playerTab)-1 {
						w.playerTab[i] = w.playerTab[len(w.playerTab)-1]
					}
					w.playerTab = w.playerTab[:len(w.playerTab)-1]
					w.teams[p.team].count--
					log.Printf("player removed: %v", p)
					continue SERVICE
				}
			}
			log.Printf("player not found: %v", p)
		case i := <-w.input:
			//log.Printf("input: %v", i)

			switch m := i.msg.(type) {
			case msg.Button:
				log.Printf("input button: %v", m)

				if i.player.cannonLife <= 0 {
					continue // cannon destroyed
				}

				if m.ID == msg.ButtonTurn {
					p := i.player
					updateCannon(p, time.Now())
					p.cannonSpeed = -p.cannonSpeed
					updateWorld(&w, false)
					continue SERVICE
				}

				now := time.Now()
				fuel := playerFuel(i.player, now)

				if m.ID != msg.ButtonFire {
					continue SERVICE // non-fire button
				}

				if fuel < 1 {
					continue SERVICE // not enough fuel
				}

				playerFuelConsume(i.player, now, 1)

				updateCannon(i.player, now)
				miss1 := &msg.Missile{
					ID:     missileID,
					CoordX: i.player.cannonCoordX,
					Speed:  .5, // 50% every 1 second
					Team:   i.player.team,
					Start:  now,
				}
				missileID++
				w.missileList = append(w.missileList, miss1)

				log.Printf("input fire - fuel was=%v is=%v missiles=%d", fuel, playerFuel(i.player, now), len(w.missileList))

				updateWorld(&w, true)
			}

		case <-tickerUpdate.C:
			//log.Printf("tick: %v", t)

			updateWorld(&w, false)
		case <-tickerCollision.C:
			if detectCollision(&w, time.Now()) {
				updateWorld(&w, false)
			}
		}
	}
}

func loadSize(name string, scale float64) (float64, float64, error) {
	bogus := image.Rect(0, 0, 10, 10)
	w, h := unit.BoxSize(bogus, scale)

	f, errOpen := os.Open(name)
	if errOpen != nil {
		return w, h, fmt.Errorf("loadSize: open: %s: %v", name, errOpen)
	}
	defer f.Close()
	img, _, errDec := image.Decode(f)
	if errDec != nil {
		return w, h, fmt.Errorf("loadSize: decode: %s: %v", name, errDec)
	}
	i, ok := img.(*image.NRGBA)
	if !ok {
		return w, h, fmt.Errorf("loadSize: %s: not NRGBA", name)
	}

	w, h = unit.BoxSize(i, scale)
	b := i.Bounds()

	log.Printf("loadSize: %s: %vx%v => %vx%v", name, b.Max.X, b.Max.Y, w, h)

	return w, h, nil
}

func updateCannon(p *player, now time.Time) {
	p.cannonCoordX, p.cannonSpeed = future.CannonX(p.cannonCoordX, p.cannonSpeed, time.Since(p.cannonStart))
	p.cannonStart = now
}

func removeMissile(w *world, i int) {
	last := len(w.missileList) - 1
	if i < last {
		w.missileList[i] = w.missileList[last]
	}
	w.missileList = w.missileList[:last]
}

func updateWorld(w *world, fire bool) {
	now := time.Now()

	for _, p := range w.playerTab {
		updateCannon(p, now)
	}

	for i := 0; i < len(w.missileList); i++ {
		m := w.missileList[i]
		m.CoordY = future.MissileY(m.CoordY, m.Speed, time.Since(m.Start))
		m.Start = now
		if m.CoordY >= 1 {
			removeMissile(w, i)
			i--
		}
	}

	for _, p := range w.playerTab {
		sendUpdatesToPlayer(w, p, now, fire)
	}
}

func playerFuel(p *player, now time.Time) float32 {
	return future.Fuel(0, now.Sub(p.fuelStart))
}

func playerFuelSet(p *player, now time.Time, fuel float32) {
	p.fuelStart = now.Add(-time.Duration(float32(time.Second) * fuel / future.FuelRechargeRate))
}

func playerFuelConsume(p *player, now time.Time, amount float32) {
	fuel := playerFuel(p, now)
	playerFuelSet(p, now, fuel-amount)
}

func sendUpdatesToPlayer(w *world, p *player, now time.Time, fire bool) {
	update := msg.Update{
		Fuel:          playerFuel(p, now),
		Interval:      w.updateInterval,
		WorldMissiles: w.missileList,
		Team:          p.team,
		Scores:        [2]int{w.teams[0].score, w.teams[1].score},
		FireSound:     fire,
	}

	for _, p1 := range w.playerTab {
		cannon := msg.Cannon{
			ID:     p1.cannonID,
			Start:  p1.cannonStart,
			CoordX: p1.cannonCoordX,
			Speed:  p1.cannonSpeed,
			Team:   p1.team,
			Life:   p1.cannonLife,
			Player: p1 == p,
		}
		update.Cannons = append(update.Cannons, &cannon)
	}

	//log.Printf("sending updates to player %v", p)

	p.output <- update
}

func listenAndServe(w *world, addr string) error {

	proto := "tcp"

	log.Printf("serving on %s %s", proto, addr)

	listener, errListen := net.Listen(proto, addr)
	if errListen != nil {
		return fmt.Errorf("listenAndServe: %s: %v", addr, errListen)
	}

	gob.Register(msg.Update{})
	gob.Register(msg.Button{})

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Printf("count=%d accept on TCP %s: %s", atomic.LoadInt32(&w.countConn), addr, err)
				conn.Close()
				continue
			}
			c, _ := conn.(*net.TCPConn)
			go connHandler(w, c)
		}
	}()

	return nil
}

func connHandler(w *world, conn *net.TCPConn) {
	count := atomic.AddInt32(&w.countConn, 1)
	log.Printf("count=%d connHandler %v", count, conn.RemoteAddr())

	defer func() {
		c := atomic.AddInt32(&w.countConn, -1)
		log.Printf("count=%d connHandler exiting: %v", c, conn.RemoteAddr())
		conn.Close()
	}()

	p := &player{
		conn:   conn,
		output: make(chan msg.Update),
	}

	w.playerAdd <- p // register player
	quitWriter := make(chan struct{})

	go func() {
		// copy from socket into input channel
		dec := gob.NewDecoder(conn)
		for {
			var m msg.Button
			if err := dec.Decode(&m); err != nil {
				log.Printf("handler: Decode: %v", err)
				break
			}
			w.input <- inputMsg{player: p, msg: m}
		}
		close(quitWriter) // send quit request to output goroutine
		log.Printf("handler: reader goroutine exiting")
	}()

	// copy from output channel into socket
	enc := gob.NewEncoder(conn)
LOOP:
	for {
		select {
		case <-quitWriter:
			log.Printf("handler: quit request")
			break LOOP
		case m := <-p.output:
			if err := enc.Encode(&m); err != nil {
				log.Printf("handler: Encode: %v", err)
				break LOOP
			}
		}
	}
	w.playerDel <- p // deregister player
	log.Printf("handler: writer goroutine exiting")
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"code.google.com/p/ebml-go/webm"
	"code.google.com/p/ffvp8-go/ffvp8"
	"flag"
	gl "github.com/chsc/gogl/gl21"
	"github.com/jteeuwen/glfw"
	"image"
	"io"
	"log"
	"os"
)

var in = flag.String("i", "", "Input file")
var nf = flag.Int("n", 0x7fffffff, "Number of frames")

const vss = `
void main() {
  gl_TexCoord[0] = gl_MultiTexCoord0;
  gl_Position = ftransform();
}
`

const fss = `
uniform sampler2D ytex;
uniform sampler2D cbtex;
uniform sampler2D crtex;

const mat3 ycbcr2rgb = mat3(
                          1.164, 0, 1.596,
                          1.164, -0.392, -0.813,
                          1.164, 2.017, 0.0
                          );
const float ysub = 0.0625;
void main() {
   float y = texture2D(ytex, gl_TexCoord[0].st).r;
   float cb = texture2D(cbtex, gl_TexCoord[0].st).r;
   float cr = texture2D(crtex, gl_TexCoord[0].st).r;
   vec3 ycbcr = vec3(y - ysub, cb - 0.5, cr - 0.5);
   vec3 rgb = ycbcr * ycbcr2rgb;
   gl_FragColor = vec4(rgb,1.0);
}
`

func decode(ch chan []byte, wch chan *image.YCbCr) {
	dec := ffvp8.NewDecoder()
	for data := <-ch; data != nil; data = <-ch {
		wch <- dec.Decode(data)
	}
	wch <- nil
}

func setupvp(w, h int) {
	gl.Viewport(0, 0, gl.Sizei(w), gl.Sizei(h))
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Ortho(0, 1, 1, 0, -1, 1)
	gl.MatrixMode(gl.MODELVIEW)
	gl.LoadIdentity()
}

func texinit() (yid gl.Uint) {
	gl.GenTextures(1, &yid)
	gl.BindTexture(gl.TEXTURE_2D, yid)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	return
}

func shinit(yid, cbid, crid gl.Uint) gl.Uint {
	vs := loadShader(gl.VERTEX_SHADER, vss)
	fs := loadShader(gl.FRAGMENT_SHADER, fss)
	prg := gl.CreateProgram()
	gl.AttachShader(prg, vs)
	gl.AttachShader(prg, fs)
	gl.LinkProgram(prg)
	gl.UseProgram(prg)
	gl.Uniform1i(0, 0)
	gl.Uniform1i(1, 1)
	gl.Uniform1i(2, 2)
	return prg
}

func upload(id gl.Uint, data []byte, stride int, w int, h int) {
	gl.BindTexture(gl.TEXTURE_2D, id)
	gl.PixelStorei(gl.UNPACK_ROW_LENGTH, gl.Int(stride))
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, gl.Sizei(w), gl.Sizei(h), 0,
		gl.LUMINANCE, gl.UNSIGNED_BYTE, gl.Pointer(&data[0]))
}

func initquad() {
	ver := []gl.Float{0, 0, 1, 0, 0, 1, 1, 1}
	gl.BindBuffer(gl.ARRAY_BUFFER, 1)
	gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(4*len(ver)),
		gl.Pointer(&ver[0]), gl.STATIC_DRAW)
	gl.VertexPointer(2, gl.FLOAT, 0, nil)
	gl.BindBuffer(gl.ARRAY_BUFFER, 2)
	gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(4*len(ver)),
		gl.Pointer(&ver[0]), gl.STATIC_DRAW)
	gl.TexCoordPointer(2, gl.FLOAT, 0, nil)
	gl.EnableClientState(gl.VERTEX_ARRAY)
	gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
}

func loadShader(shtype gl.Enum, src string) gl.Uint {
	sh := gl.CreateShader(shtype)
	gsrc := gl.GLString(src)
	gl.ShaderSource(sh, 1, &gsrc, nil)
	gl.CompileShader(sh)
	return sh
}

func write(ch chan *image.YCbCr, ech chan int) {
	img := <-ch
	w := img.Rect.Dx()
	h := img.Rect.Dy()
	glfw.Init()
	defer glfw.Terminate()
	glfw.OpenWindow(w, h, 0, 0, 0, 0, 0, 0, glfw.Windowed)
	defer glfw.CloseWindow()
	glfw.SetSwapInterval(1)
	glfw.SetWindowTitle("webmplay")
	gl.Init()
	setupvp(w, h)
	yid := texinit()
	cbid := texinit()
	crid := texinit()
	shinit(yid, cbid, crid)
	initquad()
	gl.Enable(gl.TEXTURE_2D)
	for i := 0; img != nil; i, img = i+1, <-ch {
		gl.ActiveTexture(gl.TEXTURE0)
		upload(yid, img.Y, img.YStride, w, h)
		gl.ActiveTexture(gl.TEXTURE1)
		upload(cbid, img.Cb, img.CStride, w/2, h/2)
		gl.ActiveTexture(gl.TEXTURE2)
		upload(crid, img.Cr, img.CStride, w/2, h/2)
		gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
		gl.Flush()
		glfw.SwapBuffers()
		glfw.Sleep(0.001)
	}
	ech <- 1
}

func read(dchan chan []byte) {
	var err error
	var wm webm.WebM
	r, err := os.Open(*in)
	defer r.Close()
	if err != nil {
		log.Panic("unable to open file " + *in)
	}
	br := bufio.NewReader(r)
	e, rest, err := webm.Parse(br, &wm)
	track := wm.FindFirstVideoTrack()
	for i := 0; err == nil && i < *nf; {
		t := make([]byte, 4)
		io.ReadFull(e.R, t)
		if uint(t[0])&0x7f == track.TrackNumber {
			data := make([]byte, e.Size())
			io.ReadFull(e.R, data)
			dchan <- data
			i++
		}
		_, err = e.ReadData()
		e, err = rest.Next()
	}
	dchan <- nil
}

func main() {
	flag.Parse()
	dchan := make(chan []byte, 4)
	wchan := make(chan *image.YCbCr, 4)
	echan := make(chan int, 1)
	go read(dchan)
	go decode(dchan, wchan)
	go write(wchan, echan)
	<-echan
}
<commit_msg>Simplified, fixed glfw issues by moving glfw stuff to the main goroutine<commit_after>package main

import (
	"bufio"
	"code.google.com/p/ebml-go/webm"
	"code.google.com/p/ffvp8-go/ffvp8"
	"flag"
	gl "github.com/chsc/gogl/gl21"
	"github.com/jteeuwen/glfw"
	"image"
	"io"
	"log"
	"os"
)

var in = flag.String("i", "", "Input file")
var nf = flag.Int("n", 0x7fffffff, "Number of frames")

const vss = `
void main() {
  gl_TexCoord[0] = gl_MultiTexCoord0;
  gl_Position = ftransform();
}
`

const fss = `
uniform sampler2D ytex;
uniform sampler2D cbtex;
uniform sampler2D crtex;

const mat3 ycbcr2rgb = mat3(
                          1.164, 0, 1.596,
                          1.164, -0.392, -0.813,
                          1.164, 2.017, 0.0
                          );
const float ysub = 0.0625;
void main() {
   float y = texture2D(ytex, gl_TexCoord[0].st).r;
   float cb = texture2D(cbtex, gl_TexCoord[0].st).r;
   float cr = texture2D(crtex, gl_TexCoord[0].st).r;
   vec3 ycbcr = vec3(y - ysub, cb - 0.5, cr - 0.5);
   vec3 rgb = ycbcr * ycbcr2rgb;
   gl_FragColor = vec4(rgb,1.0);
}
`

func decode(ch chan []byte, wch chan *image.YCbCr) {
	dec := ffvp8.NewDecoder()
	for data := <-ch; data != nil; data = <-ch {
		wch <- dec.Decode(data)
	}
	wch <- nil
}

func setupvp(w, h int) {
	gl.Viewport(0, 0, gl.Sizei(w), gl.Sizei(h))
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Ortho(0, 1, 1, 0, -1, 1)
	gl.MatrixMode(gl.MODELVIEW)
	gl.LoadIdentity()
}

func texinit() (yid gl.Uint) {
	gl.GenTextures(1, &yid)
	gl.BindTexture(gl.TEXTURE_2D, yid)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	return
}

func shinit(yid, cbid, crid gl.Uint) gl.Uint {
	vs := loadShader(gl.VERTEX_SHADER, vss)
	fs := loadShader(gl.FRAGMENT_SHADER, fss)
	prg := gl.CreateProgram()
	gl.AttachShader(prg, vs)
	gl.AttachShader(prg, fs)
	gl.LinkProgram(prg)
	gl.UseProgram(prg)
	gl.Uniform1i(0, 0)
	gl.Uniform1i(1, 1)
	gl.Uniform1i(2, 2)
	return prg
}

func upload(id gl.Uint, data []byte, stride int, w int, h int) {
	gl.BindTexture(gl.TEXTURE_2D, id)
	gl.PixelStorei(gl.UNPACK_ROW_LENGTH, gl.Int(stride))
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, gl.Sizei(w), gl.Sizei(h), 0,
		gl.LUMINANCE, gl.UNSIGNED_BYTE, gl.Pointer(&data[0]))
}

func initquad() {
	ver := []gl.Float{0, 0, 1, 0, 0, 1, 1, 1}
	gl.BindBuffer(gl.ARRAY_BUFFER, 1)
	gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(4*len(ver)),
		gl.Pointer(&ver[0]), gl.STATIC_DRAW)
	gl.VertexPointer(2, gl.FLOAT, 0, nil)
	gl.BindBuffer(gl.ARRAY_BUFFER, 2)
	gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(4*len(ver)),
		gl.Pointer(&ver[0]), gl.STATIC_DRAW)
	gl.TexCoordPointer(2, gl.FLOAT, 0, nil)
	gl.EnableClientState(gl.VERTEX_ARRAY)
	gl.EnableClientState(gl.TEXTURE_COORD_ARRAY)
}

func loadShader(shtype gl.Enum, src string) gl.Uint {
	sh := gl.CreateShader(shtype)
	gsrc := gl.GLString(src)
	gl.ShaderSource(sh, 1, &gsrc, nil)
	gl.CompileShader(sh)
	return sh
}

func write(ch chan *image.YCbCr) {
	img := <-ch
	w := img.Rect.Dx()
	h := img.Rect.Dy()
	glfw.Init()
	defer glfw.Terminate()
	glfw.OpenWindow(w, h, 0, 0, 0, 0, 0, 0, glfw.Windowed)
	defer glfw.CloseWindow()
	glfw.SetSwapInterval(1)
	glfw.SetWindowTitle("webmplay")
	gl.Init()
	setupvp(w, h)
	yid := texinit()
	cbid := texinit()
	crid := texinit()
	shinit(yid, cbid, crid)
	initquad()
	gl.Enable(gl.TEXTURE_2D)
	for i := 0; img != nil; i, img = i+1, <-ch {
		gl.ActiveTexture(gl.TEXTURE0)
		upload(yid, img.Y, img.YStride, w, h)
		gl.ActiveTexture(gl.TEXTURE1)
		upload(cbid, img.Cb, img.CStride, w/2, h/2)
		gl.ActiveTexture(gl.TEXTURE2)
		upload(crid, img.Cr, img.CStride, w/2, h/2)
		gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
		gl.Flush()
		glfw.SwapBuffers()
		glfw.Sleep(0.001)
	}
}

func read(dchan chan []byte) {
	var err error
	var wm webm.WebM
	r, err := os.Open(*in)
	defer r.Close()
	if err != nil {
		log.Panic("unable to open file " + *in)
	}
	br := bufio.NewReader(r)
	e, rest, err := webm.Parse(br, &wm)
	track := wm.FindFirstVideoTrack()
	for i := 0; err == nil && i < *nf; {
		t := make([]byte, 4)
		io.ReadFull(e.R, t)
		if uint(t[0])&0x7f == track.TrackNumber {
			data := make([]byte, e.Size())
			io.ReadFull(e.R, data)
			dchan <- data
			i++
		}
		_, err = e.ReadData()
		e, err = rest.Next()
	}
	dchan <- nil
}

func main() {
	flag.Parse()
	dchan := make(chan []byte, 4)
	wchan := make(chan *image.YCbCr, 4)
	go read(dchan)
	go decode(dchan, wchan)
	write(wchan)
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package execution

import (
	"strconv"
	"time"

	"fmt"

	"os"

	"strings"

	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/execution/event"
	"github.com/getgauge/gauge/execution/rerun"
	"github.com/getgauge/gauge/execution/result"
	"github.com/getgauge/gauge/gauge"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/manifest"
	"github.com/getgauge/gauge/plugin"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/reporter"
	"github.com/getgauge/gauge/runner"
	"github.com/getgauge/gauge/validation"
)

var NumberOfExecutionStreams int
var InParallel bool

type execution interface {
	run() *result.SuiteResult
}

type executionInfo struct {
	manifest        *manifest.Manifest
	specs           *gauge.SpecCollection
	runner          runner.Runner
	pluginHandler   *plugin.Handler
	errMaps         *validation.ValidationErrMaps
	inParallel      bool
	numberOfStreams int
	stream          int
}

func newExecutionInfo(s *gauge.SpecCollection, r runner.Runner, ph *plugin.Handler, e *validation.ValidationErrMaps, p bool, stream int) *executionInfo {
	m, err := manifest.ProjectManifest()
	if err != nil {
		logger.Fatalf(err.Error())
	}
	return &executionInfo{
		manifest:        m,
		specs:           s,
		runner:          r,
		pluginHandler:   ph,
		errMaps:         e,
		inParallel:      p,
		numberOfStreams: NumberOfExecutionStreams,
		stream:          stream,
	}
}

func ExecuteSpecs(specDirs []string) int {
	err := validateFlags()
	if err != nil {
		logger.Fatalf(err.Error())
	}
	if config.CheckUpdates() {
		i := &install.UpdateFacade{}
		i.BufferUpdateDetails()
		defer i.PrintUpdateBuffer()
	}

	res := validation.ValidateSpecs(specDirs, false)
	if len(res.Errs) > 0 {
		os.Exit(1)
	}
	if res.SpecCollection.Size() < 1 {
		logger.Info("No specifications found in %s.", strings.Join(specDirs, ", "))
		res.Runner.Kill()
		os.Exit(0)
	}
	event.InitRegistry()
	reporter.ListenExecutionEvents()
	rerun.ListenFailedScenarios()
	ei := newExecutionInfo(res.SpecCollection, res.Runner, nil, res.ErrMap, InParallel, 0)
	e := newExecution(ei)
	return printExecutionStatus(e.run(), res.ErrMap)
}

func Execute(s *gauge.SpecCollection, r runner.Runner, ph *plugin.Handler, e *validation.ValidationErrMaps, p bool, n int) {
	newExecution(newExecutionInfo(s, r, ph, e, p, n)).run()
}

func newExecution(executionInfo *executionInfo) execution {
	if executionInfo.inParallel {
		return newParallelExecution(executionInfo)
	}
	return newSimpleExecution(executionInfo)
}

func printExecutionStatus(suiteResult *result.SuiteResult, errMap *validation.ValidationErrMaps) int {
	nSkippedScenarios := len(errMap.ScenarioErrs)
	nSkippedSpecs := suiteResult.SpecsSkippedCount
	var nExecutedSpecs int
	if len(suiteResult.SpecResults) != 0 {
		nExecutedSpecs = len(suiteResult.SpecResults) - nSkippedSpecs
	}
	nFailedSpecs := suiteResult.SpecsFailedCount
	nPassedSpecs := nExecutedSpecs - nFailedSpecs

	nExecutedScenarios := 0
	nFailedScenarios := 0
	nPassedScenarios := 0
	for _, specResult := range suiteResult.SpecResults {
		nExecutedScenarios += specResult.ScenarioCount
		nFailedScenarios += specResult.ScenarioFailedCount
	}
	nExecutedScenarios -= nSkippedScenarios
	nPassedScenarios = nExecutedScenarios - nFailedScenarios

	if nExecutedScenarios < 0 {
		nExecutedScenarios = 0
	}

	if nPassedScenarios < 0 {
		nPassedScenarios = 0
	}

	logger.Info("Specifications:\t%d executed\t%d passed\t%d failed\t%d skipped", nExecutedSpecs, nPassedSpecs, nFailedSpecs, nSkippedSpecs)
	logger.Info("Scenarios:\t%d executed\t%d passed\t%d failed\t%d skipped", nExecutedScenarios, nPassedScenarios, nFailedScenarios, nSkippedScenarios)
	logger.Info("\nTotal time taken: %s", time.Millisecond*time.Duration(suiteResult.ExecutionTime))

	if suiteResult.IsFailed || (nSkippedSpecs+nSkippedScenarios) > 0 {
		return 1
	}
	return 0
}

func validateFlags() error {
	if !InParallel {
		return nil
	}
	if NumberOfExecutionStreams < 1 {
		return fmt.Errorf("Invalid input(%s) to --n flag.", strconv.Itoa(NumberOfExecutionStreams))
	}
	if !isValidStrategy(Strategy) {
		return fmt.Errorf("Invalid input(%s) to --strategy flag.", Strategy)
	}
	return nil
}
<commit_msg>Gauge exit status is 0 in case of sce/specs skipped #523<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package execution

import (
	"strconv"
	"time"

	"fmt"

	"os"

	"strings"

	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/execution/event"
	"github.com/getgauge/gauge/execution/rerun"
	"github.com/getgauge/gauge/execution/result"
	"github.com/getgauge/gauge/gauge"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/manifest"
	"github.com/getgauge/gauge/plugin"
	"github.com/getgauge/gauge/plugin/install"
	"github.com/getgauge/gauge/reporter"
	"github.com/getgauge/gauge/runner"
	"github.com/getgauge/gauge/validation"
)

var NumberOfExecutionStreams int
var InParallel bool

type execution interface {
	run() *result.SuiteResult
}

type executionInfo struct {
	manifest        *manifest.Manifest
	specs           *gauge.SpecCollection
	runner          runner.Runner
	pluginHandler   *plugin.Handler
	errMaps         *validation.ValidationErrMaps
	inParallel      bool
	numberOfStreams int
	stream          int
}

func newExecutionInfo(s *gauge.SpecCollection, r runner.Runner, ph *plugin.Handler, e *validation.ValidationErrMaps, p bool, stream int) *executionInfo {
	m, err := manifest.ProjectManifest()
	if err != nil {
		logger.Fatalf(err.Error())
	}
	return &executionInfo{
		manifest:        m,
		specs:           s,
		runner:          r,
		pluginHandler:   ph,
		errMaps:         e,
		inParallel:      p,
		numberOfStreams: NumberOfExecutionStreams,
		stream:          stream,
	}
}

func ExecuteSpecs(specDirs []string) int {
	err := validateFlags()
	if err != nil {
		logger.Fatalf(err.Error())
	}
	if config.CheckUpdates() {
		i := &install.UpdateFacade{}
		i.BufferUpdateDetails()
		defer i.PrintUpdateBuffer()
	}

	res := validation.ValidateSpecs(specDirs, false)
	if len(res.Errs) > 0 {
		os.Exit(1)
	}
	if res.SpecCollection.Size() < 1 {
		logger.Info("No specifications found in %s.", strings.Join(specDirs, ", "))
		res.Runner.Kill()
		os.Exit(0)
	}
	event.InitRegistry()
	reporter.ListenExecutionEvents()
	rerun.ListenFailedScenarios()
	ei := newExecutionInfo(res.SpecCollection, res.Runner, nil, res.ErrMap, InParallel, 0)
	e := newExecution(ei)
	return printExecutionStatus(e.run(), res.ErrMap)
}

func Execute(s *gauge.SpecCollection, r runner.Runner, ph *plugin.Handler, e *validation.ValidationErrMaps, p bool, n int) {
	newExecution(newExecutionInfo(s, r, ph, e, p, n)).run()
}

func newExecution(executionInfo *executionInfo) execution {
	if executionInfo.inParallel {
		return newParallelExecution(executionInfo)
	}
	return newSimpleExecution(executionInfo)
}

func printExecutionStatus(suiteResult *result.SuiteResult, errMap *validation.ValidationErrMaps) int {
	nSkippedScenarios := len(errMap.ScenarioErrs)
	nSkippedSpecs := suiteResult.SpecsSkippedCount
	var nExecutedSpecs int
	if len(suiteResult.SpecResults) != 0 {
		nExecutedSpecs = len(suiteResult.SpecResults) - nSkippedSpecs
	}
	nFailedSpecs := suiteResult.SpecsFailedCount
	nPassedSpecs := nExecutedSpecs - nFailedSpecs

	nExecutedScenarios := 0
	nFailedScenarios := 0
	nPassedScenarios := 0
	for _, specResult := range suiteResult.SpecResults {
		nExecutedScenarios += specResult.ScenarioCount
		nFailedScenarios += specResult.ScenarioFailedCount
	}
	nExecutedScenarios -= nSkippedScenarios
	nPassedScenarios = nExecutedScenarios - nFailedScenarios

	if nExecutedScenarios < 0 {
		nExecutedScenarios = 0
	}

	if nPassedScenarios < 0 {
		nPassedScenarios = 0
	}

	logger.Info("Specifications:\t%d executed\t%d passed\t%d failed\t%d skipped", nExecutedSpecs, nPassedSpecs, nFailedSpecs, nSkippedSpecs)
	logger.Info("Scenarios:\t%d executed\t%d passed\t%d failed\t%d skipped", nExecutedScenarios, nPassedScenarios, nFailedScenarios, nSkippedScenarios)
	logger.Info("\nTotal time taken: %s", time.Millisecond*time.Duration(suiteResult.ExecutionTime))

	if suiteResult.IsFailed {
		return 1
	}
	return 0
}

func validateFlags() error {
	if !InParallel {
		return nil
	}
	if NumberOfExecutionStreams < 1 {
		return fmt.Errorf("Invalid input(%s) to --n flag.", strconv.Itoa(NumberOfExecutionStreams))
	}
	if !isValidStrategy(Strategy) {
		return fmt.Errorf("Invalid input(%s) to --strategy flag.", Strategy)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Gravitational, Inc.

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 services

import (
	"encoding/json"
	"fmt"
	"net/url"
	"sync"
	"time"

	"github.com/gokyle/hotp"

	"github.com/gravitational/log"
	"github.com/gravitational/trace"
	"golang.org/x/crypto/bcrypt"

	"github.com/gravitational/teleport"
	"github.com/gravitational/teleport/lib/backend"
)

type WebService struct {
	backend     backend.Backend
	SignupMutex *sync.Mutex
}

func NewWebService(backend backend.Backend) *WebService {
	return &WebService{
		backend:     backend,
		SignupMutex: &sync.Mutex{},
	}
}

// UpsertPasswordHash upserts user password hash
func (s *WebService) UpsertPasswordHash(user string, hash []byte) error {
	err := s.backend.UpsertVal([]string{"web", "users", user},
		"pwd", hash, 0)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}
	return err
}

// GetPasswordHash returns the password hash for a given user
func (s *WebService) GetPasswordHash(user string) ([]byte, error) {
	hash, err := s.backend.GetVal([]string{"web", "users", user}, "pwd")
	if err != nil {
		return nil, err
	}
	return hash, err
}

func (s *WebService) UpsertHOTP(user string, otp *hotp.HOTP) error {
	bytes, err := hotp.Marshal(otp)
	if err != nil {
		return trace.Wrap(err)
	}
	err = s.backend.UpsertVal([]string{"web", "users", user},
		"hotp", bytes, 0)
	if err != nil {
		return trace.Wrap(err)
	}
	return nil
}

func (s *WebService) GetHOTP(user string) (*hotp.HOTP, error) {
	bytes, err := s.backend.GetVal([]string{"web", "users", user},
		"hotp")
	if err != nil {
		return nil, trace.Wrap(err)
	}
	otp, err := hotp.Unmarshal(bytes)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	return otp, nil
}

// UpsertSession
func (s *WebService) UpsertWebSession(user, sid string,
	session WebSession, ttl time.Duration) error {

	bytes, err := json.Marshal(session)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}

	err = s.backend.UpsertVal([]string{"web", "users", user, "sessions"},
		sid, bytes, ttl)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}
	return err

}

// GetWebSession
func (s *WebService) GetWebSession(user, sid string) (*WebSession, error) {
	val, err := s.backend.GetVal(
		[]string{"web", "users", user, "sessions"},
		sid,
	)
	if err != nil {
		return nil, err
	}

	var session WebSession
	err = json.Unmarshal(val, &session)
	if err != nil {
		log.Errorf(err.Error())
		return nil, trace.Wrap(err)
	}

	return &session, nil
}

// GetWebSessionsKeys
func (s *WebService) GetWebSessionsKeys(user string) ([]AuthorizedKey, error) {
	keys, err := s.backend.GetKeys([]string{"web", "users", user, "sessions"})
	if err != nil {
		return nil, err
	}

	values := make([]AuthorizedKey, len(keys))
	for i, key := range keys {
		session, err := s.GetWebSession(user, key)
		if err != nil {
			log.Errorf(err.Error())
			return nil, trace.Wrap(err)
		}
		values[i].Value = session.Pub
	}
	return values, nil
}

// DeleteWebSession
func (s *WebService) DeleteWebSession(user, sid string) error {
	err := s.backend.DeleteKey(
		[]string{"web", "users", user, "sessions"},
		sid,
	)
	return err
}

func (s *WebService) UpsertWebTun(tun WebTun, ttl time.Duration) error {
	if tun.Prefix == "" {
		log.Errorf("Missing parameter 'Prefix'")
		return fmt.Errorf("Missing parameter 'Prefix'")
	}

	bytes, err := json.Marshal(tun)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}

	err = s.backend.UpsertVal([]string{"web", "tunnels"},
		tun.Prefix, bytes, ttl)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}
	return nil
}

func (s *WebService) DeleteWebTun(prefix string) error {
	err := s.backend.DeleteKey(
		[]string{"web", "tunnels"},
		prefix,
	)
	return err
}
func (s *WebService) GetWebTun(prefix string) (*WebTun, error) {
	val, err := s.backend.GetVal(
		[]string{"web", "tunnels"},
		prefix,
	)
	if err != nil {
		return nil, err
	}

	var tun WebTun
	err = json.Unmarshal(val, &tun)
	if err != nil {
		log.Errorf(err.Error())
		return nil, trace.Wrap(err)
	}

	return &tun, nil
}
func (s *WebService) GetWebTuns() ([]WebTun, error) {
	keys, err := s.backend.GetKeys([]string{"web", "tunnels"})
	if err != nil {
		return nil, err
	}

	tuns := make([]WebTun, len(keys))
	for i, key := range keys {
		tun, err := s.GetWebTun(key)
		if err != nil {
			log.Errorf(err.Error())
			return nil, trace.Wrap(err)
		}
		tuns[i] = *tun
	}
	return tuns, nil
}

func (s *WebService) UpsertPassword(user string,
	password []byte) (hotpURL string, hotpQR []byte, err error) {

	if err := verifyPassword(password); err != nil {
		return "", nil, err
	}
	hash, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
	if err != nil {
		return "", nil, err
	}

	otp, err := hotp.GenerateHOTP(HOTPTokenDigits, false)
	if err != nil {
		return "", nil, err
	}
	hotpQR, err = otp.QR(user)
	if err != nil {
		return "", nil, err
	}
	hotpURL = otp.URL(user)
	if err != nil {
		return "", nil, err
	}
	otp.Increment()

	err = s.UpsertPasswordHash(user, hash)
	if err != nil {
		return "", nil, err
	}
	err = s.UpsertHOTP(user, otp)
	if err != nil {
		return "", nil, err
	}

	return hotpURL, hotpQR, nil

}

func (s *WebService) CheckPassword(user string, password []byte, hotpToken string) error {
	if err := verifyPassword(password); err != nil {
		return trace.Wrap(err)
	}
	hash, err := s.GetPasswordHash(user)
	if err != nil {
		return trace.Wrap(err)
	}
	if err := bcrypt.CompareHashAndPassword(hash, password); err != nil {
		return &teleport.BadParameterError{Err: "passwords do not match", Param: "password"}
	}

	otp, err := s.GetHOTP(user)
	if err != nil {
		return trace.Wrap(err)
	}

	if !otp.Scan(hotpToken, 4) {
		return &teleport.BadParameterError{Err: "tokens do not match", Param: "token"}
	}

	if err := s.UpsertHOTP(user, otp); err != nil {
		return trace.Wrap(err)
	}

	return nil
}

// TO DO: not very good
func (s *WebService) CheckPasswordWOToken(user string, password []byte) error {
	if err := verifyPassword(password); err != nil {
		return trace.Wrap(err)
	}
	hash, err := s.GetPasswordHash(user)
	if err != nil {
		return trace.Wrap(err)
	}
	if err := bcrypt.CompareHashAndPassword(hash, password); err != nil {
		return &teleport.BadParameterError{Err: "passwords do not match"}
	}

	return nil
}

// make sure password satisfies our requirements (relaxed),
// mostly to avoid putting garbage in
func verifyPassword(password []byte) error {
	if len(password) < MinPasswordLength {
		return &teleport.BadParameterError{
			Param: "password",
			Err: fmt.Sprintf(
				"password is too short, min length is %v", MinPasswordLength),
		}
	}
	if len(password) > MaxPasswordLength {
		return &teleport.BadParameterError{
			Param: "password",
			Err: fmt.Sprintf(
				"password is too long, max length is %v", MaxPasswordLength),
		}
	}
	return nil
}

type WebSession struct {
	Pub  []byte `json:"pub"`
	Priv []byte `json:"priv"`
}

// WebTun is a web tunnel, the SSH tunnel
// created by the SSH server to a remote web server
type WebTun struct {
	// Prefix is a domain prefix that will be used
	// to serve this tunnel
	Prefix string `json:"prefix"`
	// ProxyAddr is the address of the SSH server
	// that will be acting as a SSH proxy
	ProxyAddr string `json:"proxy"`
	// TargetAddr is the target http address of the server
	TargetAddr string `json:"target"`
}

func NewWebTun(prefix, proxyAddr, targetAddr string) (*WebTun, error) {
	if prefix == "" {
		return nil, &teleport.MissingParameterError{Param: "prefix"}
	}
	if targetAddr == "" {
		return nil, &teleport.MissingParameterError{Param: "target"}
	}
	if proxyAddr == "" {
		return nil, &teleport.MissingParameterError{Param: "proxy"}
	}
	if _, err := url.ParseRequestURI(targetAddr); err != nil {
		return nil, &teleport.BadParameterError{Param: "target", Err: err.Error()}
	}
	return &WebTun{Prefix: prefix, ProxyAddr: proxyAddr, TargetAddr: targetAddr}, nil
}

type SignupToken struct {
	Token           string
	User            string
	Hotp            []byte
	HotpFirstValues []string
	HotpQR          []byte
}

func (s *WebService) UpsertSignupToken(token string, tokenData SignupToken, ttl time.Duration) error {
	out, err := json.Marshal(tokenData)
	if err != nil {
		return trace.Wrap(err)
	}

	err = s.backend.UpsertVal([]string{"addusertokens"}, token, out, ttl)
	if err != nil {
		return trace.Wrap(err)
	}
	return nil

}
func (s *WebService) GetSignupToken(token string) (tokenData SignupToken,
	ttl time.Duration, e error) {

	out, ttl, err := s.backend.GetValAndTTL([]string{"addusertokens"}, token)
	if err != nil {
		return SignupToken{}, 0, trace.Wrap(err)
	}
	var data SignupToken
	err = json.Unmarshal(out, &data)
	if err != nil {
		return SignupToken{}, 0, trace.Wrap(err)
	}

	return data, ttl, nil
}
func (s *WebService) DeleteSignupToken(token string) error {
	err := s.backend.DeleteKey([]string{"addusertokens"}, token)
	return err
}

const (
	MinPasswordLength = 6
	MaxPasswordLength = 128
	HOTPTokenDigits   = 6 //number of digits in each token
)
<commit_msg>Fixed old account creation for different hotp token generators<commit_after>/*
Copyright 2015 Gravitational, Inc.

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 services

import (
	"encoding/json"
	"fmt"
	"net/url"
	"sync"
	"time"

	"github.com/gokyle/hotp"

	"github.com/gravitational/log"
	"github.com/gravitational/trace"
	"golang.org/x/crypto/bcrypt"

	"github.com/gravitational/teleport"
	"github.com/gravitational/teleport/lib/backend"
)

type WebService struct {
	backend     backend.Backend
	SignupMutex *sync.Mutex
}

func NewWebService(backend backend.Backend) *WebService {
	return &WebService{
		backend:     backend,
		SignupMutex: &sync.Mutex{},
	}
}

// UpsertPasswordHash upserts user password hash
func (s *WebService) UpsertPasswordHash(user string, hash []byte) error {
	err := s.backend.UpsertVal([]string{"web", "users", user},
		"pwd", hash, 0)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}
	return err
}

// GetPasswordHash returns the password hash for a given user
func (s *WebService) GetPasswordHash(user string) ([]byte, error) {
	hash, err := s.backend.GetVal([]string{"web", "users", user}, "pwd")
	if err != nil {
		return nil, err
	}
	return hash, err
}

func (s *WebService) UpsertHOTP(user string, otp *hotp.HOTP) error {
	bytes, err := hotp.Marshal(otp)
	if err != nil {
		return trace.Wrap(err)
	}
	err = s.backend.UpsertVal([]string{"web", "users", user},
		"hotp", bytes, 0)
	if err != nil {
		return trace.Wrap(err)
	}
	return nil
}

func (s *WebService) GetHOTP(user string) (*hotp.HOTP, error) {
	bytes, err := s.backend.GetVal([]string{"web", "users", user},
		"hotp")
	if err != nil {
		return nil, trace.Wrap(err)
	}
	otp, err := hotp.Unmarshal(bytes)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	return otp, nil
}

// UpsertSession
func (s *WebService) UpsertWebSession(user, sid string,
	session WebSession, ttl time.Duration) error {

	bytes, err := json.Marshal(session)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}

	err = s.backend.UpsertVal([]string{"web", "users", user, "sessions"},
		sid, bytes, ttl)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}
	return err

}

// GetWebSession
func (s *WebService) GetWebSession(user, sid string) (*WebSession, error) {
	val, err := s.backend.GetVal(
		[]string{"web", "users", user, "sessions"},
		sid,
	)
	if err != nil {
		return nil, err
	}

	var session WebSession
	err = json.Unmarshal(val, &session)
	if err != nil {
		log.Errorf(err.Error())
		return nil, trace.Wrap(err)
	}

	return &session, nil
}

// GetWebSessionsKeys
func (s *WebService) GetWebSessionsKeys(user string) ([]AuthorizedKey, error) {
	keys, err := s.backend.GetKeys([]string{"web", "users", user, "sessions"})
	if err != nil {
		return nil, err
	}

	values := make([]AuthorizedKey, len(keys))
	for i, key := range keys {
		session, err := s.GetWebSession(user, key)
		if err != nil {
			log.Errorf(err.Error())
			return nil, trace.Wrap(err)
		}
		values[i].Value = session.Pub
	}
	return values, nil
}

// DeleteWebSession
func (s *WebService) DeleteWebSession(user, sid string) error {
	err := s.backend.DeleteKey(
		[]string{"web", "users", user, "sessions"},
		sid,
	)
	return err
}

func (s *WebService) UpsertWebTun(tun WebTun, ttl time.Duration) error {
	if tun.Prefix == "" {
		log.Errorf("Missing parameter 'Prefix'")
		return fmt.Errorf("Missing parameter 'Prefix'")
	}

	bytes, err := json.Marshal(tun)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}

	err = s.backend.UpsertVal([]string{"web", "tunnels"},
		tun.Prefix, bytes, ttl)
	if err != nil {
		log.Errorf(err.Error())
		return trace.Wrap(err)
	}
	return nil
}

func (s *WebService) DeleteWebTun(prefix string) error {
	err := s.backend.DeleteKey(
		[]string{"web", "tunnels"},
		prefix,
	)
	return err
}
func (s *WebService) GetWebTun(prefix string) (*WebTun, error) {
	val, err := s.backend.GetVal(
		[]string{"web", "tunnels"},
		prefix,
	)
	if err != nil {
		return nil, err
	}

	var tun WebTun
	err = json.Unmarshal(val, &tun)
	if err != nil {
		log.Errorf(err.Error())
		return nil, trace.Wrap(err)
	}

	return &tun, nil
}
func (s *WebService) GetWebTuns() ([]WebTun, error) {
	keys, err := s.backend.GetKeys([]string{"web", "tunnels"})
	if err != nil {
		return nil, err
	}

	tuns := make([]WebTun, len(keys))
	for i, key := range keys {
		tun, err := s.GetWebTun(key)
		if err != nil {
			log.Errorf(err.Error())
			return nil, trace.Wrap(err)
		}
		tuns[i] = *tun
	}
	return tuns, nil
}

func (s *WebService) UpsertPassword(user string,
	password []byte) (hotpURL string, hotpQR []byte, err error) {

	if err := verifyPassword(password); err != nil {
		return "", nil, err
	}
	hash, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
	if err != nil {
		return "", nil, err
	}

	otp, err := hotp.GenerateHOTP(HOTPTokenDigits, false)
	if err != nil {
		return "", nil, err
	}
	hotpQR, err = otp.QR(user)
	if err != nil {
		return "", nil, err
	}
	hotpURL = otp.URL(user)
	if err != nil {
		return "", nil, err
	}

	err = s.UpsertPasswordHash(user, hash)
	if err != nil {
		return "", nil, err
	}
	err = s.UpsertHOTP(user, otp)
	if err != nil {
		return "", nil, err
	}

	return hotpURL, hotpQR, nil

}

func (s *WebService) CheckPassword(user string, password []byte, hotpToken string) error {
	if err := verifyPassword(password); err != nil {
		return trace.Wrap(err)
	}
	hash, err := s.GetPasswordHash(user)
	if err != nil {
		return trace.Wrap(err)
	}
	if err := bcrypt.CompareHashAndPassword(hash, password); err != nil {
		return &teleport.BadParameterError{Err: "passwords do not match", Param: "password"}
	}

	otp, err := s.GetHOTP(user)
	if err != nil {
		return trace.Wrap(err)
	}

	if !otp.Scan(hotpToken, 4) {
		return &teleport.BadParameterError{Err: "tokens do not match", Param: "token"}
	}

	if err := s.UpsertHOTP(user, otp); err != nil {
		return trace.Wrap(err)
	}

	return nil
}

// TO DO: not very good
func (s *WebService) CheckPasswordWOToken(user string, password []byte) error {
	if err := verifyPassword(password); err != nil {
		return trace.Wrap(err)
	}
	hash, err := s.GetPasswordHash(user)
	if err != nil {
		return trace.Wrap(err)
	}
	if err := bcrypt.CompareHashAndPassword(hash, password); err != nil {
		return &teleport.BadParameterError{Err: "passwords do not match"}
	}

	return nil
}

// make sure password satisfies our requirements (relaxed),
// mostly to avoid putting garbage in
func verifyPassword(password []byte) error {
	if len(password) < MinPasswordLength {
		return &teleport.BadParameterError{
			Param: "password",
			Err: fmt.Sprintf(
				"password is too short, min length is %v", MinPasswordLength),
		}
	}
	if len(password) > MaxPasswordLength {
		return &teleport.BadParameterError{
			Param: "password",
			Err: fmt.Sprintf(
				"password is too long, max length is %v", MaxPasswordLength),
		}
	}
	return nil
}

type WebSession struct {
	Pub  []byte `json:"pub"`
	Priv []byte `json:"priv"`
}

// WebTun is a web tunnel, the SSH tunnel
// created by the SSH server to a remote web server
type WebTun struct {
	// Prefix is a domain prefix that will be used
	// to serve this tunnel
	Prefix string `json:"prefix"`
	// ProxyAddr is the address of the SSH server
	// that will be acting as a SSH proxy
	ProxyAddr string `json:"proxy"`
	// TargetAddr is the target http address of the server
	TargetAddr string `json:"target"`
}

func NewWebTun(prefix, proxyAddr, targetAddr string) (*WebTun, error) {
	if prefix == "" {
		return nil, &teleport.MissingParameterError{Param: "prefix"}
	}
	if targetAddr == "" {
		return nil, &teleport.MissingParameterError{Param: "target"}
	}
	if proxyAddr == "" {
		return nil, &teleport.MissingParameterError{Param: "proxy"}
	}
	if _, err := url.ParseRequestURI(targetAddr); err != nil {
		return nil, &teleport.BadParameterError{Param: "target", Err: err.Error()}
	}
	return &WebTun{Prefix: prefix, ProxyAddr: proxyAddr, TargetAddr: targetAddr}, nil
}

type SignupToken struct {
	Token           string
	User            string
	Hotp            []byte
	HotpFirstValues []string
	HotpQR          []byte
}

func (s *WebService) UpsertSignupToken(token string, tokenData SignupToken, ttl time.Duration) error {
	out, err := json.Marshal(tokenData)
	if err != nil {
		return trace.Wrap(err)
	}

	err = s.backend.UpsertVal([]string{"addusertokens"}, token, out, ttl)
	if err != nil {
		return trace.Wrap(err)
	}
	return nil

}
func (s *WebService) GetSignupToken(token string) (tokenData SignupToken,
	ttl time.Duration, e error) {

	out, ttl, err := s.backend.GetValAndTTL([]string{"addusertokens"}, token)
	if err != nil {
		return SignupToken{}, 0, trace.Wrap(err)
	}
	var data SignupToken
	err = json.Unmarshal(out, &data)
	if err != nil {
		return SignupToken{}, 0, trace.Wrap(err)
	}

	return data, ttl, nil
}
func (s *WebService) DeleteSignupToken(token string) error {
	err := s.backend.DeleteKey([]string{"addusertokens"}, token)
	return err
}

const (
	MinPasswordLength = 6
	MaxPasswordLength = 128
	HOTPTokenDigits   = 6 //number of digits in each token
)
<|endoftext|>


<commit_before>package spaten

import (
	"io"

	"github.com/thomersch/grandine/lib/spatial"
)

type Codec struct {
	headerWritten bool
}

func (c *Codec) Encode(w io.Writer, fc *spatial.FeatureCollection) error {
	err := WriteFileHeader(w)
	if err != nil {
		return err
	}

	for _, ftBlk := range geomBlocks(100, fc.Features) {
		var meta map[string]interface{}
		if len(fc.SRID) != 0 {
			meta = map[string]interface{}{
				"@srid": fc.SRID,
			}
		}

		err = WriteBlock(w, ftBlk, meta)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Codec) EncodeChunk(w io.Writer, fc *spatial.FeatureCollection) error {
	if !c.headerWritten {
		err := WriteFileHeader(w)
		if err != nil {
			return err
		}
		c.headerWritten = true
	}
	return WriteBlock(w, fc.Features, nil)
}

func (c *Codec) Close() error {
	return nil
}

// ChunkedDecode is the preferred method for reading large datasets. It retrieves a file block
// at a time, making it possible to traverse the file in a streaming manner without allocating
// enough memory to fit the whole file.
func (c *Codec) ChunkedDecode(r io.Reader) (spatial.Chunks, error) {
	_, err := ReadFileHeader(r)
	if err != nil {
		return nil, err
	}
	return &Chunks{
		reader: r,
	}, nil
}

func (c *Codec) Decode(r io.Reader, fc *spatial.FeatureCollection) error {
	_, err := ReadFileHeader(r)
	if err != nil {
		return err
	}
	err = ReadBlocks(r, fc)
	return err
}

func (c *Codec) Extensions() []string {
	return []string{"spaten"}
}

// geomBlocks slices a slice of geometries into slices with a max size
func geomBlocks(size int, src []spatial.Feature) [][]spatial.Feature {
	if len(src) <= size {
		return [][]spatial.Feature{src}
	}

	var (
		i   int
		res [][]spatial.Feature
		end int
	)
	for end < len(src) {
		end = (i + 1) * size
		if end > len(src) {
			end = len(src)
		}
		res = append(res, src[i*size:end])
		i++
	}
	return res
}
<commit_msg>lib/spaten: chunk size<commit_after>package spaten

import (
	"io"

	"github.com/thomersch/grandine/lib/spatial"
)

type Codec struct {
	headerWritten bool
}

const blockSize = 1000

func (c *Codec) Encode(w io.Writer, fc *spatial.FeatureCollection) error {
	err := WriteFileHeader(w)
	if err != nil {
		return err
	}

	for _, ftBlk := range geomBlocks(blockSize, fc.Features) {
		var meta map[string]interface{}
		if len(fc.SRID) != 0 {
			meta = map[string]interface{}{
				"@srid": fc.SRID,
			}
		}

		err = WriteBlock(w, ftBlk, meta)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *Codec) EncodeChunk(w io.Writer, fc *spatial.FeatureCollection) error {
	if !c.headerWritten {
		err := WriteFileHeader(w)
		if err != nil {
			return err
		}
		c.headerWritten = true
	}
	// TODO: consider splitting up incoming chunks into blocks
	return WriteBlock(w, fc.Features, nil)
}

func (c *Codec) Close() error {
	return nil
}

// ChunkedDecode is the preferred method for reading large datasets. It retrieves a file block
// at a time, making it possible to traverse the file in a streaming manner without allocating
// enough memory to fit the whole file.
func (c *Codec) ChunkedDecode(r io.Reader) (spatial.Chunks, error) {
	_, err := ReadFileHeader(r)
	if err != nil {
		return nil, err
	}
	return &Chunks{
		reader: r,
	}, nil
}

func (c *Codec) Decode(r io.Reader, fc *spatial.FeatureCollection) error {
	_, err := ReadFileHeader(r)
	if err != nil {
		return err
	}
	err = ReadBlocks(r, fc)
	return err
}

func (c *Codec) Extensions() []string {
	return []string{"spaten"}
}

// geomBlocks slices a slice of geometries into slices with a max size
func geomBlocks(size int, src []spatial.Feature) [][]spatial.Feature {
	if len(src) <= size {
		return [][]spatial.Feature{src}
	}

	var (
		i   int
		res [][]spatial.Feature
		end int
	)
	for end < len(src) {
		end = (i + 1) * size
		if end > len(src) {
			end = len(src)
		}
		res = append(res, src[i*size:end])
		i++
	}
	return res
}
<|endoftext|>


<commit_before>/*
Incoming!!

Roadmap:
- document. make sure to mention that adblock (at least on chrome) causes high
  CPU usage. recommend to disable adblock for the page that uses incoming.
--> 0.1 finished

- (optional) file verification after upload: checksum in browser and backend, then
  assert that checksum is the same. Most likely error scenario: user updated file on
  disk while upload was running.
- go through ways for web app to retrieve file
  - available on filesystem? just give it the path to the file then (good enough if
    incoming!! serves only one web app). web app must move file away (or copy it), then
    tell incoming!! that it is finished. This is what we have now.
  - web app could download the file (very bad idea with most web apps, as it takes time,
    but this should be easy to implement)
  - if stored in cloud storage (ceph?): object id will work. coolest solution, as the file
    is stored in the right place right away

open questions:
- web app frontend must know name of incoming!! server. how will it get to know that?
    - for now: web app backend knows. html includes URL to js file.
- Incoming!! js code must know name of incoming!! server. how will it know?
    - for now, there is a function set_server_hostname in the incoming lib that must
	  be called by the web app frontend. Can we simplify this?
*/
package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"bitbucket.org/kardianos/osext"
	"github.com/gorilla/mux"

	"source.uit.no/lars.tiede/incoming/upload"
)

type appVarsT struct {
	uploaders upload.UploaderPool
	config    *appConfigT
}

var appVars *appVarsT

/* NewUploadHandler receives an http request from a webapp wanting to do
an upload, and makes an Uploader for it. It responds with the uploader's id
(string).
*/
func NewUploadHandler(w http.ResponseWriter, r *http.Request) {
	log.Printf("got new upload request")
	// read upload parameters from request
	destType := r.FormValue("destType")
	if destType == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "destType not given")
		return
	}
	signalFinishURL, err := url.ParseRequestURI(r.FormValue("signalFinishURL"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "signalFinishURL invalid: %s", err.Error())
		return
	}
	removeFileWhenFinished, err := strconv.ParseBool(
		r.FormValue("removeFileWhenFinished"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "removeFileWhenFinished invalid: %s", err.Error())
		return
	}
	signalFinishSecret := r.FormValue("signalFinishSecret")
	// signalFinishSecret is optional, so it's fine when it's empty

	// make (and pool) new uploader
	storageDirAbsolute, _ := filepath.Abs(appVars.config.StorageDir)
	uploader := upload.NewUploadToLocalFile(appVars.uploaders,
		storageDirAbsolute, signalFinishURL,
		removeFileWhenFinished, signalFinishSecret,
		time.Duration(appVars.config.UploadMaxIdleDurationS)*time.Second)

	// answer request with id of new uploader
	fmt.Fprint(w, uploader.GetId())
	return
}

func ServeJSFileHandler(w http.ResponseWriter, r *http.Request) {
	programDir, _ := osext.ExecutableFolder()
	filePath := path.Join(programDir, "incoming_jslib.js")
	http.ServeFile(w, r, filePath)
}

func FinishUploadHandler(w http.ResponseWriter, r *http.Request) {
	// fetch uploader for given id
	id := r.FormValue("id")
	if id == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id not given")
		return
	}
	uploader, ok := appVars.uploaders.Get(id)
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id unknown")
		return
	}

	// tell uploader that handover is done
	err := uploader.HandoverDone()

	// return error message or "ok"
	if err != nil {
		fmt.Fprint(w, err.Error())
	} else {
		fmt.Fprint(w, "ok")
	}
}

func CancelUploadHandler(w http.ResponseWriter, r *http.Request) {
	// Note that this can be called by both backend and frontend

	// fetch uploader for given id
	id := r.FormValue("id")
	if id == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id not given")
		return
	}
	uploader, ok := appVars.uploaders.Get(id)
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id unknown")
		return
	}

	// let uploader cancel (async because this method should return quickly)
	tellWebAppBackend := true
	if strings.Contains(r.URL.String(), "backend/") {
		tellWebAppBackend = false
	}
	go func() {
		uploader.Cancel(tellWebAppBackend, "Cancelled by request",
			time.Duration(appVars.config.HandoverTimeoutS)*time.Second)
		uploader.CleanUp()
	}()
	fmt.Fprint(w, "ok")
	// when uploader is done cancelling, it will send "upload finished" to web
	// app backend if necessary, so we are done here
	return
}

func main() {
	log.SetFlags(log.Lshortfile)

	// --- init application-wide things (config, data structures)
	appVars = new(appVarsT)
	var err error

	// load config
	appVars.config, err = LoadConfig()
	if err != nil {
		log.Printf("Couldn't load config!")
		log.Fatal(err)
		return
	}

	// init upload module
	err = upload.InitModule(appVars.config.StorageDir)
	if err != nil {
		log.Fatal(err)
		return
	}

	// init uploader pool
	appVars.uploaders = upload.NewLockedUploaderPool()

	// --- set up http server
	routes := mux.NewRouter()
	routes.HandleFunc("/incoming/backend/new_upload", NewUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/backend/cancel_upload", CancelUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/frontend/cancel_upload", CancelUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/backend/finish_upload", FinishUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/frontend/upload_ws", websocketHandler).
		Methods("GET")
	routes.HandleFunc("/incoming/frontend/incoming.js", ServeJSFileHandler).
		Methods("GET")

	// --- run server forever
	serverHost := fmt.Sprintf("%s:%d", appVars.config.IncomingIP,
		appVars.config.IncomingPort)
	log.Printf("Will start server on %s", serverHost)
	log.Fatal(http.ListenAndServe(serverHost, routes))
}
<commit_msg>more detailed logging config<commit_after>/*
Incoming!!

Roadmap:
- document. make sure to mention that adblock (at least on chrome) causes high
  CPU usage. recommend to disable adblock for the page that uses incoming.
--> 0.1 finished

- (optional) file verification after upload: checksum in browser and backend, then
  assert that checksum is the same. Most likely error scenario: user updated file on
  disk while upload was running.
- go through ways for web app to retrieve file
  - available on filesystem? just give it the path to the file then (good enough if
    incoming!! serves only one web app). web app must move file away (or copy it), then
    tell incoming!! that it is finished. This is what we have now.
  - web app could download the file (very bad idea with most web apps, as it takes time,
    but this should be easy to implement)
  - if stored in cloud storage (ceph?): object id will work. coolest solution, as the file
    is stored in the right place right away

open questions:
- web app frontend must know name of incoming!! server. how will it get to know that?
    - for now: web app backend knows. html includes URL to js file.
- Incoming!! js code must know name of incoming!! server. how will it know?
    - for now, there is a function set_server_hostname in the incoming lib that must
	  be called by the web app frontend. Can we simplify this?
*/
package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"bitbucket.org/kardianos/osext"
	"github.com/gorilla/mux"

	"source.uit.no/lars.tiede/incoming/upload"
)

type appVarsT struct {
	uploaders upload.UploaderPool
	config    *appConfigT
}

var appVars *appVarsT

/* NewUploadHandler receives an http request from a webapp wanting to do
an upload, and makes an Uploader for it. It responds with the uploader's id
(string).
*/
func NewUploadHandler(w http.ResponseWriter, r *http.Request) {
	log.Printf("got new upload request")
	// read upload parameters from request
	destType := r.FormValue("destType")
	if destType == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "destType not given")
		return
	}
	signalFinishURL, err := url.ParseRequestURI(r.FormValue("signalFinishURL"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "signalFinishURL invalid: %s", err.Error())
		return
	}
	removeFileWhenFinished, err := strconv.ParseBool(
		r.FormValue("removeFileWhenFinished"))
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "removeFileWhenFinished invalid: %s", err.Error())
		return
	}
	signalFinishSecret := r.FormValue("signalFinishSecret")
	// signalFinishSecret is optional, so it's fine when it's empty

	// make (and pool) new uploader
	storageDirAbsolute, _ := filepath.Abs(appVars.config.StorageDir)
	uploader := upload.NewUploadToLocalFile(appVars.uploaders,
		storageDirAbsolute, signalFinishURL,
		removeFileWhenFinished, signalFinishSecret,
		time.Duration(appVars.config.UploadMaxIdleDurationS)*time.Second)

	// answer request with id of new uploader
	fmt.Fprint(w, uploader.GetId())
	return
}

func ServeJSFileHandler(w http.ResponseWriter, r *http.Request) {
	programDir, _ := osext.ExecutableFolder()
	filePath := path.Join(programDir, "incoming_jslib.js")
	http.ServeFile(w, r, filePath)
}

func FinishUploadHandler(w http.ResponseWriter, r *http.Request) {
	// fetch uploader for given id
	id := r.FormValue("id")
	if id == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id not given")
		return
	}
	uploader, ok := appVars.uploaders.Get(id)
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id unknown")
		return
	}

	// tell uploader that handover is done
	err := uploader.HandoverDone()

	// return error message or "ok"
	if err != nil {
		fmt.Fprint(w, err.Error())
	} else {
		fmt.Fprint(w, "ok")
	}
}

func CancelUploadHandler(w http.ResponseWriter, r *http.Request) {
	// Note that this can be called by both backend and frontend

	// fetch uploader for given id
	id := r.FormValue("id")
	if id == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id not given")
		return
	}
	uploader, ok := appVars.uploaders.Get(id)
	if !ok {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "id unknown")
		return
	}

	// let uploader cancel (async because this method should return quickly)
	tellWebAppBackend := true
	if strings.Contains(r.URL.String(), "backend/") {
		tellWebAppBackend = false
	}
	go func() {
		uploader.Cancel(tellWebAppBackend, "Cancelled by request",
			time.Duration(appVars.config.HandoverTimeoutS)*time.Second)
		uploader.CleanUp()
	}()
	fmt.Fprint(w, "ok")
	// when uploader is done cancelling, it will send "upload finished" to web
	// app backend if necessary, so we are done here
	return
}

func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)

	// --- init application-wide things (config, data structures)
	appVars = new(appVarsT)
	var err error

	// load config
	appVars.config, err = LoadConfig()
	if err != nil {
		log.Printf("Couldn't load config!")
		log.Fatal(err)
		return
	}

	// init upload module
	err = upload.InitModule(appVars.config.StorageDir)
	if err != nil {
		log.Fatal(err)
		return
	}

	// init uploader pool
	appVars.uploaders = upload.NewLockedUploaderPool()

	// --- set up http server
	routes := mux.NewRouter()
	routes.HandleFunc("/incoming/backend/new_upload", NewUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/backend/cancel_upload", CancelUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/frontend/cancel_upload", CancelUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/backend/finish_upload", FinishUploadHandler).
		Methods("POST")
	routes.HandleFunc("/incoming/frontend/upload_ws", websocketHandler).
		Methods("GET")
	routes.HandleFunc("/incoming/frontend/incoming.js", ServeJSFileHandler).
		Methods("GET")

	// --- run server forever
	serverHost := fmt.Sprintf("%s:%d", appVars.config.IncomingIP,
		appVars.config.IncomingPort)
	log.Printf("Will start server on %s", serverHost)
	log.Fatal(http.ListenAndServe(serverHost, routes))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

func main() {
	if os.Args[0] == "/init" {
        fmt.Fprintf(os.Stdout, "started dockersh persistent container\n")
		// Wait for terminating signal
		sc := make(chan os.Signal, 2)
		signal.Notify(sc, syscall.SIGTERM, syscall.SIGINT)
		<-sc
		os.Exit(0)
	} else {
		os.Exit(realMain())
	}
}

func tmplConfigVar(template string, v *configInterpolation) string {
	shell := "/bin/bash"
	return strings.Replace(strings.Replace(strings.Replace(template, "%h", v.Home, -1), "%u", v.User, -1), "%s", shell, -1)
}

func realMain() int {
	_, err := nsenterdetect()
	if err != nil {
		return 1
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not load config: %v", err)
		return 1
	}
	/* Woo! We found nsenter, now to move onto more interesting things */
	username, homedir, uid, gid, err := getCurrentUser()
	config, err := loadAllConfig(username, homedir)
	configInterpolations := configInterpolation{homedir, username}
	realUsername := tmplConfigVar(config.ContainerUsername, &configInterpolations)
	realHomedirTo := tmplConfigVar(config.MountHomeTo, &configInterpolations)
    realHomedirFrom := tmplConfigVar(config.MountHomeFrom, &configInterpolations)
	realImageName := tmplConfigVar(config.ImageName, &configInterpolations)
	realShell := tmplConfigVar(config.Shell, &configInterpolations)
	containerName := fmt.Sprintf("%s_dockersh", realUsername)

	pid, err := dockerpid(containerName)
	if err != nil {
		pid, err = dockerstart(realUsername, realHomedirFrom, realHomedirTo, containerName, realImageName, config.DockerSocket, config.MountHome, config.MountTmp, config.MountDockerSocket, config.Entrypoint)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not start container: %s\n", err)
			return 1
		}
	}
	nsenterexec(pid, uid, gid, realHomedir, realShell)
	return 0
}
<commit_msg>Fix bug<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

func main() {
	if os.Args[0] == "/init" {
        fmt.Fprintf(os.Stdout, "started dockersh persistent container\n")
		// Wait for terminating signal
		sc := make(chan os.Signal, 2)
		signal.Notify(sc, syscall.SIGTERM, syscall.SIGINT)
		<-sc
		os.Exit(0)
	} else {
		os.Exit(realMain())
	}
}

func tmplConfigVar(template string, v *configInterpolation) string {
	shell := "/bin/bash"
	return strings.Replace(strings.Replace(strings.Replace(template, "%h", v.Home, -1), "%u", v.User, -1), "%s", shell, -1)
}

func realMain() int {
	_, err := nsenterdetect()
	if err != nil {
		return 1
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "could not load config: %v", err)
		return 1
	}
	/* Woo! We found nsenter, now to move onto more interesting things */
	username, homedir, uid, gid, err := getCurrentUser()
	config, err := loadAllConfig(username, homedir)
	configInterpolations := configInterpolation{homedir, username}
	realUsername := tmplConfigVar(config.ContainerUsername, &configInterpolations)
	realHomedirTo := tmplConfigVar(config.MountHomeTo, &configInterpolations)
    realHomedirFrom := tmplConfigVar(config.MountHomeFrom, &configInterpolations)
	realImageName := tmplConfigVar(config.ImageName, &configInterpolations)
	realShell := tmplConfigVar(config.Shell, &configInterpolations)
	containerName := fmt.Sprintf("%s_dockersh", realUsername)

	pid, err := dockerpid(containerName)
	if err != nil {
		pid, err = dockerstart(realUsername, realHomedirFrom, realHomedirTo, containerName, realImageName, config.DockerSocket, config.MountHome, config.MountTmp, config.MountDockerSocket, config.Entrypoint)
		if err != nil {
			fmt.Fprintf(os.Stderr, "could not start container: %s\n", err)
			return 1
		}
	}
    // FIXME - Should this be it's own setting not realHomedirTo
	nsenterexec(pid, uid, gid, realHomedirTo, realShell)
	return 0
}
<|endoftext|>