<commit_before>// Copyright 2020 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// Package st7567 implements an interface to the single-chip dot matrix LCD
//
// Datasheet
//
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7567.pdf

package st7567

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"periph.io/x/periph/conn"
	"periph.io/x/periph/conn/gpio"
	"periph.io/x/periph/conn/physic"
	"periph.io/x/periph/conn/spi"
)

const (
	// Width the max pixel width
	Width = 128
	// Height the max pixel height
	Height = 64

	pageSize = 128
	// displayOff (0xae): Display OFF (sleep mode)
	displayOff = 0xae
	// displayOn (0xaf): Display ON in normal mode
	displayOn = 0xaf
	// setStartLine (0x40-7f): Set display start line
	setStartLine = 0x40
	// setPageStart (0xb0-b7): Set page start address
	setPageStart = 0xb0
	// setColl (0x00-0x0f): Set lower column address
	setColl = 0x00
	// setCollH (0x10-0x1f): Set higher column address
	setCollH = 0x10
	// displayRAM (0xa4): Resume to RAM content display
	displayRAM = 0xa4
	// displayEntire (0xa5): Entire display ON
	displayEntire = 0xa5
	// enterRMWMode (0xe0): Enter the Read Modify Write mode
	enterRMWMode = 0xe0
	// exitRMWMode (0xee): Leave the Read Modify Write mode
	exitRMWMode = 0xee
	// powerControl (0x2c): Control built-in power circuit
	powerControl = 0x2f
	// setContrast (0x81): Set contrast control
	setContrast = 0x81
)

// Dev is a handle to a ST7567.
type Dev struct {
	c conn.Conn

	//dc low when sending a command, high when sending data.
	dc gpio.PinOut
	//rst reset pin, active low.
	rst gpio.PinOut
	//cs chip select pin
	cs gpio.PinIn

	//pixels the array containing the pixel map
	pixels [1024]byte
}

// Bias selects the LCD bias ratio of the voltage required for driving the LCD
type Bias byte

const (
	// Bias17 (0xa3): Select BIAS setting 1/7
	Bias17 Bias = 0xa3
	// Bias19 (0xa2): Select BIAS setting 1/9
	Bias19 Bias = 0xa2
)

func (b *Bias) Set(s string) error {
	switch s {
	case "17":
		*b = Bias17
	case "19":
		*b = Bias19
	default:
		return fmt.Errorf("unknown Bias %q: expected either 17 or 19", s)
	}
	return nil
}

func (b *Bias) String() string {
	switch *b {
	case Bias17:
		return "Bias 1/7"
	case Bias19:
		return "Bias 1/9"
	default:
		return "Unknown"
	}
}

// SegmentDirection is the direction of the segments
type SegmentDirection byte

const (
	// SegmentDirNormal (0xa0): Column address 0 is mapped to SEG0
	SegmentDirNormal SegmentDirection = 0xa0
	// SegmentDirReverse (0xa1): Column address 128 is mapped to SEG0
	SegmentDirReverse SegmentDirection = 0xa1
)

func (sd *SegmentDirection) Set(s string) error {
	switch s {
	case "normal":
		*sd = SegmentDirNormal
	case "reverse":
		*sd = SegmentDirReverse
	default:
		return fmt.Errorf("unknown SegmentDirection %q: expected either 'normal' or 'reverse'", s)
	}
	return nil
}

func (sd *SegmentDirection) String() string {
	switch *sd {
	case SegmentDirNormal:
		return "Normal segment direction"
	case SegmentDirReverse:
		return "Reverse segment direction"
	default:
		return "Unknown"
	}
}

// CommonDirection controls the common output status which changes the vertical display direction.
type CommonDirection byte

const (
	// CommonDirNormal (0xc0): Column address 0 is mapped to SEG0
	CommonDirNormal CommonDirection = 0xc0
	// CommonDirReverse (0xc8): Column address 128 is mapped to SEG0
	CommonDirReverse CommonDirection = 0xc8
)

func (cd *CommonDirection) Set(s string) error {
	switch s {
	case "normal":
		*cd = CommonDirNormal
	case "reverse":
		*cd = CommonDirReverse
	default:
		return fmt.Errorf("unknown CommonDirection %q: expected either 'normal' or 'reverse'", s)
	}
	return nil
}

func (cd *CommonDirection) String() string {
	switch *cd {
	case CommonDirNormal:
		return "Normal common direction"
	case CommonDirReverse:
		return "Reverse common direction"
	default:
		return "Unknown"
	}
}

// Display contains if the display is in normal or inverse mode (black will be white and vice versa)
type Display byte

const (
	// DisplayNormal (0xa6): Normal display
	DisplayNormal Display = 0xa6
	// DisplayInverse (0xa7): Inverse display
	DisplayInverse Display = 0xa7
)

func (d *Display) Set(s string) error {
	switch s {
	case "normal":
		*d = DisplayNormal
	case "inverse":
		*d = DisplayInverse
	default:
		return fmt.Errorf("unknown Display %q: expected either 'normal' or 'inverse'", s)
	}
	return nil
}

func (d *Display) String() string {
	switch *d {
	case DisplayNormal:
		return "Normal display"
	case DisplayInverse:
		return "Inverse display"
	default:
		return "Unknown"
	}
}

// RegulationResistor is the single regulation resistor value
type RegulationResistor byte

const (
	// RegResistorRR0 (0x21): Regulation Resistor ratio
	RegResistorRR0 RegulationResistor = 0x21
	// RegResistorRR1 (0x22): Regulation Resistor ratio
	RegResistorRR1 RegulationResistor = 0x22
	// RegResistorRR2 (0x24): Regulation Resistor ratio
	RegResistorRR2 RegulationResistor = 0x24
)

func (rr *RegulationResistor) Set(s string) error {
	switch s {
	case "RR0":
		*rr = RegResistorRR0
	case "RR1":
		*rr = RegResistorRR1
	case "RR2":
		*rr = RegResistorRR2
	default:
		return fmt.Errorf("unknown RegulataionRatio %q: expected either 'RR0' or 'RR1' or 'RR2'", s)
	}
	return nil
}

func (rr *RegulationResistor) String() string {
	switch *rr {
	case RegResistorRR0:
		return "Regulation resistor RR0"
	case RegResistorRR1:
		return "Regulation resistor RR1"
	case RegResistorRR2:
		return "Regulation resistor RR2"
	default:
		return "Unknown"
	}
}

//RegulationRatio selects the regulation resistor ratio
type RegulationRatio []RegulationResistor

func (rrs *RegulationRatio) String() string {
	return "regulation resistor ratios"
}

func (rrs *RegulationRatio) Set(value string) error {
	values := strings.Split(value, ",")

	for _, v := range values {
		rr := new(RegulationResistor)

		if err := rr.Set(v); err != nil {
			return err
		}

		*rrs = append(*rrs, *rr)
	}

	return nil
}

func (rrs RegulationRatio) getValue() RegulationResistor {
	var out RegulationResistor
	for _, v := range rrs {
		out |= v
	}
	return out
}

// Opts contains the configuration for the S7567 device.
type Opts struct {
	// Bias selects the LCD bias ratio of the voltage required for driving the LCD.
	Bias Bias
	// SegmentDirection is the direction of the segments.
	SegmentDirection SegmentDirection
	// CommonDirection is the direction of the segments.
	CommonDirection CommonDirection
	// Display changes the selected and non-selected voltage of SEG.
	Display Display
	// RegulationRatio controls the regulation ratio of the built-in regulator.
	RegulationRatio RegulationRatio
	// StartLine sets the line address of the Display Data RAM to determine the initial display line.
	StartLine byte
	// Contrast the value to adjust the display contrast.
	Contrast byte
}

// New opens a handle to a ST7567 LCD.
func New(p spi.Port, dc gpio.PinOut, rst gpio.PinOut, cs gpio.PinIn, o *Opts) (*Dev, error) {
	c, err := p.Connect(1000*physic.KiloHertz, spi.Mode0, 8)

	if err != nil {
		return nil, errors.New("could not connect to device")
	}

	d := &Dev{
		c:   c,
		dc:  dc,
		rst: rst,
		cs:  cs,
	}

	cmd := make([]byte, 9)
	cmd = append(cmd, byte(o.Bias))
	cmd = append(cmd, byte(o.SegmentDirection))
	cmd = append(cmd, byte(o.CommonDirection))
	cmd = append(cmd, byte(o.Display))
	cmd = append(cmd, setStartLine|o.StartLine)
	cmd = append(cmd, powerControl)
	cmd = append(cmd, byte(o.RegulationRatio.getValue()))
	cmd = append(cmd, displayOn)
	cmd = append(cmd, setContrast)
	cmd = append(cmd, o.Contrast)

	if err := d.sendCommand(cmd); err != nil {
		return nil, err
	}

	return d, nil
}

// Halt resets the registers and switches the driver off.
func (d *Dev) Halt() error {
	return d.reset()
}

// SetContrast sets the contrast
func (d *Dev) SetContrast(value byte) error {
	return d.sendCommand([]byte{setContrast, value})
}

// SetPixel sets a pixel in the pixels array
func (d *Dev) SetPixel(x, y int, active bool) {
	offset := (y / 8 * Width) + x
	pageAddress := y % 8
	d.pixels[offset] &= ^(1 << byte(pageAddress))
	d.pixels[offset] |= bTob(active) & 1 << byte(pageAddress)
}

// Update updates the display
func (d *Dev) Update() error {
	if err := d.sendCommand([]byte{enterRMWMode}); err != nil {
		return err
	}
	for i := 0; i < 8; i++ {
		offset := i * pageSize
		if err := d.sendCommand([]byte{setPageStart | byte(i), setColl, setCollH}); err != nil {
			return err
		}
		if err := d.sendData(d.pixels[offset : offset+pageSize]); err != nil {
			return err
		}
	}
	if err := d.sendCommand([]byte{exitRMWMode}); err != nil {
		return err
	}
	return nil
}

// PowerSave turning the display into sleep
func (d *Dev) PowerSave() error {
	return d.sendCommand([]byte{displayOff, displayEntire})
}

// WakeUp wakes the display up from power saving mode
func (d *Dev) WakeUp() error {
	return d.sendCommand([]byte{displayRAM, displayOn})
}

func (d *Dev) sendCommand(c []byte) error {
	if err := d.dc.Out(gpio.Low); err != nil {
		return err
	}
	return d.c.Tx(c, nil)
}

func (d *Dev) sendData(c []byte) error {
	if err := d.dc.Out(gpio.High); err != nil {
		return err
	}
	return d.c.Tx(c, nil)
}

func (d *Dev) reset() error {
	if err := d.rst.Out(gpio.Low); err != nil {
		return err
	}
	time.Sleep(50 * time.Millisecond)
	if err := d.rst.Out(gpio.High); err != nil {
		return err
	}
	time.Sleep(50 * time.Millisecond)
	return nil
}

func bTob(b bool) byte {
	if b {
		return 1
	}
	return 0
}
<commit_msg>st7567: Minor cleanup (#453)<commit_after>// Copyright 2020 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

// Package st7567 implements an interface to the single-chip dot matrix LCD
//
// Datasheet
//
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7567.pdf

package st7567

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"periph.io/x/periph/conn"
	"periph.io/x/periph/conn/gpio"
	"periph.io/x/periph/conn/physic"
	"periph.io/x/periph/conn/spi"
)

const (
	// Width the max pixel width
	Width = 128
	// Height the max pixel height
	Height = 64

	pageSize = 128
	// displayOff (0xae): Display OFF (sleep mode)
	displayOff = 0xae
	// displayOn (0xaf): Display ON in normal mode
	displayOn = 0xaf
	// setStartLine (0x40-7f): Set display start line
	setStartLine = 0x40
	// setPageStart (0xb0-b7): Set page start address
	setPageStart = 0xb0
	// setColl (0x00-0x0f): Set lower column address
	setColl = 0x00
	// setCollH (0x10-0x1f): Set higher column address
	setCollH = 0x10
	// displayRAM (0xa4): Resume to RAM content display
	displayRAM = 0xa4
	// displayEntire (0xa5): Entire display ON
	displayEntire = 0xa5
	// enterRMWMode (0xe0): Enter the Read Modify Write mode
	enterRMWMode = 0xe0
	// exitRMWMode (0xee): Leave the Read Modify Write mode
	exitRMWMode = 0xee
	// powerControl (0x2c): Control built-in power circuit
	powerControl = 0x2f
	// setContrast (0x81): Set contrast control
	setContrast = 0x81
)

// Dev is a handle to a ST7567.
type Dev struct {
	c conn.Conn

	//dc low when sending a command, high when sending data.
	dc gpio.PinOut
	//rst reset pin, active low.
	rst gpio.PinOut
	//cs chip select pin
	cs gpio.PinIn

	//pixels the array containing the pixel map
	pixels [1024]byte
}

// Bias selects the LCD bias ratio of the voltage required for driving the LCD
type Bias byte

const (
	// Bias17 (0xa3): Select BIAS setting 1/7
	Bias17 Bias = 0xa3
	// Bias19 (0xa2): Select BIAS setting 1/9
	Bias19 Bias = 0xa2
)

func (b *Bias) Set(s string) error {
	switch s {
	case "17":
		*b = Bias17
	case "19":
		*b = Bias19
	default:
		return fmt.Errorf("unknown Bias %q: expected either 17 or 19", s)
	}
	return nil
}

func (b *Bias) String() string {
	switch *b {
	case Bias17:
		return "Bias 1/7"
	case Bias19:
		return "Bias 1/9"
	default:
		return "Unknown"
	}
}

// SegmentDirection is the direction of the segments
type SegmentDirection byte

const (
	// SegmentDirNormal (0xa0): Column address 0 is mapped to SEG0
	SegmentDirNormal SegmentDirection = 0xa0
	// SegmentDirReverse (0xa1): Column address 128 is mapped to SEG0
	SegmentDirReverse SegmentDirection = 0xa1
)

func (sd *SegmentDirection) Set(s string) error {
	switch s {
	case "normal":
		*sd = SegmentDirNormal
	case "reverse":
		*sd = SegmentDirReverse
	default:
		return fmt.Errorf("unknown SegmentDirection %q: expected either 'normal' or 'reverse'", s)
	}
	return nil
}

func (sd *SegmentDirection) String() string {
	switch *sd {
	case SegmentDirNormal:
		return "Normal segment direction"
	case SegmentDirReverse:
		return "Reverse segment direction"
	default:
		return "Unknown"
	}
}

// CommonDirection controls the common output status which changes the vertical display direction.
type CommonDirection byte

const (
	// CommonDirNormal (0xc0): Column address 0 is mapped to SEG0
	CommonDirNormal CommonDirection = 0xc0
	// CommonDirReverse (0xc8): Column address 128 is mapped to SEG0
	CommonDirReverse CommonDirection = 0xc8
)

func (cd *CommonDirection) Set(s string) error {
	switch s {
	case "normal":
		*cd = CommonDirNormal
	case "reverse":
		*cd = CommonDirReverse
	default:
		return fmt.Errorf("unknown CommonDirection %q: expected either 'normal' or 'reverse'", s)
	}
	return nil
}

func (cd *CommonDirection) String() string {
	switch *cd {
	case CommonDirNormal:
		return "Normal common direction"
	case CommonDirReverse:
		return "Reverse common direction"
	default:
		return "Unknown"
	}
}

// Display contains if the display is in normal or inverse mode (black will be white and vice versa)
type Display byte

const (
	// DisplayNormal (0xa6): Normal display
	DisplayNormal Display = 0xa6
	// DisplayInverse (0xa7): Inverse display
	DisplayInverse Display = 0xa7
)

func (d *Display) Set(s string) error {
	switch s {
	case "normal":
		*d = DisplayNormal
	case "inverse":
		*d = DisplayInverse
	default:
		return fmt.Errorf("unknown Display %q: expected either 'normal' or 'inverse'", s)
	}
	return nil
}

func (d *Display) String() string {
	switch *d {
	case DisplayNormal:
		return "Normal display"
	case DisplayInverse:
		return "Inverse display"
	default:
		return "Unknown"
	}
}

// RegulationResistor is the single regulation resistor value
type RegulationResistor byte

const (
	// RegResistorRR0 (0x21): Regulation Resistor ratio
	RegResistorRR0 RegulationResistor = 0x21
	// RegResistorRR1 (0x22): Regulation Resistor ratio
	RegResistorRR1 RegulationResistor = 0x22
	// RegResistorRR2 (0x24): Regulation Resistor ratio
	RegResistorRR2 RegulationResistor = 0x24
)

func (rr *RegulationResistor) Set(s string) error {
	switch s {
	case "RR0":
		*rr = RegResistorRR0
	case "RR1":
		*rr = RegResistorRR1
	case "RR2":
		*rr = RegResistorRR2
	default:
		return fmt.Errorf("unknown RegulataionRatio %q: expected either 'RR0' or 'RR1' or 'RR2'", s)
	}
	return nil
}

func (rr *RegulationResistor) String() string {
	switch *rr {
	case RegResistorRR0:
		return "Regulation resistor RR0"
	case RegResistorRR1:
		return "Regulation resistor RR1"
	case RegResistorRR2:
		return "Regulation resistor RR2"
	default:
		return "Unknown"
	}
}

//RegulationRatio selects the regulation resistor ratio
type RegulationRatio []RegulationResistor

func (rrs *RegulationRatio) String() string {
	return "Regulation resistor ratio"
}

func (rrs *RegulationRatio) Set(value string) error {
	values := strings.Split(value, ",")

	for _, v := range values {
		rr := new(RegulationResistor)

		if err := rr.Set(v); err != nil {
			return err
		}

		*rrs = append(*rrs, *rr)
	}

	return nil
}

func (rrs RegulationRatio) getValue() RegulationResistor {
	var out RegulationResistor
	for _, v := range rrs {
		out |= v
	}
	return out
}

// Opts contains the configuration for the S7567 device.
type Opts struct {
	// Bias selects the LCD bias ratio of the voltage required for driving the LCD.
	Bias Bias
	// SegmentDirection is the direction of the segments.
	SegmentDirection SegmentDirection
	// CommonDirection controls the common output status which changes the vertical display direction.
	CommonDirection CommonDirection
	// Display changes the selected and non-selected voltage of SEG.
	Display Display
	// RegulationRatio controls the regulation ratio of the built-in regulator.
	RegulationRatio RegulationRatio
	// StartLine sets the line address of the Display Data RAM to determine the initial display line.
	StartLine byte
	// Contrast the value to adjust the display contrast.
	Contrast byte
}

// New opens a handle to a ST7567 LCD.
func New(p spi.Port, dc gpio.PinOut, rst gpio.PinOut, cs gpio.PinIn, o *Opts) (*Dev, error) {
	c, err := p.Connect(1000*physic.KiloHertz, spi.Mode0, 8)

	if err != nil {
		return nil, errors.New("could not connect to device")
	}

	d := &Dev{
		c:   c,
		dc:  dc,
		rst: rst,
		cs:  cs,
	}

	cmd := [...]byte{
		byte(o.Bias),
		byte(o.SegmentDirection),
		byte(o.CommonDirection),
		byte(o.Display),
		setStartLine | o.StartLine,
		powerControl,
		byte(o.RegulationRatio.getValue()),
		displayOn,
		setContrast,
		o.Contrast,
	}

	if err := d.sendCommand(cmd[:]); err != nil {
		return nil, err
	}

	return d, nil
}

// Halt resets the registers and switches the driver off.
func (d *Dev) Halt() error {
	return d.reset()
}

// SetContrast sets the contrast
func (d *Dev) SetContrast(value byte) error {
	return d.sendCommand([]byte{setContrast, value})
}

// SetPixel sets a pixel in the pixels array
func (d *Dev) SetPixel(x, y int, active bool) {
	offset := (y / 8 * Width) + x
	pageAddress := y % 8
	d.pixels[offset] &= ^(1 << byte(pageAddress))
	d.pixels[offset] |= bTob(active) & 1 << byte(pageAddress)
}

// Update updates the display
func (d *Dev) Update() error {
	if err := d.sendCommand([]byte{enterRMWMode}); err != nil {
		return err
	}
	for i := 0; i < 8; i++ {
		offset := i * pageSize
		if err := d.sendCommand([]byte{setPageStart | byte(i), setColl, setCollH}); err != nil {
			return err
		}
		if err := d.sendData(d.pixels[offset : offset+pageSize]); err != nil {
			return err
		}
	}
	if err := d.sendCommand([]byte{exitRMWMode}); err != nil {
		return err
	}
	return nil
}

// PowerSave turning the display into sleep
func (d *Dev) PowerSave() error {
	return d.sendCommand([]byte{displayOff, displayEntire})
}

// WakeUp wakes the display up from power saving mode
func (d *Dev) WakeUp() error {
	return d.sendCommand([]byte{displayRAM, displayOn})
}

func (d *Dev) sendCommand(c []byte) error {
	if err := d.dc.Out(gpio.Low); err != nil {
		return err
	}
	return d.c.Tx(c, nil)
}

func (d *Dev) sendData(c []byte) error {
	if err := d.dc.Out(gpio.High); err != nil {
		return err
	}
	return d.c.Tx(c, nil)
}

func (d *Dev) reset() error {
	if err := d.rst.Out(gpio.Low); err != nil {
		return err
	}
	time.Sleep(50 * time.Millisecond)
	if err := d.rst.Out(gpio.High); err != nil {
		return err
	}
	time.Sleep(50 * time.Millisecond)
	return nil
}

func bTob(b bool) byte {
	if b {
		return 1
	}
	return 0
}
<|endoftext|>


<commit_before>/*
MIT License

Copyright (c) 2017 Simon Schmidt

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*
 Multi-Hop Anonymization Protocol for one connection. This Protocol uses
 the public key function Curve25519 and the cipher Twofish in Counter Mode.
 A Session consists of two end points (Client and Server) and zero or more
 Intermediate stations. The Intermediate station scrambles the key-exchange
 handshake without braking it and it scrambles the communicated data without
 breaking it. The Intermediate station's input and output can not be associated
 with each other (to identify a Session), except with a 256-bit brute force attack.
*/
package scrambler

import "io"
import "encoding/binary"
import "golang.org/x/crypto/curve25519"
//import "golang.org/x/crypto/twofish"
import "git.schwanenlied.me/yawning/chacha20.git"
import "crypto/rand"
import "crypto/cipher"
import "fmt"

const (
	ivC2S = "Client-to-Server"
	ivS2C = "Server-to-Client"
	ivP2P = "Peer---to---Peer"
)

func hex(i interface{}) string{
	return fmt.Sprintf("%X",i)
}

type CryptoRecord struct{
	Array [3][32]byte
}

type wrapper struct{
	C io.Closer
	cipher.StreamReader
	cipher.StreamWriter
}
func (w *wrapper) Close() error{
	if w.C==nil { return nil }
	return w.C.Close()
}

func encryptIV(key, ivi, ivo []byte){
	var out [32]byte
	var nonce [chacha20.HNonceSize]byte
	copy(nonce[:],ivi)
	chacha20.HChaCha(key,&nonce,&out)
	copy(ivo,out[:])
}

/* Client side function to start a session. */
func Initiator(srv io.ReadWriteCloser) (io.ReadWriteCloser,error){
	var t [3][32]byte
	var r CryptoRecord

	for i := range t {
		rand.Read(t[i][:])
		curve25519.ScalarBaseMult(&(r.Array[i]),&(t[i]))
	}

	e := binary.Write(srv,binary.BigEndian,r)
	if e!=nil { return nil,e }
	e = binary.Read(srv,binary.BigEndian,&r)
	if e!=nil { return nil,e }

	for i := range t {
		curve25519.ScalarMult(&(r.Array[i]),&(t[i]),&(r.Array[i]))
	}

	//------------------------------------------------------------

	iv := []byte(ivC2S)
	eiv := make([]byte,24)
	c2s := make(multiStream,3)
	for i := range r.Array {
		//c,_ := twofish.NewCipher(r.Array[i][:])
		//c.Encrypt(eiv,iv)
		encryptIV(r.Array[i][:],iv,eiv)
		//c2s[i] = cipher.NewCTR(c, eiv)
		c2s[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	iv = []byte(ivS2C)
	s2c := make(multiStream,3)
	for i := range r.Array {
		//c,_ := twofish.NewCipher(r.Array[i][:])
		//c.Encrypt(eiv,iv)
		encryptIV(r.Array[i][:],iv,eiv)
		//s2c[i] = cipher.NewCTR(c, eiv)
		s2c[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	return &wrapper{
		srv,
		cipher.StreamReader{s2c,srv},
		cipher.StreamWriter{c2s,srv,nil},
	},nil
}

/*
Intermediate station function to start a session.
If an error is returned, please close the connections, otherwise, don't.
*/
func Intermediate(clt io.ReadWriteCloser,srv io.ReadWriteCloser) error{
	const (
		SALT = iota
		SALT2
		CLTK
		SRVK
		N_Ts /* Number of t-Keys */
	)

	var t [N_Ts][32]byte
	var K [2][32]byte
	var r CryptoRecord

	for i := range t {
		rand.Read(t[i][:])
	}

	//-------------------------------------------------------

	/*  [A,B,X] -> [B,C,X]  */

	e := binary.Read(clt,binary.BigEndian,&r)
	if e!=nil { return e }

	curve25519.ScalarMult(&(K[0]),&(t[CLTK]),&(r.Array[0]))
	r.Array[0] = r.Array[1]
	curve25519.ScalarBaseMult(&(r.Array[1]),&(t[SRVK]))

	/* Scramble B and X */

	curve25519.ScalarMult(&(r.Array[0]),&(t[SALT]),&(r.Array[0]))
	curve25519.ScalarMult(&(r.Array[2]),&(t[SALT2]),&(r.Array[2]))

	e = binary.Write(srv,binary.BigEndian,r)
	if e!=nil { return e }

	//-------------------------------------------------------

	/*  [B,C,X] -> [A,B,X]  */

	e = binary.Read(srv,binary.BigEndian,&r)
	if e!=nil { return e }

	curve25519.ScalarMult(&(K[1]),&(t[SRVK]),&(r.Array[1]))
	r.Array[1] = r.Array[0]
	curve25519.ScalarBaseMult(&(r.Array[0]),&(t[CLTK]))

	/* Scramble B and X */

	curve25519.ScalarMult(&(r.Array[1]),&(t[SALT]),&(r.Array[1]))
	curve25519.ScalarMult(&(r.Array[2]),&(t[SALT2]),&(r.Array[2]))

	e = binary.Write(clt,binary.BigEndian,r)
	if e!=nil { return e }

	//-------------------------------------------------------

	/* Apply Transcryption (A and C) */

	iv := []byte(ivC2S)
	eiv := make([]byte,24)
	c2s := make(multiStream,2)
	for i := range K {
		//c,_ := twofish.NewCipher(K[i][:])
		//c.Encrypt(eiv,iv)
		encryptIV(K[i][:],iv,eiv)
		//c2s[i] = cipher.NewCTR(c, eiv)
		c2s[i],_ = chacha20.NewCipher(K[i][:],eiv)
	}

	s2c := make(multiStream,2)
	iv = []byte(ivS2C)
	for i := range K {
		//c,_ := twofish.NewCipher(K[i][:])
		//c.Encrypt(eiv,iv)
		encryptIV(K[i][:],iv,eiv)
		//s2c[i] = cipher.NewCTR(c, eiv)
		s2c[i],_ = chacha20.NewCipher(K[i][:],eiv)
	}

	eclt := cipher.StreamReader{c2s,clt}
	esrv := cipher.StreamReader{s2c,srv}

	go dispatch(eclt,srv)
	go dispatch(esrv,clt)
	return nil
}

/* Server side function to start a session. */
func Endpt(clt io.ReadWriteCloser) (io.ReadWriteCloser,error) {
	var t [3][32]byte
	var r,r2 CryptoRecord
	e := binary.Read(clt,binary.BigEndian,&r)
	if e!=nil { return nil,e }

	for i := range t {
		rand.Read(t[i][:])
		curve25519.ScalarBaseMult(&(r2.Array[i]),&(t[i]))
		curve25519.ScalarMult(&(r.Array[i]),&(t[i]),&(r.Array[i]))
	}

	e = binary.Write(clt,binary.BigEndian,r2)
	if e!=nil { return nil,e }

	//-------------------------------------------------------

	iv := []byte(ivC2S)
	eiv := make([]byte,16)
	c2s := make(multiStream,3)
	for i := range r.Array {
		//c,_ := twofish.NewCipher(r.Array[i][:])
		//c.Encrypt(eiv,iv)
		encryptIV(r.Array[i][:],iv,eiv)
		//c2s[i] = cipher.NewCTR(c, eiv)
		c2s[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	iv = []byte(ivS2C)
	s2c := make(multiStream,3)
	for i := range r.Array {
		//c,_ := twofish.NewCipher(r.Array[i][:])
		//c.Encrypt(eiv,iv)
		encryptIV(r.Array[i][:],iv,eiv)
		//s2c[i] = cipher.NewCTR(c, eiv)
		s2c[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	return &wrapper{
		clt,
		cipher.StreamReader{c2s,clt},
		cipher.StreamWriter{s2c,clt,nil},
	},nil
}

<commit_msg>Remove Comments<commit_after>/*
MIT License

Copyright (c) 2017 Simon Schmidt

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/*
 Multi-Hop Anonymization Protocol for one connection. This Protocol uses
 the public key function Curve25519 and the cipher Twofish in Counter Mode.
 A Session consists of two end points (Client and Server) and zero or more
 Intermediate stations. The Intermediate station scrambles the key-exchange
 handshake without braking it and it scrambles the communicated data without
 breaking it. The Intermediate station's input and output can not be associated
 with each other (to identify a Session), except with a 256-bit brute force attack.
*/
package scrambler

import "io"
import "encoding/binary"
import "golang.org/x/crypto/curve25519"
import "git.schwanenlied.me/yawning/chacha20.git"
import "crypto/rand"
import "crypto/cipher"
import "fmt"

const (
	ivC2S = "Client-to-Server"
	ivS2C = "Server-to-Client"
	ivP2P = "Peer---to---Peer"
)

func hex(i interface{}) string{
	return fmt.Sprintf("%X",i)
}

type CryptoRecord struct{
	Array [3][32]byte
}

type wrapper struct{
	C io.Closer
	cipher.StreamReader
	cipher.StreamWriter
}
func (w *wrapper) Close() error{
	if w.C==nil { return nil }
	return w.C.Close()
}

func encryptIV(key, ivi, ivo []byte){
	var out [32]byte
	var nonce [chacha20.HNonceSize]byte
	copy(nonce[:],ivi)
	chacha20.HChaCha(key,&nonce,&out)
	copy(ivo,out[:])
}

/* Client side function to start a session. */
func Initiator(srv io.ReadWriteCloser) (io.ReadWriteCloser,error){
	var t [3][32]byte
	var r CryptoRecord

	for i := range t {
		rand.Read(t[i][:])
		curve25519.ScalarBaseMult(&(r.Array[i]),&(t[i]))
	}

	e := binary.Write(srv,binary.BigEndian,r)
	if e!=nil { return nil,e }
	e = binary.Read(srv,binary.BigEndian,&r)
	if e!=nil { return nil,e }

	for i := range t {
		curve25519.ScalarMult(&(r.Array[i]),&(t[i]),&(r.Array[i]))
	}

	//------------------------------------------------------------

	iv := []byte(ivC2S)
	eiv := make([]byte,24)
	c2s := make(multiStream,3)
	for i := range r.Array {
		encryptIV(r.Array[i][:],iv,eiv)
		c2s[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	iv = []byte(ivS2C)
	s2c := make(multiStream,3)
	for i := range r.Array {
		encryptIV(r.Array[i][:],iv,eiv)
		s2c[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	return &wrapper{
		srv,
		cipher.StreamReader{s2c,srv},
		cipher.StreamWriter{c2s,srv,nil},
	},nil
}

/*
Intermediate station function to start a session.
If an error is returned, please close the connections, otherwise, don't.
*/
func Intermediate(clt io.ReadWriteCloser,srv io.ReadWriteCloser) error{
	const (
		SALT = iota
		SALT2
		CLTK
		SRVK
		N_Ts /* Number of t-Keys */
	)

	var t [N_Ts][32]byte
	var K [2][32]byte
	var r CryptoRecord

	for i := range t {
		rand.Read(t[i][:])
	}

	//-------------------------------------------------------

	/*  [A,B,X] -> [B,C,X]  */

	e := binary.Read(clt,binary.BigEndian,&r)
	if e!=nil { return e }

	curve25519.ScalarMult(&(K[0]),&(t[CLTK]),&(r.Array[0]))
	r.Array[0] = r.Array[1]
	curve25519.ScalarBaseMult(&(r.Array[1]),&(t[SRVK]))

	/* Scramble B and X */

	curve25519.ScalarMult(&(r.Array[0]),&(t[SALT]),&(r.Array[0]))
	curve25519.ScalarMult(&(r.Array[2]),&(t[SALT2]),&(r.Array[2]))

	e = binary.Write(srv,binary.BigEndian,r)
	if e!=nil { return e }

	//-------------------------------------------------------

	/*  [B,C,X] -> [A,B,X]  */

	e = binary.Read(srv,binary.BigEndian,&r)
	if e!=nil { return e }

	curve25519.ScalarMult(&(K[1]),&(t[SRVK]),&(r.Array[1]))
	r.Array[1] = r.Array[0]
	curve25519.ScalarBaseMult(&(r.Array[0]),&(t[CLTK]))

	/* Scramble B and X */

	curve25519.ScalarMult(&(r.Array[1]),&(t[SALT]),&(r.Array[1]))
	curve25519.ScalarMult(&(r.Array[2]),&(t[SALT2]),&(r.Array[2]))

	e = binary.Write(clt,binary.BigEndian,r)
	if e!=nil { return e }

	//-------------------------------------------------------

	/* Apply Transcryption (A and C) */

	iv := []byte(ivC2S)
	eiv := make([]byte,24)
	c2s := make(multiStream,2)
	for i := range K {
		encryptIV(K[i][:],iv,eiv)
		c2s[i],_ = chacha20.NewCipher(K[i][:],eiv)
	}

	s2c := make(multiStream,2)
	iv = []byte(ivS2C)
	for i := range K {
		encryptIV(K[i][:],iv,eiv)
		s2c[i],_ = chacha20.NewCipher(K[i][:],eiv)
	}

	eclt := cipher.StreamReader{c2s,clt}
	esrv := cipher.StreamReader{s2c,srv}

	go dispatch(eclt,srv)
	go dispatch(esrv,clt)
	return nil
}

/* Server side function to start a session. */
func Endpt(clt io.ReadWriteCloser) (io.ReadWriteCloser,error) {
	var t [3][32]byte
	var r,r2 CryptoRecord
	e := binary.Read(clt,binary.BigEndian,&r)
	if e!=nil { return nil,e }

	for i := range t {
		rand.Read(t[i][:])
		curve25519.ScalarBaseMult(&(r2.Array[i]),&(t[i]))
		curve25519.ScalarMult(&(r.Array[i]),&(t[i]),&(r.Array[i]))
	}

	e = binary.Write(clt,binary.BigEndian,r2)
	if e!=nil { return nil,e }

	//-------------------------------------------------------

	iv := []byte(ivC2S)
	eiv := make([]byte,16)
	c2s := make(multiStream,3)
	for i := range r.Array {
		encryptIV(r.Array[i][:],iv,eiv)
		c2s[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	iv = []byte(ivS2C)
	s2c := make(multiStream,3)
	for i := range r.Array {
		encryptIV(r.Array[i][:],iv,eiv)
		s2c[i],_ = chacha20.NewCipher(r.Array[i][:],eiv)
	}

	return &wrapper{
		clt,
		cipher.StreamReader{c2s,clt},
		cipher.StreamWriter{s2c,clt,nil},
	},nil
}

<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2016 Rick Beton
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package servefiles

import (
	"errors"
	"fmt"
	"log"
	"math/rand"
	"mime"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

// This needs to track the same string in net/http (which is unlikely ever to change)
const indexPage = "index.html"

// Assets sets the options for asset handling. Use AssetHandler to create the handler(s) you need.
type Assets struct {
	// Choose a number greater than zero to strip off some leading segments from the URL path. This helps if
	// you want, say, a sequence number in the URL so that only has the effect of managing far-future cache
	// control. Use zero for default behaviour.
	UnwantedPrefixSegments int

	// The directory where the assets reside.
	AssetPath string

	// Set the expiry duration for assets. This will be set via headers in the response. This should never be
	// negative. Use zero to disable asset caching in clients and proxies.
	MaxAge time.Duration

	// Configurable http.Handler which is called when no matching route is found. If it is not set,
	// http.NotFound is used.
	NotFound http.Handler

	expiryElasticity time.Duration
	timestamp        int64
	timestampExpiry  string
	lock             *sync.Mutex
}

// Type conformance proof
var _ http.Handler = &Assets{}

//-------------------------------------------------------------------------------------------------

// NewAssetHandler creates an Assets value. It cleans the asset path, so use it instead of
// creating Assets values directly.
func NewAssetHandler(assetPath string) *Assets {
	a := &Assets{}
	a.AssetPath = cleanPathAndAppendSlash(assetPath)
	a.lock = &sync.Mutex{}
	return a
}

// StripOff alters the handler to strip off a specified number of segments from the path before
// looking for the matching asset. For example, if StripOff(2) has been applied, the requested
// path "/a/b/c/d/doc.js" would be shortened to "c/d/doc.js".
//
// The returned handler is a new copy of the original one.
func (a Assets) StripOff(unwantedPrefixSegments int) *Assets {
	if unwantedPrefixSegments < 0 {
		panic(errors.New("Negative unwantedPrefixSegments"))
	}
	a.UnwantedPrefixSegments = unwantedPrefixSegments
	return &a
}

// WithMaxAge alters the handler to set the specified max age on the served assets.
//
// The returned handler is a new copy of the original one.
func (a Assets) WithMaxAge(maxAge time.Duration) *Assets {
	if maxAge < 0 {
		panic(errors.New("Negative maxAge"))
	}
	a.MaxAge = maxAge
	return &a
}

// WithNotFound alters the handler so that 404-not found cases are passed to a specified
// handler. Without this, the default handler is the one provided in the net/http package.
//
// The returned handler is a new copy of the original one.
func (a Assets) WithNotFound(notFound http.Handler) *Assets {
	a.NotFound = notFound
	return &a
}

//-------------------------------------------------------------------------------------------------

// Calculate the 'Expires' value using an approximation that reduces unimportant re-calculation.
// We don't need to do this accurately because the 'Cache-Control' maxAge value takes precedence
// anyway. So the value is cached and shared between requests for a short while.
func (a *Assets) expires() string {
	if a.expiryElasticity == 0 {
		a.expiryElasticity = 1 + a.MaxAge/100
	}
	now := time.Now().UTC()
	unix := now.Unix()
	if unix > a.timestamp {
		later := now.Add(a.MaxAge + a.expiryElasticity) // add expiryElasticity to avoid negative expiry
		a.lock.Lock()
		defer a.lock.Unlock()
		// cache the formatted string for one second to avoid repeated formatting
		// race condition is ignored here, but note the order below
		a.timestampExpiry = later.Format(time.RFC1123)
		a.timestamp = unix + int64(a.expiryElasticity)
	}
	return a.timestampExpiry
}

func (a *Assets) removeUnwantedSegments(path string) string {
	//log.Printf("removeUnwantedSegments %s", path)
	for i := a.UnwantedPrefixSegments; i >= 0; i-- {
		slash := strings.IndexByte(path, '/') + 1
		if slash > 0 {
			path = path[slash:]
		}
	}
	return path
}

func listContainsWholeString(header, want string) bool {
	accepted := strings.Split(header, ",")
	for _, encoding := range accepted {
		if strings.TrimSpace(encoding) == want {
			return true
		}
	}
	return false
}

func calculateEtag(d os.FileInfo) string {
	return fmt.Sprintf(`"%x-%x"`, d.ModTime().Unix(), d.Size())
}

func checkPlainResource(resource string, header http.Header) string {
	d, err := os.Stat(resource)
	if err == nil {
		// strong etag because the representation is the original file
		header.Set("ETag", calculateEtag(d))
	}
	return resource
}

func (a *Assets) chooseResource(header http.Header, req *http.Request) (string, int, string) {
	name := a.removeUnwantedSegments(req.URL.Path)
	if name == "" || strings.HasSuffix(name, "/") {
		name += indexPage
	}

	resource := a.AssetPath + name
	gzipped := resource + ".gz"

	if a.MaxAge > 0 {
		header.Set("Expires", a.expires())
		header.Set("Cache-Control", fmt.Sprintf("public, maxAge=%d", a.MaxAge/time.Second))
	}

	d, err := os.Stat(gzipped)
	if err != nil {
		if os.IsNotExist(err) {
			// gzipped does not exist; original might but this gets checked later
			return checkPlainResource(resource, header), 0, ""

		} else if os.IsPermission(err) {
			// incorrectly assembled gzipped asset is treated as an error
			return resource, http.StatusForbidden, "403 Forbidden"
		}

		// Possibly the server is under heavy load and ran out of file descriptors
		backoff := 2 + rand.Int31()%4 // 2–6 seconds to prevent a stampede
		header.Set("Retry-After", strconv.Itoa(int(backoff)))
		log.Printf("Failed to stat %s: %v\n", resource, err)
		return resource, http.StatusServiceUnavailable, "Currently unavailable"
	}

	if d.IsDir() {
		// this odd case is simply passed on to the standard library
		return resource, 0, ""
	}

	// gzipped file exists and is readable
	acceptEncoding, ok := req.Header["Accept-Encoding"]
	if ok {
		acceptGzip := listContainsWholeString(acceptEncoding[0], "gzip")
		if acceptGzip {
			ext := filepath.Ext(resource)
			header.Set("Content-Type", mime.TypeByExtension(ext))
			// the standard library sometimes overrides the content type via sniffing
			header.Set("X-Content-Type-Options", "nosniff")
			header.Set("Content-Encoding", "gzip")
			header.Add("Vary", "Accept-Encoding")
			// weak etag because the representation is not the original file but a compressed variant
			header.Set("ETag", "W/"+calculateEtag(d))
			return gzipped, 0, ""
		}
	}

	// no intervention; the file will be served normally by the standard api
	return checkPlainResource(resource, header), 0, ""
}

// ServeHTTP implements the http.Handler interface.
func (a *Assets) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	resource, code, message := a.chooseResource(w.Header(), req)
	//fmt.Printf("ServeHTTP %s %s %+v -> %d %s\n", req.Method, req.URL.Path, req.Header, code, resource)
	if code >= 400 {
		http.Error(w, message, code)
		return
	}

	if a.NotFound == nil {
		// Conditional requests and content negotiation are handled in ServeFile.
		// Note that req.URL remains unchanged, even if prefix stripping is turned on, because the resource is
		// the only value that matters.
		//fmt.Printf("ServeFile (1) %s %s W:%+v\n", req.Method, req.URL.Path, w.Header())
		http.ServeFile(w, req, resource)

	} else {
		ww := newNo404Writer(w)

		//fmt.Printf("ServeFile (2) %s %s W:%+v\n", req.Method, req.URL.Path, w.Header())
		http.ServeFile(ww, req, resource)

		if ww.Code == http.StatusNotFound {
			// ww has silently dropped the headers and body from the built-in handler in this case,
			// so complete the response using the original handler.
			w.Header().Set("X-Content-Type-Options", "nosniff")
			a.NotFound.ServeHTTP(w, req)
		} else {
			ww.LazyWriteHeaders()
		}
		//fmt.Printf("              WW:%s\n", ww)
	}
}

func cleanPathAndAppendSlash(s string) string {
	clean := path.Clean(s)
	return string(append([]byte(clean), '/'))
}
<commit_msg>clarification of function docs<commit_after>// MIT License
//
// Copyright (c) 2016 Rick Beton
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package servefiles

import (
	"errors"
	"fmt"
	"log"
	"math/rand"
	"mime"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

// This needs to track the same string in net/http (which is unlikely ever to change)
const indexPage = "index.html"

// Assets sets the options for asset handling. Use AssetHandler to create the handler(s) you need.
type Assets struct {
	// Choose a number greater than zero to strip off some leading segments from the URL path. This helps if
	// you want, say, a sequence number in the URL so that only has the effect of managing far-future cache
	// control. Use zero for default behaviour.
	UnwantedPrefixSegments int

	// The directory where the assets reside.
	AssetPath string

	// Set the expiry duration for assets. This will be set via headers in the response. This should never be
	// negative. Use zero to disable asset caching in clients and proxies.
	MaxAge time.Duration

	// Configurable http.Handler which is called when no matching route is found. If it is not set,
	// http.NotFound is used.
	NotFound http.Handler

	expiryElasticity time.Duration
	timestamp        int64
	timestampExpiry  string
	lock             *sync.Mutex
}

// Type conformance proof
var _ http.Handler = &Assets{}

//-------------------------------------------------------------------------------------------------

// NewAssetHandler creates an Assets value. The parameter is the directory containing the asset files;
// this can be absolute or relative to the directory in which the server process is started.
//
// This function cleans (i.e. normalises) the asset path, so use it instead of creating Assets values
// directly.
func NewAssetHandler(assetPath string) *Assets {
	a := &Assets{}
	a.AssetPath = cleanPathAndAppendSlash(assetPath)
	a.lock = &sync.Mutex{}
	return a
}

// StripOff alters the handler to strip off a specified number of segments from the path before
// looking for the matching asset. For example, if StripOff(2) has been applied, the requested
// path "/a/b/c/d/doc.js" would be shortened to "c/d/doc.js".
//
// The returned handler is a new copy of the original one.
func (a Assets) StripOff(unwantedPrefixSegments int) *Assets {
	if unwantedPrefixSegments < 0 {
		panic(errors.New("Negative unwantedPrefixSegments"))
	}
	a.UnwantedPrefixSegments = unwantedPrefixSegments
	return &a
}

// WithMaxAge alters the handler to set the specified max age on the served assets.
//
// The returned handler is a new copy of the original one.
func (a Assets) WithMaxAge(maxAge time.Duration) *Assets {
	if maxAge < 0 {
		panic(errors.New("Negative maxAge"))
	}
	a.MaxAge = maxAge
	return &a
}

// WithNotFound alters the handler so that 404-not found cases are passed to a specified
// handler. Without this, the default handler is the one provided in the net/http package.
//
// The returned handler is a new copy of the original one.
func (a Assets) WithNotFound(notFound http.Handler) *Assets {
	a.NotFound = notFound
	return &a
}

//-------------------------------------------------------------------------------------------------

// Calculate the 'Expires' value using an approximation that reduces unimportant re-calculation.
// We don't need to do this accurately because the 'Cache-Control' maxAge value takes precedence
// anyway. So the value is cached and shared between requests for a short while.
func (a *Assets) expires() string {
	if a.expiryElasticity == 0 {
		a.expiryElasticity = 1 + a.MaxAge/100
	}
	now := time.Now().UTC()
	unix := now.Unix()
	if unix > a.timestamp {
		later := now.Add(a.MaxAge + a.expiryElasticity) // add expiryElasticity to avoid negative expiry
		a.lock.Lock()
		defer a.lock.Unlock()
		// cache the formatted string for one second to avoid repeated formatting
		// race condition is ignored here, but note the order below
		a.timestampExpiry = later.Format(time.RFC1123)
		a.timestamp = unix + int64(a.expiryElasticity)
	}
	return a.timestampExpiry
}

func (a *Assets) removeUnwantedSegments(path string) string {
	//log.Printf("removeUnwantedSegments %s", path)
	for i := a.UnwantedPrefixSegments; i >= 0; i-- {
		slash := strings.IndexByte(path, '/') + 1
		if slash > 0 {
			path = path[slash:]
		}
	}
	return path
}

func listContainsWholeString(header, want string) bool {
	accepted := strings.Split(header, ",")
	for _, encoding := range accepted {
		if strings.TrimSpace(encoding) == want {
			return true
		}
	}
	return false
}

func calculateEtag(d os.FileInfo) string {
	return fmt.Sprintf(`"%x-%x"`, d.ModTime().Unix(), d.Size())
}

func checkPlainResource(resource string, header http.Header) string {
	d, err := os.Stat(resource)
	if err == nil {
		// strong etag because the representation is the original file
		header.Set("ETag", calculateEtag(d))
	}
	return resource
}

func (a *Assets) chooseResource(header http.Header, req *http.Request) (string, int, string) {
	name := a.removeUnwantedSegments(req.URL.Path)
	if name == "" || strings.HasSuffix(name, "/") {
		name += indexPage
	}

	resource := a.AssetPath + name
	gzipped := resource + ".gz"

	if a.MaxAge > 0 {
		header.Set("Expires", a.expires())
		header.Set("Cache-Control", fmt.Sprintf("public, maxAge=%d", a.MaxAge/time.Second))
	}

	d, err := os.Stat(gzipped)
	if err != nil {
		if os.IsNotExist(err) {
			// gzipped does not exist; original might but this gets checked later
			return checkPlainResource(resource, header), 0, ""

		} else if os.IsPermission(err) {
			// incorrectly assembled gzipped asset is treated as an error
			return resource, http.StatusForbidden, "403 Forbidden"
		}

		// Possibly the server is under heavy load and ran out of file descriptors
		backoff := 2 + rand.Int31()%4 // 2–6 seconds to prevent a stampede
		header.Set("Retry-After", strconv.Itoa(int(backoff)))
		log.Printf("Failed to stat %s: %v\n", resource, err)
		return resource, http.StatusServiceUnavailable, "Currently unavailable"
	}

	if d.IsDir() {
		// this odd case is simply passed on to the standard library
		return resource, 0, ""
	}

	// gzipped file exists and is readable
	acceptEncoding, ok := req.Header["Accept-Encoding"]
	if ok {
		acceptGzip := listContainsWholeString(acceptEncoding[0], "gzip")
		if acceptGzip {
			ext := filepath.Ext(resource)
			header.Set("Content-Type", mime.TypeByExtension(ext))
			// the standard library sometimes overrides the content type via sniffing
			header.Set("X-Content-Type-Options", "nosniff")
			header.Set("Content-Encoding", "gzip")
			header.Add("Vary", "Accept-Encoding")
			// weak etag because the representation is not the original file but a compressed variant
			header.Set("ETag", "W/"+calculateEtag(d))
			return gzipped, 0, ""
		}
	}

	// no intervention; the file will be served normally by the standard api
	return checkPlainResource(resource, header), 0, ""
}

// ServeHTTP implements the http.Handler interface.
func (a *Assets) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	resource, code, message := a.chooseResource(w.Header(), req)
	//fmt.Printf("ServeHTTP %s %s %+v -> %d %s\n", req.Method, req.URL.Path, req.Header, code, resource)
	if code >= 400 {
		http.Error(w, message, code)
		return
	}

	if a.NotFound == nil {
		// Conditional requests and content negotiation are handled in ServeFile.
		// Note that req.URL remains unchanged, even if prefix stripping is turned on, because the resource is
		// the only value that matters.
		//fmt.Printf("ServeFile (1) %s %s W:%+v\n", req.Method, req.URL.Path, w.Header())
		http.ServeFile(w, req, resource)

	} else {
		ww := newNo404Writer(w)

		//fmt.Printf("ServeFile (2) %s %s W:%+v\n", req.Method, req.URL.Path, w.Header())
		http.ServeFile(ww, req, resource)

		if ww.Code == http.StatusNotFound {
			// ww has silently dropped the headers and body from the built-in handler in this case,
			// so complete the response using the original handler.
			w.Header().Set("X-Content-Type-Options", "nosniff")
			a.NotFound.ServeHTTP(w, req)
		} else {
			ww.LazyWriteHeaders()
		}
		//fmt.Printf("              WW:%s\n", ww)
	}
}

func cleanPathAndAppendSlash(s string) string {
	clean := path.Clean(s)
	return string(append([]byte(clean), '/'))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"time"
)

type Params struct {
	Customers             int
	Seats                 int
	Customer_delay        int
	Customer_return_delay int
	Barber_delay          int
}

func serve_customer(customer_id int, delay int, customer_served chan int) {
	time.Sleep(time.Duration(delay) * time.Millisecond)
	customer_served <- customer_id
	fmt.Printf("BARBER: Customer %d served.\n", customer_id)
}

func barber(delay int, seats chan int, customer_served chan int) {
	for {
		select {
		case customer_id := <-seats:
			serve_customer(customer_id, delay, customer_served)
		default:
			fmt.Printf("BARBER: Sleeping.\n")
			customer_id := <-seats
			fmt.Printf("BARBER: Woken up by customer %d.\n", customer_id)
			serve_customer(customer_id, delay, customer_served)
		}
	}
}

func customer(id int, return_delay int, seats chan int, customer_served chan int) {
	var serviced bool = false
	for serviced != true {
		select {
		case seats <- id:
			fmt.Printf("CUSTOMER %d: Entering barber shop.\n", id)
			finished_customer := -1
			for finished_customer != id {
				finished_customer = <-customer_served
			}
			fmt.Printf("CUSTOMER %d: Leaving barber shop happy.\n", id)
			serviced = true
		default:
			fmt.Printf("CUSTOMER %d: Leaving barber shop unserviced.\n", id)
			time.Sleep(time.Duration(return_delay) * time.Millisecond)
		}
	}
}

func read_params() *Params {
	var params *Params = new(Params)
	flag.IntVar(&params.Customers, "customers", 10, "number of customers to come to barber shop")
	flag.IntVar(&params.Seats, "seats", 3, "number of seats in barber shop")
	flag.IntVar(&params.Customer_delay, "customers_delay", 5, "time between customers incoming to shop")
	flag.IntVar(&params.Customer_return_delay, "customers_return_delay", 20, "time between customers' retry if the barber shop is full")
	flag.IntVar(&params.Barber_delay, "barber_delay", 15, "time of barber working on customer")

	flag.Parse()
	return params
}

func main() {
	var params *Params = read_params()

	seats := make(chan int, params.Seats)
	customer_served := make(chan int)

	go barber(params.Barber_delay, seats, customer_served)
	for id := 0; id < params.Customers; id++ {
		go customer(id, params.Customer_return_delay, seats, customer_served)
		time.Sleep(time.Duration(params.Customer_delay) * time.Millisecond)
	}

	time.Sleep(500 * time.Millisecond)
}
<commit_msg>Barber leaves shop after all customers<commit_after>package main

import (
	"flag"
	"fmt"
	"time"
)

func serve_customer(customer_id int, delay int, customer_served chan int) {
	time.Sleep(time.Duration(delay) * time.Millisecond)
	customer_served <- customer_id
	fmt.Printf("BARBER: Customer %d served.\n", customer_id)
}

func barber(delay int, seats chan int, customer_served chan int, going_home chan int, customer_to_serve int) {
	var customer_id int = -1
	var number_of_customers_served int = 0
	for {
		select {
		case customer_id = <-seats:
		default:
			fmt.Printf("BARBER: Sleeping.\n")
			customer_id = <-seats
			fmt.Printf("BARBER: Woken up by customer %d.\n", customer_id)
		}
		serve_customer(customer_id, delay, customer_served)
		number_of_customers_served++
		if number_of_customers_served == customer_to_serve {
			break
		}
	}
	fmt.Printf("BARBER: Closing shop, going home.\n")
	going_home <- 1
}

func customer(id int, return_delay int, seats chan int, customer_served chan int) {
	var serviced bool = false
	for serviced != true {
		select {
		case seats <- id:
			fmt.Printf("CUSTOMER %d: Entering barber shop.\n", id)
			finished_customer := -1
			for finished_customer != id {
				finished_customer = <-customer_served
			}
			fmt.Printf("CUSTOMER %d: Leaving barber shop happy.\n", id)
			serviced = true
		default:
			fmt.Printf("CUSTOMER %d: Leaving barber shop unserviced.\n", id)
			time.Sleep(time.Duration(return_delay) * time.Millisecond)
		}
	}
}

type Params struct {
	Customers             int
	Seats                 int
	Customer_delay        int
	Customer_return_delay int
	Barber_delay          int
}

func read_params() *Params {
	var params *Params = new(Params)
	flag.IntVar(&params.Customers, "customers", 10, "number of customers to come to barber shop")
	flag.IntVar(&params.Seats, "seats", 3, "number of seats in barber shop")
	flag.IntVar(&params.Customer_delay, "customers_delay", 5, "time between customers incoming to shop")
	flag.IntVar(&params.Customer_return_delay, "customers_return_delay", 20, "time between customers' retry if the barber shop is full")
	flag.IntVar(&params.Barber_delay, "barber_delay", 15, "time of barber working on customer")

	flag.Parse()
	return params
}

func main() {
	var params *Params = read_params()

	seats := make(chan int, params.Seats)
	customer_served := make(chan int)
	barber_going_home := make(chan int)

	go barber(params.Barber_delay, seats, customer_served, barber_going_home, params.Customers)
	for id := 0; id < params.Customers; id++ {
		go customer(id, params.Customer_return_delay, seats, customer_served)
		time.Sleep(time.Duration(params.Customer_delay) * time.Millisecond)
	}
	<-barber_going_home
}
<|endoftext|>


<commit_before>package wtpolicy

import (
	"errors"
	"fmt"

	"github.com/btcsuite/btcutil"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/watchtower/blob"
)

const (
	// RewardScale is the denominator applied when computing the
	// proportional component for a tower's reward output. The current scale
	// is in millionths.
	RewardScale = 1000000

	// DefaultMaxUpdates specifies the number of encrypted blobs a client
	// can send to the tower in a single session.
	DefaultMaxUpdates = 1024

	// DefaultRewardRate specifies the fraction of the channel that the
	// tower takes if it successfully sweeps a breach. The value is
	// expressed in millionths of the channel capacity.
	DefaultRewardRate = 10000

	// DefaultSweepFeeRate specifies the fee rate used to construct justice
	// transactions. The value is expressed in satoshis per kilo-weight.
	DefaultSweepFeeRate = 3000
)

var (
	// ErrFeeExceedsInputs signals that the total input value of breaching
	// commitment txn is insufficient to cover the fees required to sweep
	// it.
	ErrFeeExceedsInputs = errors.New("sweep fee exceeds input value")

	// ErrRewardExceedsInputs signals that the reward given to the tower (in
	// addition to the transaction fees) is more than the input amount.
	ErrRewardExceedsInputs = errors.New("reward amount exceeds input value")

	// ErrCreatesDust signals that the session's policy would create a dust
	// output for the victim.
	ErrCreatesDust = errors.New("justice transaction creates dust at fee rate")
)

// DefaultPolicy returns a Policy containing the default parameters that can be
// used by clients or servers.
func DefaultPolicy() Policy {
	return Policy{
		BlobType:   blob.TypeDefault,
		MaxUpdates: DefaultMaxUpdates,
		RewardRate: DefaultRewardRate,
		SweepFeeRate: lnwallet.SatPerKWeight(
			DefaultSweepFeeRate,
		),
	}
}

// Policy defines the negotiated parameters for a session between a client and
// server. The parameters specify the format of encrypted blobs sent to the
// tower, the reward schedule for the tower, and the number of encrypted blobs a
// client can send in one session.
type Policy struct {
	// BlobType specifies the blob format that must be used by all updates sent
	// under the session key used to negotiate this session.
	BlobType blob.Type

	// MaxUpdates is the maximum number of updates the watchtower will honor
	// for this session.
	MaxUpdates uint16

	// RewardBase is the fixed amount allocated to the tower when the
	// policy's blob type specifies a reward for the tower. This is taken
	// before adding the proportional reward.
	RewardBase uint32

	// RewardRate is the fraction of the total balance of the revoked
	// commitment that the watchtower is entitled to. This value is
	// expressed in millionths of the total balance.
	RewardRate uint32

	// SweepFeeRate expresses the intended fee rate to be used when
	// constructing the justice transaction. All sweep transactions created
	// for this session must use this value during construction, and the
	// signatures must implicitly commit to the resulting output values.
	SweepFeeRate lnwallet.SatPerKWeight
}

// String returns a human-readable description of the current policy.
func (p Policy) String() string {
	return fmt.Sprintf("(blob-type=%b max-updates=%d reward-rate=%d "+
		"sweep-fee-rate=%d)", p.BlobType, p.MaxUpdates, p.RewardRate,
		p.SweepFeeRate)
}

// ComputeAltruistOutput computes the lone output value of a justice transaction
// that pays no reward to the tower. The value is computed using the weight of
// of the justice transaction and subtracting an amount that satisfies the
// policy's fee rate.
func (p *Policy) ComputeAltruistOutput(totalAmt btcutil.Amount,
	txWeight int64) (btcutil.Amount, error) {

	txFee := p.SweepFeeRate.FeeForWeight(txWeight)
	if txFee > totalAmt {
		return 0, ErrFeeExceedsInputs
	}

	sweepAmt := totalAmt - txFee

	// TODO(conner): replace w/ configurable dust limit
	dustLimit := lnwallet.DefaultDustLimit()

	// Check that the created outputs won't be dusty.
	if sweepAmt <= dustLimit {
		return 0, ErrCreatesDust
	}

	return sweepAmt, nil
}

// ComputeRewardOutputs splits the total funds in a breaching commitment
// transaction between the victim and the tower, according to the sweep fee rate
// and reward rate. The reward to he tower is substracted first, before
// splitting the remaining balance amongst the victim and fees.
func (p *Policy) ComputeRewardOutputs(totalAmt btcutil.Amount,
	txWeight int64) (btcutil.Amount, btcutil.Amount, error) {

	txFee := p.SweepFeeRate.FeeForWeight(txWeight)
	if txFee > totalAmt {
		return 0, 0, ErrFeeExceedsInputs
	}

	// Apply the reward rate to the remaining total, specified in millionths
	// of the available balance.
	rewardAmt := ComputeRewardAmount(totalAmt, p.RewardBase, p.RewardRate)
	if rewardAmt+txFee > totalAmt {
		return 0, 0, ErrRewardExceedsInputs
	}

	// The sweep amount for the victim constitutes the remainder of the
	// input value.
	sweepAmt := totalAmt - rewardAmt - txFee

	// TODO(conner): replace w/ configurable dust limit
	dustLimit := lnwallet.DefaultDustLimit()

	// Check that the created outputs won't be dusty.
	if sweepAmt <= dustLimit {
		return 0, 0, ErrCreatesDust
	}

	return sweepAmt, rewardAmt, nil
}

// ComputeRewardAmount computes the amount rewarded to the tower using the
// proportional rate expressed in millionths, e.g. one million is equivalent to
// one hundred percent of the total amount. The amount is rounded up to the
// nearest whole satoshi.
func ComputeRewardAmount(total btcutil.Amount, base, rate uint32) btcutil.Amount {
	rewardBase := btcutil.Amount(base)
	rewardRate := btcutil.Amount(rate)

	// If the base reward exceeds the total, there is no more funds left
	// from which to derive the proportional fee. We simply return the base,
	// the caller should detect that this exceeds the total amount input.
	if rewardBase > total {
		return rewardBase
	}

	// Otherwise, subtract the base from the total and compute the
	// proportional reward from the remaining total.
	afterBase := total - rewardBase
	proportional := (afterBase*rewardRate + RewardScale - 1) / RewardScale

	return rewardBase + proportional
}
<commit_msg>watchtower/wtpolicy/policy: add ComputeJusticeTxOuts<commit_after>package wtpolicy

import (
	"errors"
	"fmt"

	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
	"github.com/lightningnetwork/lnd/lnwallet"
	"github.com/lightningnetwork/lnd/watchtower/blob"
)

const (
	// RewardScale is the denominator applied when computing the
	// proportional component for a tower's reward output. The current scale
	// is in millionths.
	RewardScale = 1000000

	// DefaultMaxUpdates specifies the number of encrypted blobs a client
	// can send to the tower in a single session.
	DefaultMaxUpdates = 1024

	// DefaultRewardRate specifies the fraction of the channel that the
	// tower takes if it successfully sweeps a breach. The value is
	// expressed in millionths of the channel capacity.
	DefaultRewardRate = 10000

	// DefaultSweepFeeRate specifies the fee rate used to construct justice
	// transactions. The value is expressed in satoshis per kilo-weight.
	DefaultSweepFeeRate = 3000
)

var (
	// ErrFeeExceedsInputs signals that the total input value of breaching
	// commitment txn is insufficient to cover the fees required to sweep
	// it.
	ErrFeeExceedsInputs = errors.New("sweep fee exceeds input value")

	// ErrRewardExceedsInputs signals that the reward given to the tower (in
	// addition to the transaction fees) is more than the input amount.
	ErrRewardExceedsInputs = errors.New("reward amount exceeds input value")

	// ErrCreatesDust signals that the session's policy would create a dust
	// output for the victim.
	ErrCreatesDust = errors.New("justice transaction creates dust at fee rate")
)

// DefaultPolicy returns a Policy containing the default parameters that can be
// used by clients or servers.
func DefaultPolicy() Policy {
	return Policy{
		BlobType:   blob.TypeDefault,
		MaxUpdates: DefaultMaxUpdates,
		RewardRate: DefaultRewardRate,
		SweepFeeRate: lnwallet.SatPerKWeight(
			DefaultSweepFeeRate,
		),
	}
}

// Policy defines the negotiated parameters for a session between a client and
// server. The parameters specify the format of encrypted blobs sent to the
// tower, the reward schedule for the tower, and the number of encrypted blobs a
// client can send in one session.
type Policy struct {
	// BlobType specifies the blob format that must be used by all updates sent
	// under the session key used to negotiate this session.
	BlobType blob.Type

	// MaxUpdates is the maximum number of updates the watchtower will honor
	// for this session.
	MaxUpdates uint16

	// RewardBase is the fixed amount allocated to the tower when the
	// policy's blob type specifies a reward for the tower. This is taken
	// before adding the proportional reward.
	RewardBase uint32

	// RewardRate is the fraction of the total balance of the revoked
	// commitment that the watchtower is entitled to. This value is
	// expressed in millionths of the total balance.
	RewardRate uint32

	// SweepFeeRate expresses the intended fee rate to be used when
	// constructing the justice transaction. All sweep transactions created
	// for this session must use this value during construction, and the
	// signatures must implicitly commit to the resulting output values.
	SweepFeeRate lnwallet.SatPerKWeight
}

// String returns a human-readable description of the current policy.
func (p Policy) String() string {
	return fmt.Sprintf("(blob-type=%b max-updates=%d reward-rate=%d "+
		"sweep-fee-rate=%d)", p.BlobType, p.MaxUpdates, p.RewardRate,
		p.SweepFeeRate)
}

// ComputeAltruistOutput computes the lone output value of a justice transaction
// that pays no reward to the tower. The value is computed using the weight of
// of the justice transaction and subtracting an amount that satisfies the
// policy's fee rate.
func (p *Policy) ComputeAltruistOutput(totalAmt btcutil.Amount,
	txWeight int64) (btcutil.Amount, error) {

	txFee := p.SweepFeeRate.FeeForWeight(txWeight)
	if txFee > totalAmt {
		return 0, ErrFeeExceedsInputs
	}

	sweepAmt := totalAmt - txFee

	// TODO(conner): replace w/ configurable dust limit
	dustLimit := lnwallet.DefaultDustLimit()

	// Check that the created outputs won't be dusty.
	if sweepAmt <= dustLimit {
		return 0, ErrCreatesDust
	}

	return sweepAmt, nil
}

// ComputeRewardOutputs splits the total funds in a breaching commitment
// transaction between the victim and the tower, according to the sweep fee rate
// and reward rate. The reward to he tower is substracted first, before
// splitting the remaining balance amongst the victim and fees.
func (p *Policy) ComputeRewardOutputs(totalAmt btcutil.Amount,
	txWeight int64) (btcutil.Amount, btcutil.Amount, error) {

	txFee := p.SweepFeeRate.FeeForWeight(txWeight)
	if txFee > totalAmt {
		return 0, 0, ErrFeeExceedsInputs
	}

	// Apply the reward rate to the remaining total, specified in millionths
	// of the available balance.
	rewardAmt := ComputeRewardAmount(totalAmt, p.RewardBase, p.RewardRate)
	if rewardAmt+txFee > totalAmt {
		return 0, 0, ErrRewardExceedsInputs
	}

	// The sweep amount for the victim constitutes the remainder of the
	// input value.
	sweepAmt := totalAmt - rewardAmt - txFee

	// TODO(conner): replace w/ configurable dust limit
	dustLimit := lnwallet.DefaultDustLimit()

	// Check that the created outputs won't be dusty.
	if sweepAmt <= dustLimit {
		return 0, 0, ErrCreatesDust
	}

	return sweepAmt, rewardAmt, nil
}

// ComputeRewardAmount computes the amount rewarded to the tower using the
// proportional rate expressed in millionths, e.g. one million is equivalent to
// one hundred percent of the total amount. The amount is rounded up to the
// nearest whole satoshi.
func ComputeRewardAmount(total btcutil.Amount, base, rate uint32) btcutil.Amount {
	rewardBase := btcutil.Amount(base)
	rewardRate := btcutil.Amount(rate)

	// If the base reward exceeds the total, there is no more funds left
	// from which to derive the proportional fee. We simply return the base,
	// the caller should detect that this exceeds the total amount input.
	if rewardBase > total {
		return rewardBase
	}

	// Otherwise, subtract the base from the total and compute the
	// proportional reward from the remaining total.
	afterBase := total - rewardBase
	proportional := (afterBase*rewardRate + RewardScale - 1) / RewardScale

	return rewardBase + proportional
}

// ComputeJusticeTxOuts constructs the justice transaction outputs for the given
// policy. If the policy specifies a reward for the tower, there will be two
// outputs paying to the victim and the tower. Otherwise there will be a single
// output sweeping funds back to the victim. The totalAmt should be the sum of
// any inputs used in the transaction. The passed txWeight should include the
// weight of the outputs for the justice transaction, which is dependent on
// whether the justice transaction has a reward. The sweepPkScript should be the
// pkScript of the victim to which funds will be recovered. The rewardPkScript
// is the pkScript of the tower where its reward will be deposited, and will be
// ignored if the blob type does not specify a reward.
func (p *Policy) ComputeJusticeTxOuts(totalAmt btcutil.Amount, txWeight int64,
	sweepPkScript, rewardPkScript []byte) ([]*wire.TxOut, error) {

	var outputs []*wire.TxOut

	// If the policy specifies a reward for the tower, compute a split of
	// the funds based on the policy's parameters. Otherwise, we will use an
	// the altruist output computation and sweep as much of the funds back
	// to the victim as possible.
	if p.BlobType.Has(blob.FlagReward) {
		// Using the total input amount and the transaction's weight,
		// compute the sweep and reward amounts. This corresponds to the
		// amount returned to the victim and the amount paid to the
		// tower, respectively. To do so, the required transaction fee
		// is subtracted from the total, and the remaining amount is
		// divided according to the prenegotiated reward rate from the
		// client's session info.
		sweepAmt, rewardAmt, err := p.ComputeRewardOutputs(
			totalAmt, txWeight,
		)
		if err != nil {
			return nil, err
		}

		// Add the sweep and reward outputs to the list of txouts.
		outputs = append(outputs, &wire.TxOut{
			PkScript: sweepPkScript,
			Value:    int64(sweepAmt),
		})
		outputs = append(outputs, &wire.TxOut{
			PkScript: rewardPkScript,
			Value:    int64(rewardAmt),
		})
	} else {
		// Using the total input amount and the transaction's weight,
		// compute the sweep amount, which corresponds to the amount
		// returned to the victim. To do so, the required transaction
		// fee is subtracted from the total input amount.
		sweepAmt, err := p.ComputeAltruistOutput(
			totalAmt, txWeight,
		)
		if err != nil {
			return nil, err
		}

		// Add the sweep output to the list of txouts.
		outputs = append(outputs, &wire.TxOut{
			PkScript: sweepPkScript,
			Value:    int64(sweepAmt),
		})
	}

	return outputs, nil
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 CoreOS, 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 rafthttp

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

	"github.com/coreos/etcd/etcdserver/stats"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/etcd/raft/raftpb"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
)

const (
	streamBufSize = 4096
)

type WriteFlusher interface {
	io.Writer
	http.Flusher
}

type streamServer struct {
	to   types.ID
	term uint64
	fs   *stats.FollowerStats
	q    chan []raftpb.Entry
	done chan struct{}
}

func startStreamServer(w WriteFlusher, to types.ID, term uint64, fs *stats.FollowerStats) *streamServer {
	s := &streamServer{
		to:   to,
		term: term,
		fs:   fs,
		q:    make(chan []raftpb.Entry, streamBufSize),
		done: make(chan struct{}),
	}
	go s.handle(w)
	log.Printf("rafthttp: starting server stream to %s at term %d", to, term)
	return s
}

func (s *streamServer) send(ents []raftpb.Entry) error {
	select {
	case <-s.done:
		return fmt.Errorf("stopped")
	default:
	}
	select {
	case s.q <- ents:
		return nil
	default:
		log.Printf("rafthttp: maximum number of streams %s reached", s.to)
		return fmt.Errorf("maximum number of streams reached")
	}
}

func (s *streamServer) stop() {
	close(s.q)
	<-s.done
}

func (s *streamServer) stopNotify() <-chan struct{} { return s.done }

func (s *streamServer) handle(w WriteFlusher) {
	defer func() {
		close(s.done)
		log.Printf("rafthttp: server streaming to %s at term %d has been stopped", s.to, s.term)
	}()

	ew := &entryWriter{w: w}
	for ents := range s.q {
		start := time.Now()
		if err := ew.writeEntries(ents); err != nil {
			log.Printf("rafthttp: encountered error writing to server log stream: %v", err)
			return
		}
		w.Flush()
		s.fs.Succ(time.Since(start))
	}
}

type streamClient struct {
	id   types.ID
	to   types.ID
	term uint64
	p    Processor

	closer io.Closer
	done   chan struct{}
}

func newStreamClient(id, to types.ID, term uint64, p Processor) *streamClient {
	return &streamClient{
		id:   id,
		to:   to,
		term: term,
		p:    p,
		done: make(chan struct{}),
	}
}

// Dial dials to the remote url, and sends streaming request. If it succeeds,
// it returns nil error, and the caller should call Handle function to keep
// receiving appendEntry messages.
func (s *streamClient) start(tr http.RoundTripper, u string, cid types.ID) error {
	uu, err := url.Parse(u)
	if err != nil {
		return fmt.Errorf("parse url %s error: %v", u, err)
	}
	uu.Path = path.Join(RaftStreamPrefix, s.id.String())
	req, err := http.NewRequest("GET", uu.String(), nil)
	if err != nil {
		return fmt.Errorf("new request to %s error: %v", u, err)
	}
	req.Header.Set("X-Etcd-Cluster-ID", cid.String())
	req.Header.Set("X-Raft-To", s.to.String())
	req.Header.Set("X-Raft-Term", strconv.FormatUint(s.term, 10))
	resp, err := tr.RoundTrip(req)
	if err != nil {
		return fmt.Errorf("error posting to %q: %v", u, err)
	}
	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return fmt.Errorf("unhandled http status %d", resp.StatusCode)
	}
	s.closer = resp.Body
	go s.handle(resp.Body)
	log.Printf("rafthttp: starting client stream to %s at term %d", s.to, s.term)
	return nil
}

func (s *streamClient) stop() {
	s.closer.Close()
	<-s.done
}

func (s *streamClient) isStopped() bool {
	select {
	case <-s.done:
		return true
	default:
		return false
	}
}

func (s *streamClient) handle(r io.Reader) {
	defer func() {
		close(s.done)
		log.Printf("rafthttp: client streaming to %s at term %d is been stopped", s.to, s.term)
	}()

	er := &entryReader{r: r}
	for {
		ents, err := er.readEntries()
		if err != nil {
			if err != io.EOF {
				log.Printf("rafthttp: encountered error reading the client log stream: %v", err)
			}
			return
		}
		// Considering Commit in MsgApp is not recovered, zero-entry appendEntry
		// messages have no use to raft state machine. Drop it here because
		// we don't have easy way to recover its Index easily.
		if len(ents) == 0 {
			continue
		}
		// The commit index field in appendEntry message is not recovered.
		// The follower updates its commit index through heartbeat.
		msg := raftpb.Message{
			Type:    raftpb.MsgApp,
			From:    uint64(s.to),
			To:      uint64(s.id),
			Term:    s.term,
			LogTerm: s.term,
			Index:   ents[0].Index - 1,
			Entries: ents,
		}
		if err := s.p.Process(context.TODO(), msg); err != nil {
			log.Printf("rafthttp: process raft message error: %v", err)
			return
		}
	}
}

func shouldInitStream(m raftpb.Message) bool {
	return m.Type == raftpb.MsgAppResp && m.Reject == false
}

func canUseStream(m raftpb.Message) bool {
	return m.Type == raftpb.MsgApp && m.Index > 0 && m.Term == m.LogTerm
}
<commit_msg>rafthttp: feedback<commit_after>/*
   Copyright 2014 CoreOS, 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 rafthttp

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

	"github.com/coreos/etcd/etcdserver/stats"
	"github.com/coreos/etcd/pkg/types"
	"github.com/coreos/etcd/raft/raftpb"

	"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
)

const (
	streamBufSize = 4096
)

type WriteFlusher interface {
	io.Writer
	http.Flusher
}

type streamServer struct {
	to   types.ID
	term uint64
	fs   *stats.FollowerStats
	q    chan []raftpb.Entry
	done chan struct{}
}

func startStreamServer(w WriteFlusher, to types.ID, term uint64, fs *stats.FollowerStats) *streamServer {
	s := &streamServer{
		to:   to,
		term: term,
		fs:   fs,
		q:    make(chan []raftpb.Entry, streamBufSize),
		done: make(chan struct{}),
	}
	go s.handle(w)
	log.Printf("rafthttp: starting server stream to %s at term %d", to, term)
	return s
}

func (s *streamServer) send(ents []raftpb.Entry) error {
	select {
	case <-s.done:
		return fmt.Errorf("stopped")
	default:
	}
	select {
	case s.q <- ents:
		return nil
	default:
		log.Printf("rafthttp: maximum number of stream buffer entries to %d has been reached", s.to)
		return fmt.Errorf("maximum number of stream buffer entries has been reached")
	}
}

func (s *streamServer) stop() {
	close(s.q)
	<-s.done
}

func (s *streamServer) stopNotify() <-chan struct{} { return s.done }

func (s *streamServer) handle(w WriteFlusher) {
	defer func() {
		close(s.done)
		log.Printf("rafthttp: server streaming to %s at term %d has been stopped", s.to, s.term)
	}()

	ew := &entryWriter{w: w}
	for ents := range s.q {
		start := time.Now()
		if err := ew.writeEntries(ents); err != nil {
			log.Printf("rafthttp: encountered error writing to server log stream: %v", err)
			return
		}
		w.Flush()
		s.fs.Succ(time.Since(start))
	}
}

type streamClient struct {
	id   types.ID
	to   types.ID
	term uint64
	p    Processor

	closer io.Closer
	done   chan struct{}
}

func newStreamClient(id, to types.ID, term uint64, p Processor) *streamClient {
	return &streamClient{
		id:   id,
		to:   to,
		term: term,
		p:    p,
		done: make(chan struct{}),
	}
}

// Dial dials to the remote url, and sends streaming request. If it succeeds,
// it returns nil error, and the caller should call Handle function to keep
// receiving appendEntry messages.
func (s *streamClient) start(tr http.RoundTripper, u string, cid types.ID) error {
	uu, err := url.Parse(u)
	if err != nil {
		return fmt.Errorf("parse url %s error: %v", u, err)
	}
	uu.Path = path.Join(RaftStreamPrefix, s.id.String())
	req, err := http.NewRequest("GET", uu.String(), nil)
	if err != nil {
		return fmt.Errorf("new request to %s error: %v", u, err)
	}
	req.Header.Set("X-Etcd-Cluster-ID", cid.String())
	req.Header.Set("X-Raft-To", s.to.String())
	req.Header.Set("X-Raft-Term", strconv.FormatUint(s.term, 10))
	resp, err := tr.RoundTrip(req)
	if err != nil {
		return fmt.Errorf("error posting to %q: %v", u, err)
	}
	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return fmt.Errorf("unhandled http status %d", resp.StatusCode)
	}
	s.closer = resp.Body
	go s.handle(resp.Body)
	log.Printf("rafthttp: starting client stream to %s at term %d", s.to, s.term)
	return nil
}

func (s *streamClient) stop() {
	s.closer.Close()
	<-s.done
}

func (s *streamClient) isStopped() bool {
	select {
	case <-s.done:
		return true
	default:
		return false
	}
}

func (s *streamClient) handle(r io.Reader) {
	defer func() {
		close(s.done)
		log.Printf("rafthttp: client streaming to %s at term %d has been stopped", s.to, s.term)
	}()

	er := &entryReader{r: r}
	for {
		ents, err := er.readEntries()
		if err != nil {
			if err != io.EOF {
				log.Printf("rafthttp: encountered error reading the client log stream: %v", err)
			}
			return
		}
		// Considering Commit in MsgApp is not recovered, zero-entry appendEntry
		// messages have no use to raft state machine. Drop it here because
		// we don't have easy way to recover its Index easily.
		if len(ents) == 0 {
			continue
		}
		// The commit index field in appendEntry message is not recovered.
		// The follower updates its commit index through heartbeat.
		msg := raftpb.Message{
			Type:    raftpb.MsgApp,
			From:    uint64(s.to),
			To:      uint64(s.id),
			Term:    s.term,
			LogTerm: s.term,
			Index:   ents[0].Index - 1,
			Entries: ents,
		}
		if err := s.p.Process(context.TODO(), msg); err != nil {
			log.Printf("rafthttp: process raft message error: %v", err)
			return
		}
	}
}

func shouldInitStream(m raftpb.Message) bool {
	return m.Type == raftpb.MsgAppResp && m.Reject == false
}

func canUseStream(m raftpb.Message) bool {
	return m.Type == raftpb.MsgApp && m.Index > 0 && m.Term == m.LogTerm
}
<|endoftext|>


<commit_before>package object

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"encoding/xml"
	"github.com/TShadwell/jsarray"
	htmltemplate "html/template"
	"log"
	"net/http"
	"path"
	texttemplate "text/template"
)

type ContentMarshaler map[MediaType]MarshalFunc

type MarshalFunc func(v interface{}, m MediaType,
	params map[string]string) (data []byte, contentType string, err error)

//HTMLTemplate returns a MarshalFunc that executes the data on template `t` using the html/template
//package
func HTMLTemplate(t *htmltemplate.Template) MarshalFunc {
	return func(v interface{}, _ MediaType,
		_ map[string]string) (data []byte, contentType string, err error) {
		contentType = "text/html;charset=utf8"
		var bf bytes.Buffer
		err = t.Execute(&bf, v)
		if err != nil {
			return
		}
		data = bf.Bytes()
		return
	}
}

//TextTemplate returns a MarshalFunc that executes the data on template `t` using the text/template
//package.
func TextTemplate(t *texttemplate.Template) MarshalFunc {
	return func(v interface{}, _ MediaType,
		_ map[string]string) (data []byte, contentType string, err error) {
		contentType = "text/plain;charset=utf8"
		var bf bytes.Buffer
		err = t.Execute(&bf, v)
		if err != nil {
			return
		}
		data = bf.Bytes()
		return
	}
}

var Json MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {
	contentType = "application/json;charset=utf8"
	data, err = json.Marshal(v)

	return
}

var Xml MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {

	contentType = "application/xml"
	data, err = xml.Marshal(v)
	return
}

var nullbytes = []byte("null")

//See github.com/TShadwell/jsarray for details.
var JsonArray MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {

	contentType = "application/json"
	data, err = jsarray.Marshal(v)
	return
}

var plain MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) ([]byte, string, error) {
	return []byte(v.(string)), "text/plain", nil
}

var Gob MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {

	contentType = "application/gob"
	var buf bytes.Buffer
	err = gob.NewEncoder(&buf).Encode(v)
	if err != nil {
		return
	}

	data = buf.Bytes()
	return
}

//Marshaler returns the MarshalFunc present in c that matches one of the
//ContentTypes with pattern matching (text/*) in order of preference,
//as well as the chosen ContentType.
//If mf is nil ct may be some random data.
func (c ContentMarshaler) Marshaler(cts ...ContentType) (mf MarshalFunc, ct ContentType) {
	var k MediaType
	for _, ct = range cts {
		patt := restricted(string(ct.MediaType))
		for k, mf = range c {
			if ok, _ := path.Match(patt, string(k)); ok {
				return
			}
		}
	}
	mf = nil
	return
}

func Marshaler(cs []ContentMarshaler, cts ...ContentType) (mf MarshalFunc, ct ContentType) {
	var k MediaType
	for _, ct = range cts {
		patt := restricted(string(ct.MediaType))
		for _, c := range cs {
			for k, mf = range c {
				if k != "" {
					if ok, _ := path.Match(patt, string(k)); ok {
						return
					}
				}
			}
		}
	}
	mf = nil
	return
}

//RequestMarshalFunc returns the MarshalFunc mf that matches the *http.Request rq,
//as well as the selected ContentType.
//The extension of the request path is assumed to be the most preferable MIME type.
func (c ContentMarshaler) RequestMarshaler(r *http.Request) (mf MarshalFunc, ct ContentType) {
	types, _ := ParseContentType(r.Header.Get("Accept"))
	if m := pathMime(r.URL.Path); m != "" {
		types = []ContentType{{MediaType: MediaType(m)}}
	}

	return c.Marshaler(types...)
}

//RequestMarshaler returns the first MarshalFunc mf that matches the MIME types specified in
//the *http.Request from the []ContentMarshaler cs in order of preference, as well as the selected ContentType.
//The extension of the request path is assumed to be the most preferable MIME type.
func RequestMarshaler(r *http.Request, cs ...ContentMarshaler) (mf MarshalFunc, c ContentType) {
	types, _ := ParseContentType(r.Header.Get("Accept"))
	if debug {
		log.Printf("%+v", r.Header.Get("Accept"))
	}
	if m := pathMime(r.URL.Path); m != "" {
		a, b := pmt(m)
		types = append([]ContentType{{a, b}}, types...)
		if debug {
			log.Printf("%+v", types)
		}
	}

	mf, c = Marshaler(cs, types...)
	return

}
<commit_msg>Everybody loves UTF-8<commit_after>package object

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"encoding/xml"
	"github.com/TShadwell/jsarray"
	htmltemplate "html/template"
	"log"
	"net/http"
	"path"
	texttemplate "text/template"
)

type ContentMarshaler map[MediaType]MarshalFunc

type MarshalFunc func(v interface{}, m MediaType,
	params map[string]string) (data []byte, contentType string, err error)

//HTMLTemplate returns a MarshalFunc that executes the data on template `t` using the html/template
//package
func HTMLTemplate(t *htmltemplate.Template) MarshalFunc {
	return func(v interface{}, _ MediaType,
		_ map[string]string) (data []byte, contentType string, err error) {
		contentType = "text/html;charset=utf8"
		var bf bytes.Buffer
		err = t.Execute(&bf, v)
		if err != nil {
			return
		}
		data = bf.Bytes()
		return
	}
}

//TextTemplate returns a MarshalFunc that executes the data on template `t` using the text/template
//package.
func TextTemplate(t *texttemplate.Template) MarshalFunc {
	return func(v interface{}, _ MediaType,
		_ map[string]string) (data []byte, contentType string, err error) {
		contentType = "text/plain;charset=utf8"
		var bf bytes.Buffer
		err = t.Execute(&bf, v)
		if err != nil {
			return
		}
		data = bf.Bytes()
		return
	}
}

var Json MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {
	contentType = "application/json;charset=utf8"
	data, err = json.Marshal(v)

	return
}

var Xml MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {

	contentType = "application/xml;charset=utf8"
	data, err = xml.Marshal(v)
	return
}

var nullbytes = []byte("null")

//See github.com/TShadwell/jsarray for details.
var JsonArray MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {

	contentType = "application/json;charset=utf8"
	data, err = jsarray.Marshal(v)
	return
}

var plain MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) ([]byte, string, error) {
	return []byte(v.(string)), "text/plain", nil
}

var Gob MarshalFunc = func(v interface{}, _ MediaType,
	_ map[string]string) (data []byte, contentType string, err error) {

	contentType = "application/gob"
	var buf bytes.Buffer
	err = gob.NewEncoder(&buf).Encode(v)
	if err != nil {
		return
	}

	data = buf.Bytes()
	return
}

//Marshaler returns the MarshalFunc present in c that matches one of the
//ContentTypes with pattern matching (text/*) in order of preference,
//as well as the chosen ContentType.
//If mf is nil ct may be some random data.
func (c ContentMarshaler) Marshaler(cts ...ContentType) (mf MarshalFunc, ct ContentType) {
	var k MediaType
	for _, ct = range cts {
		patt := restricted(string(ct.MediaType))
		for k, mf = range c {
			if ok, _ := path.Match(patt, string(k)); ok {
				return
			}
		}
	}
	mf = nil
	return
}

func Marshaler(cs []ContentMarshaler, cts ...ContentType) (mf MarshalFunc, ct ContentType) {
	var k MediaType
	for _, ct = range cts {
		patt := restricted(string(ct.MediaType))
		for _, c := range cs {
			for k, mf = range c {
				if k != "" {
					if ok, _ := path.Match(patt, string(k)); ok {
						return
					}
				}
			}
		}
	}
	mf = nil
	return
}

//RequestMarshalFunc returns the MarshalFunc mf that matches the *http.Request rq,
//as well as the selected ContentType.
//The extension of the request path is assumed to be the most preferable MIME type.
func (c ContentMarshaler) RequestMarshaler(r *http.Request) (mf MarshalFunc, ct ContentType) {
	types, _ := ParseContentType(r.Header.Get("Accept"))
	if m := pathMime(r.URL.Path); m != "" {
		types = []ContentType{{MediaType: MediaType(m)}}
	}

	return c.Marshaler(types...)
}

//RequestMarshaler returns the first MarshalFunc mf that matches the MIME types specified in
//the *http.Request from the []ContentMarshaler cs in order of preference, as well as the selected ContentType.
//The extension of the request path is assumed to be the most preferable MIME type.
func RequestMarshaler(r *http.Request, cs ...ContentMarshaler) (mf MarshalFunc, c ContentType) {
	types, _ := ParseContentType(r.Header.Get("Accept"))
	if debug {
		log.Printf("%+v", r.Header.Get("Accept"))
	}
	if m := pathMime(r.URL.Path); m != "" {
		a, b := pmt(m)
		types = append([]ContentType{{a, b}}, types...)
		if debug {
			log.Printf("%+v", types)
		}
	}

	mf, c = Marshaler(cs, types...)
	return

}
<|endoftext|>


<commit_before>package mediatype

import ()

type Video struct {
	Media
	mediaFormat  string
	mediaRunTime string
}
<commit_msg>Added idiomatic get/set combos for video<commit_after>package mediatype

import ()

type Video struct {
	Media
	mediaFormat  string
	mediaRunTime string
}

func MediaFormat() {
	return mediaFormat
}

func MediaRunTime() {
	return mediaRunTime
}

func SetMediaFormat(newMediaFormat string) {
	mediaFormat = newMediaFormat
}

func SetMediaRunTime(newMediaRunTime string) {
	mediaRunTime = newMediaRunTime
}
<|endoftext|>


<commit_before>package definition

type tree struct {
	root Resource
}

// Creates a definition tree structure
func newTree(context string, definition_resources []map[interface{}]interface{}) *tree {
	resource := &Directory{
		name:     context,
		id:       context,
		children: generate(context, definition_resources),
	}
	return &tree{root: resource}
}

// Traverse the tree and yield each node to a function
func (t *tree) Traverse(action func(r Resource)) {
	traverse(t.root, action)
}

// Traverse the tree and yield each node to a function
func traverse(r Resource, action func(r Resource)) {
	if r.Children() == nil {
		return
	}

	for _, node := range r.Children() {
		action(node)
		traverse(node, action)
	}
}

// Generates a definition Resource hierarchy
func generate(resource_id string, definition_resources []map[interface{}]interface{}) []Resource {
	var resources []Resource
	for _, resource := range definition_resources {
		for key, data := range resource {
			if key == "dir" {
				a_data := data.(map[interface{}]interface{})
				name := a_data["name"].(string)
				id := resource_id + "/" + name

				dir_resources := []map[interface{}]interface{}{
					a_data,
				}

				resources = append(resources, &Directory{
					name:     name,
					id:       id,
					children: generate(id, dir_resources),
				})

			} else if key == "files" {
				a_data := data.([]interface{})
				files := getFileResources(resource_id, filesStringify(a_data))
				resources = append(resources, files...)
			}
		}
	}
	return resources
}

// Convert a []string to []Resource
func getFileResources(resource_id string, file_names []string) []Resource {
	var resources []Resource
	for _, file := range file_names {
		id := resource_id + "/" + file
		resources = append(resources, &File{
			name: file,
			id:   id,
		})
	}
	return resources
}

// Convert a []interface{} to []string
func filesStringify(file_names []interface{}) []string {
	var files []string
	for _, file_name := range file_names {
		files = append(files, file_name.(string))
	}
	return files
}
<commit_msg>Improve comment<commit_after>package definition

type tree struct {
	root Resource
}

// Creates a definition tree structure
func newTree(context string, definition_resources []map[interface{}]interface{}) *tree {
	resource := &Directory{
		name:     context,
		id:       context,
		children: generate(context, definition_resources),
	}
	return &tree{root: resource}
}

// Traverse the tree and yield each node to a function
func (t *tree) Traverse(action func(r Resource)) {
	traverse(t.root, action)
}

// Traverse the tree and yield each resource to a function
func traverse(r Resource, action func(r Resource)) {
	if r.Children() == nil {
		return
	}

	for _, node := range r.Children() {
		action(node)
		traverse(node, action)
	}
}

// Generates a definition Resource hierarchy
func generate(resource_id string, definition_resources []map[interface{}]interface{}) []Resource {
	var resources []Resource
	for _, resource := range definition_resources {
		for key, data := range resource {
			if key == "dir" {
				a_data := data.(map[interface{}]interface{})
				name := a_data["name"].(string)
				id := resource_id + "/" + name

				dir_resources := []map[interface{}]interface{}{
					a_data,
				}

				resources = append(resources, &Directory{
					name:     name,
					id:       id,
					children: generate(id, dir_resources),
				})

			} else if key == "files" {
				a_data := data.([]interface{})
				files := getFileResources(resource_id, filesStringify(a_data))
				resources = append(resources, files...)
			}
		}
	}
	return resources
}

// Convert a []string to []Resource
func getFileResources(resource_id string, file_names []string) []Resource {
	var resources []Resource
	for _, file := range file_names {
		id := resource_id + "/" + file
		resources = append(resources, &File{
			name: file,
			id:   id,
		})
	}
	return resources
}

// Convert a []interface{} to []string
func filesStringify(file_names []interface{}) []string {
	var files []string
	for _, file_name := range file_names {
		files = append(files, file_name.(string))
	}
	return files
}
<|endoftext|>