<commit_before>package doubleratchet

// TODO: During each DH ratchet step a new ratchet key pair and sending chain are generated.
// As the sending chain is not needed right away, these steps could be deferred until the party
// is about to send a new message.

import (
	"fmt"
)

// Session of the party involved in the Double Ratchet Algorithm.
type Session interface {
	// RatchetEncrypt performs a symmetric-key ratchet step, then AEAD-encrypts the message with
	// the resulting message key.
	RatchetEncrypt(plaintext, associatedData []byte) Message

	// RatchetDecrypt is called to AEAD-decrypt messages.
	RatchetDecrypt(m Message, associatedData []byte) ([]byte, error)

	PublicKeyer
}

// SessionHE is the session of the party involved the Double Ratchet Algorithm with encrypted header modification.
type SessionHE interface {
	// RatchetEncryptHE performs a symmetric-key ratchet step, then AEAD-encrypts
	// the header-encrypted message with the resulting message key.
	RatchetEncryptHE(plaintext, associatedData []byte) MessageHE

	// RatchetDecryptHE is called to AEAD-decrypt header-encrypted messages.
	RatchetDecryptHE(m MessageHE, associatedData []byte) ([]byte, error)

	PublicKeyer
}

type PublicKeyer interface {
	// PublicKey returns the session's ratchet public key.
	PublicKey() Key
}

// The double ratchet state.
type state struct {
	Crypto Crypto

	// DH Ratchet public key (the remote key).
	DHr Key

	// DH Ratchet key pair (the self ratchet key).
	DHs DHPair

	// Symmetric ratchet root chain.
	RootCh rootChain

	// Symmetric ratchet sending and receiving chains.
	SendCh, RecvCh chain

	// Number of messages in previous sending chain.
	PN uint32

	// Receiving header key and next header key.
	HKr, NHKr Key

	// Sending header key and next header key.
	HKs, NHKs Key
}

func newState(sharedKey Key, c Crypto) (state, error) {
	dhs, err := c.GenerateDH()
	if err != nil {
		return nil, fmt.Errorf("failed to generate dh pair: %s", err)
	}
	return state{
		Crypto: c,
		DHs:    dhs,
		RootCh: rootChain{CK: sharedKey, Crypto: c},
		// Populate CKs and CKr with sharedKey as per specification so that both
		// parties could send and receive messages from the very beginning.
		SendCh: chain{CK: sharedKey, Crypto: c},
		RecvCh: chain{CK: sharedKey, Crypto: c},
	}, nil
}

// dhRatchet performs a single ratchet step.
func (s *state) dhRatchet(m MessageHeader) error {
	s.PN = s.SendCh.N
	s.DHr = m.DH
	s.HKs = s.NHKs
	s.HKr = s.NHKr
	s.RecvCh, s.NHKr = s.RootCh.Step(s.Crypto.DH(s.DHs, s.DHr))
	var err error
	s.DHs, err = s.Crypto.GenerateDH()
	if err != nil {
		return fmt.Errorf("failed to generate dh pair: %s", err)
	}
	s.SendCh, s.NHKs = s.RootCh.Step(s.Crypto.DH(s.DHs, s.DHr))
	return nil
}

// SymmetricStep performs a symmetric ratchet step on the sending chain and returns message header
// for a new message.
func (s *state) SymmetricStep() (MessageHeader, Key) {
	return MessageHeader{
		DH: s.DHs.PublicKey(),
		N:  s.SendCh.N,
		PN: s.PN,
	}, s.SendCh.Step()
}

// Operations on this object are NOT THREAD-SAFE, make sure they're done in sequence.
type session struct {
	state state

	// Cryptography functions for the Double Ratchet Algorithm.
	Crypto Crypto

	// Dictionary of skipped-over message keys, indexed by ratchet public key and message number.
	MkSkipped KeysStorage

	// The maximum number of message keys that can be skipped in a single chain.
	// MaxSkip should be set high enough to tolerate routine lost or delayed messages,
	// but low enough that a malicious sender can't trigger excessive recipient computation.
	MaxSkip uint

	// Number of ratchet steps after which all skipped message keys for that public key will be deleted.
	MaxKeep uint

	// The number of the current ratchet step.
	Step uint

	// Shows what public key for the receiving chain was used at the specified step.
	DeleteKeys map[uint]Key
}

// New creates session with the shared key.
func New(sharedKey Key, opts ...option) (Session, error) {
	if sharedKey == [32]byte{} {
		return nil, fmt.Errorf("sharedKey must be non-zero")
	}
	var (
		c          = DefaultCrypto{}
		state, err = newState(sharedKey, c)
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create state: %s", err)
	}
	s := &session{
		state:      state,
		MkSkipped:  &KeysStorageInMemory{},
		MaxSkip:    1000,
		MaxKeep:    100,
		Crypto:     c,
		DeleteKeys: make(map[uint]Key),
	}

	for i := range opts {
		if err := opts[i](s); err != nil {
			return nil, fmt.Errorf("failed to apply option: %s", err)
		}
	}

	return s, nil
}

// NewWithRK creates session with the shared key and public key of the other party.
func NewWithRK(sharedKey, remoteKey Key, opts ...option) (Session, error) {
	s, err := New(sharedKey, opts...)
	if err != nil {
		return nil, err
	}
	s.(*session).state.DHr = remoteKey
	return s, nil
}

// option is a constructor option.
type option func(*session) error

// MaxSkip specifies the maximum number of skipped message in a single chain.
func MaxSkip(n int) option {
	return func(s *session) error {
		if n < 0 {
			return fmt.Errorf("n must be non-negative")
		}
		s.MaxSkip = uint(n)
		return nil
	}
}

// MaxKeep specifies the maximum number of ratchet steps before a message is deleted.
func MaxKeep(n int) option {
	return func(s *session) error {
		if n < 0 {
			return fmt.Errorf("n must be non-negative")
		}
		s.MaxKeep = uint(n)
		return nil
	}
}

// TODO: WithKeysStorage.
// TODO: WithCrypto.

// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
// the resulting message key.
func (s *session) RatchetEncrypt(plaintext, ad []byte) Message {
	var (
		h, mk = s.state.SymmetricStep()
		ct    = s.Crypto.Encrypt(mk, plaintext, append(ad, h.Encode()...))
	)
	return Message{h, ct}
}

func (s *session) RatchetEncryptHE(plaintext, ad []byte) MessageHE {
	var (
		h, mk = s.state.SymmetricStep()
		hEnc  = s.Crypto.Encrypt(s.state.HKs, h.Encode(), nil)
	)
	return MessageHE{
		Header:     hEnc,
		Ciphertext: s.Crypto.Encrypt(mk, plaintext, append(ad, hEnc...)),
	}
}

func (s *session) RatchetDecryptHE(m MessageHE, ad []byte) ([]byte, error) {
	// Is the message one of the skipped?
	// TODO: Replace this part with TrySkippedMessages.
	for hk, keys := range s.MkSkipped.All() {
		for n, mk := range keys {
			var (
				hEnc, err = s.Crypto.Decrypt(hk, m.Header[:], nil)
				h         = MessageEncHeader(hEnc).Decode()
			)
			if err == nil && uint(h.N) == n {
				plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header...))
				if err != nil {
					return nil, fmt.Errorf("can't decrypt skipped message: %s", err)
				}
				s.MkSkipped.DeleteMk(hk, n)
				return plaintext, nil
			}
		}
	}

	h, step, err := s.DecryptHeaderHE(m.Header)
	if err != nil {
		return nil, fmt.Errorf("can't decrypt header: %s", err)
	}

	var (
		// All changes must be applied on a different session object, so that this session won't be modified nor left in a dirty session.
		sc state = s.state

		skippedKeys1 []skippedKey
		skippedKeys2 []skippedKey
	)
	if step {
		// TODO: Here is the same code.
		if skippedKeys1, err = sc.skipMessageKeys(s.state.HKr, h.PN); err != nil {
			return nil, fmt.Errorf("can't skip previous chain message keys: %s", err)
		}
		if err = sc.dhRatchet(h); err != nil {
			return nil, fmt.Errorf("can't perform ratchet step: %s", err)
		}
	}

	// After all, update the current chain.
	if skippedKeys2, err = sc.skipMessageKeys(s.state.HKr, h.N); err != nil {
		return nil, fmt.Errorf("can't skip current chain message keys: %s", err)
	}
	mk := sc.RecvCh.Step()
	plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header...))
	if err != nil {
		return nil, fmt.Errorf("can't decrypt: %s", err)
	}

	// Apply changes.
	// TODO: s.preserveChanges(sc, key, append(skippedKeys1, skippedKeys2...))
	s.state = sc
	if step {
		s.DeleteKeys[s.Step] = s.state.HKr
		s.Step++
		if hk, ok := s.DeleteKeys[s.Step-s.MaxKeep]; ok {
			s.MkSkipped.DeletePk(hk)
			delete(s.DeleteKeys, s.Step-s.MaxKeep)
		}
		for _, skipped := range skippedKeys1 {
			s.MkSkipped.Put(skipped.key, skipped.nr, skipped.mk)
		}
	}
	for _, skipped := range skippedKeys2 {
		s.MkSkipped.Put(skipped.key, skipped.nr, skipped.mk)
	}

	return plaintext, nil
}

func (s *session) DecryptHeaderHE(encHeader []byte) (MessageHeader, bool, error) {
	if encoded, err := s.Crypto.Decrypt(s.state.HKr, encHeader, nil); err == nil {
		return MessageEncHeader(encoded).Decode(), false, nil
	}
	if encoded, err := s.Crypto.Decrypt(s.state.HKr, encHeader, nil); err == nil {
		return MessageEncHeader(encoded).Decode(), true, nil
	}
	return MessageHeader{}, false, fmt.Errorf("invalid message header")
}

// RatchetDecrypt is called to decrypt messages.
func (s *session) RatchetDecrypt(m Message, ad []byte) ([]byte, error) {
	// Is the message one of the skipped?
	// TODO: Replace this part with TrySkippedMessages.
	if mk, ok := s.MkSkipped.Get(m.Header.DH, uint(m.Header.N)); ok {
		plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header.Encode()...))
		if err != nil {
			return nil, fmt.Errorf("can't decrypt skipped message: %s", err)
		}
		s.MkSkipped.DeleteMk(m.Header.DH, uint(m.Header.N))
		return plaintext, nil
	}

	var (
		// All changes must be applied on a different session object, so that this session won't be modified nor left in a dirty session.
		sc state = s.state

		skippedKeys1 []skippedKey
		skippedKeys2 []skippedKey
		err          error
	)

	// Is there a new ratchet key?
	isDHStepped := false
	if m.Header.DH != sc.DHr {
		// TODO: Here is the same code.
		if skippedKeys1, err = sc.skipMessageKeys(sc.DHr, m.Header.PN); err != nil {
			return nil, fmt.Errorf("can't skip previous chain message keys: %s", err)
		}
		if err = sc.dhRatchet(m.Header); err != nil {
			return nil, fmt.Errorf("can't perform ratchet step: %s", err)
		}
		isDHStepped = true
	}

	// After all, update the current chain.
	if skippedKeys2, err = sc.skipMessageKeys(sc.DHr, m.Header.N); err != nil {
		return nil, fmt.Errorf("can't skip current chain message keys: %s", err)
	}
	mk := sc.RecvCh.Step()
	plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header.Encode()...))
	if err != nil {
		return nil, fmt.Errorf("can't decrypt: %s", err)
	}

	// Apply changes.
	s.state = sc
	if isDHStepped {
		s.DeleteKeys[s.Step] = s.state.DHr
		s.Step++
		if pubKey, ok := s.DeleteKeys[s.Step-s.MaxKeep]; ok {
			s.MkSkipped.DeletePk(pubKey)
			delete(s.DeleteKeys, s.Step-s.MaxKeep)
		}
		for _, skipped := range skippedKeys1 {
			s.MkSkipped.Put(skipped.key, skipped.nr, skipped.mk)
		}
	}
	for _, skipped := range skippedKeys2 {
		s.MkSkipped.Put(skipped.key, skipped.nr, skipped.mk)
	}

	return plaintext, nil
}

func (s *session) PublicKey() Key {
	return s.state.DHs.PublicKey()
}

type skippedKey struct {
	key Key
	nr  uint
	mk  Key
}

// skipMessageKeys skips message keys in the current receiving chain.
// TODO: Move it to state.
func (s *session) skipMessageKeys(key Key, until uint) ([]skippedKey, error) {
	if until < uint(s.state.RecvCh.N) {
		return nil, fmt.Errorf("bad until: probably an out-of-order message that was deleted")
	}
	nSkipped := s.MkSkipped.Count(key)
	if until-uint(s.state.RecvCh.N)+nSkipped > s.MaxSkip {
		return nil, fmt.Errorf("too many messages")
	}
	skipped := []skippedKey{}
	for uint(s.state.RecvCh.N) < until {
		mk := s.state.RecvCh.Step()
		skipped = append(skipped, skippedKey{
			key: key,
			nr:  uint(s.state.RecvCh.N - 1),
			mk:  mk,
		})
	}
	return skipped, nil
}
<commit_msg>Moved more fields from session into state<commit_after>package doubleratchet

// TODO: During each DH ratchet step a new ratchet key pair and sending chain are generated.
// As the sending chain is not needed right away, these steps could be deferred until the party
// is about to send a new message.

import (
	"fmt"
)

// Session of the party involved in the Double Ratchet Algorithm.
type Session interface {
	// RatchetEncrypt performs a symmetric-key ratchet step, then AEAD-encrypts the message with
	// the resulting message key.
	RatchetEncrypt(plaintext, associatedData []byte) Message

	// RatchetDecrypt is called to AEAD-decrypt messages.
	RatchetDecrypt(m Message, associatedData []byte) ([]byte, error)

	PublicKeyer
}

// SessionHE is the session of the party involved the Double Ratchet Algorithm with encrypted header modification.
type SessionHE interface {
	// RatchetEncryptHE performs a symmetric-key ratchet step, then AEAD-encrypts
	// the header-encrypted message with the resulting message key.
	RatchetEncryptHE(plaintext, associatedData []byte) MessageHE

	// RatchetDecryptHE is called to AEAD-decrypt header-encrypted messages.
	RatchetDecryptHE(m MessageHE, associatedData []byte) ([]byte, error)

	PublicKeyer
}

type PublicKeyer interface {
	// PublicKey returns the session's ratchet public key.
	PublicKey() Key
}

// The double ratchet state.
type state struct {
	Crypto Crypto

	// DH Ratchet public key (the remote key).
	DHr Key

	// DH Ratchet key pair (the self ratchet key).
	DHs DHPair

	// Symmetric ratchet root chain.
	RootCh rootChain

	// Symmetric ratchet sending and receiving chains.
	SendCh, RecvCh chain

	// Number of messages in previous sending chain.
	PN uint32

	// Dictionary of skipped-over message keys, indexed by ratchet public key or header key
	// and message number.
	MkSkipped KeysStorage

	// The maximum number of message keys that can be skipped in a single chain.
	// MaxSkip should be set high enough to tolerate routine lost or delayed messages,
	// but low enough that a malicious sender can't trigger excessive recipient computation.
	MaxSkip uint

	// Receiving header key and next header key. Only used for header encryption.
	HKr, NHKr Key

	// Sending header key and next header key. Only used for header encryption.
	HKs, NHKs Key

	// Number of ratchet steps after which all skipped message keys for that key will be deleted.
	MaxKeep uint

	// The number of the current ratchet step.
	Step uint

	// Which key for the receiving chain was used at the specified step.
	DeleteKeys map[uint]Key
}

func newState(sharedKey Key, c Crypto) (state, error) {
	dhs, err := c.GenerateDH()
	if err != nil {
		return nil, fmt.Errorf("failed to generate dh pair: %s", err)
	}
	return state{
		Crypto: c,
		DHs:    dhs,
		RootCh: rootChain{CK: sharedKey, Crypto: c},
		// Populate CKs and CKr with sharedKey as per specification so that both
		// parties could send and receive messages from the very beginning.
		SendCh:     chain{CK: sharedKey, Crypto: c},
		RecvCh:     chain{CK: sharedKey, Crypto: c},
		MkSkipped:  &KeysStorageInMemory{},
		MaxSkip:    1000,
		MaxKeep:    100,
		DeleteKeys: make(map[uint]Key),
	}, nil
}

// dhRatchet performs a single ratchet step.
func (s *state) dhRatchet(m MessageHeader) error {
	s.PN = s.SendCh.N
	s.DHr = m.DH
	s.HKs = s.NHKs
	s.HKr = s.NHKr
	s.RecvCh, s.NHKr = s.RootCh.Step(s.Crypto.DH(s.DHs, s.DHr))
	var err error
	s.DHs, err = s.Crypto.GenerateDH()
	if err != nil {
		return fmt.Errorf("failed to generate dh pair: %s", err)
	}
	s.SendCh, s.NHKs = s.RootCh.Step(s.Crypto.DH(s.DHs, s.DHr))
	return nil
}

type skippedKey struct {
	key Key
	nr  uint
	mk  Key
}

// skipMessageKeys skips message keys in the current receiving chain.
func (s *state) skipMessageKeys(key Key, until uint) ([]skippedKey, error) {
	if until < uint(s.RecvCh.N) {
		return nil, fmt.Errorf("bad until: probably an out-of-order message that was deleted")
	}
	nSkipped := s.MkSkipped.Count(key)
	if until-uint(s.RecvCh.N)+nSkipped > s.MaxSkip {
		return nil, fmt.Errorf("too many messages")
	}
	skipped := []skippedKey{}
	for uint(s.RecvCh.N) < until {
		mk := s.RecvCh.Step()
		skipped = append(skipped, skippedKey{
			key: key,
			nr:  uint(s.RecvCh.N - 1),
			mk:  mk,
		})
	}
	return skipped, nil
}

func (s *state) applyChanges(sc state, skipped []skippedKey) {
	*s = sc
	for _, skipped := range skipped {
		s.MkSkipped.Put(skipped.key, skipped.nr, skipped.mk)
	}
}

func (s *state) deleteSkippedKeys(key Key) {
	s.DeleteKeys[s.Step] = key
	s.Step++
	if hk, ok := s.DeleteKeys[s.Step-s.MaxKeep]; ok {
		s.MkSkipped.DeletePk(hk)
		delete(s.DeleteKeys, s.Step-s.MaxKeep)
	}
}

// Operations on this object are NOT THREAD-SAFE, make sure they're done in sequence.
type session struct {
	state state

	// Cryptography functions for the Double Ratchet Algorithm.
	Crypto Crypto
}

// New creates session with the shared key.
func New(sharedKey Key, opts ...option) (Session, error) {
	if sharedKey == [32]byte{} {
		return nil, fmt.Errorf("sharedKey must be non-zero")
	}
	var (
		c          = DefaultCrypto{}
		state, err = newState(sharedKey, c)
	)
	if err != nil {
		return nil, fmt.Errorf("failed to create state: %s", err)
	}
	s := &session{
		state:  state,
		Crypto: c,
	}

	for i := range opts {
		if err := opts[i](&s.state); err != nil {
			return nil, fmt.Errorf("failed to apply option: %s", err)
		}
	}

	return s, nil
}

// NewWithRK creates session with the shared key and public key of the other party.
func NewWithRK(sharedKey, remoteKey Key, opts ...option) (Session, error) {
	s, err := New(sharedKey, opts...)
	if err != nil {
		return nil, err
	}
	s.(*session).state.DHr = remoteKey
	return s, nil
}

// option is a constructor option.
type option func(*state) error

// MaxSkip specifies the maximum number of skipped message in a single chain.
func MaxSkip(n int) option {
	return func(s *state) error {
		if n < 0 {
			return fmt.Errorf("n must be non-negative")
		}
		s.MaxSkip = uint(n)
		return nil
	}
}

// MaxKeep specifies the maximum number of ratchet steps before a message is deleted.
func MaxKeep(n int) option {
	return func(s *state) error {
		if n < 0 {
			return fmt.Errorf("n must be non-negative")
		}
		s.MaxKeep = uint(n)
		return nil
	}
}

// TODO: WithKeysStorage.
// TODO: WithCrypto.

// RatchetEncrypt performs a symmetric-key ratchet step, then encrypts the message with
// the resulting message key.
func (s *session) RatchetEncrypt(plaintext, ad []byte) Message {
	var (
		h = MessageHeader{
			DH: s.state.DHs.PublicKey(),
			N:  s.state.SendCh.N,
			PN: s.state.PN,
		}
		mk = s.state.SendCh.Step()
		ct = s.Crypto.Encrypt(mk, plaintext, append(ad, h.Encode()...))
	)
	return Message{h, ct}
}

// RatchetEncryptHE performs a symmetric-key ratchet step, then encrypts the header with
// the corresponding header key and the message with resulting message key.
func (s *session) RatchetEncryptHE(plaintext, ad []byte) MessageHE {
	var (
		h = MessageHeader{
			DH: s.state.DHs.PublicKey(),
			N:  s.state.SendCh.N,
			PN: s.state.PN,
		}
		mk   = s.state.SendCh.Step()
		hEnc = s.Crypto.Encrypt(s.state.HKs, h.Encode(), nil)
	)
	return MessageHE{
		Header:     hEnc,
		Ciphertext: s.Crypto.Encrypt(mk, plaintext, append(ad, hEnc...)),
	}
}

func (s *session) RatchetDecryptHE(m MessageHE, ad []byte) ([]byte, error) {
	// Is the message one of the skipped?
	for hk, keys := range s.state.MkSkipped.All() {
		for n, mk := range keys {
			var (
				hEnc, err = s.Crypto.Decrypt(hk, m.Header, nil)
				h         = MessageEncHeader(hEnc).Decode()
			)
			if err == nil && uint(h.N) == n {
				plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header...))
				if err != nil {
					return nil, fmt.Errorf("can't decrypt skipped message: %s", err)
				}
				s.state.MkSkipped.DeleteMk(hk, n)
				return plaintext, nil
			}
		}
	}

	h, step, err := s.DecryptHeaderHE(m.Header)
	if err != nil {
		return nil, fmt.Errorf("can't decrypt header: %s", err)
	}

	var (
		// All changes must be applied on a different session object, so that this session won't be modified nor left in a dirty session.
		sc state = s.state

		skippedKeys1 []skippedKey
		skippedKeys2 []skippedKey
	)
	if step {
		if skippedKeys1, err = sc.skipMessageKeys(s.state.HKr, uint(h.PN)); err != nil {
			return nil, fmt.Errorf("can't skip previous chain message keys: %s", err)
		}
		if err = sc.dhRatchet(h); err != nil {
			return nil, fmt.Errorf("can't perform ratchet step: %s", err)
		}
	}

	// After all, update the current chain.
	if skippedKeys2, err = sc.skipMessageKeys(s.state.HKr, uint(h.N)); err != nil {
		return nil, fmt.Errorf("can't skip current chain message keys: %s", err)
	}
	mk := sc.RecvCh.Step()
	plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header...))
	if err != nil {
		return nil, fmt.Errorf("can't decrypt: %s", err)
	}

	s.state.applyChanges(sc, append(skippedKeys1, skippedKeys2...))
	if step {
		s.state.deleteSkippedKeys(s.state.HKr)
	}

	return plaintext, nil
}

func (s *session) DecryptHeaderHE(encHeader []byte) (MessageHeader, bool, error) {
	if encoded, err := s.Crypto.Decrypt(s.state.HKr, encHeader, nil); err == nil {
		return MessageEncHeader(encoded).Decode(), false, nil
	}
	if encoded, err := s.Crypto.Decrypt(s.state.HKr, encHeader, nil); err == nil {
		return MessageEncHeader(encoded).Decode(), true, nil
	}
	return MessageHeader{}, false, fmt.Errorf("invalid message header")
}

// RatchetDecrypt is called to decrypt messages.
func (s *session) RatchetDecrypt(m Message, ad []byte) ([]byte, error) {
	// Is the message one of the skipped?
	if mk, ok := s.state.MkSkipped.Get(m.Header.DH, uint(m.Header.N)); ok {
		plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header.Encode()...))
		if err != nil {
			return nil, fmt.Errorf("can't decrypt skipped message: %s", err)
		}
		s.state.MkSkipped.DeleteMk(m.Header.DH, uint(m.Header.N))
		return plaintext, nil
	}

	var (
		// All changes must be applied on a different session object, so that this session won't be modified nor left in a dirty session.
		sc state = s.state

		skippedKeys1 []skippedKey
		skippedKeys2 []skippedKey
		err          error
	)

	// Is there a new ratchet key?
	isDHStepped := false
	if m.Header.DH != sc.DHr {
		if skippedKeys1, err = sc.skipMessageKeys(sc.DHr, uint(m.Header.PN)); err != nil {
			return nil, fmt.Errorf("can't skip previous chain message keys: %s", err)
		}
		if err = sc.dhRatchet(m.Header); err != nil {
			return nil, fmt.Errorf("can't perform ratchet step: %s", err)
		}
		isDHStepped = true
	}

	// After all, update the current chain.
	if skippedKeys2, err = sc.skipMessageKeys(sc.DHr, uint(m.Header.N)); err != nil {
		return nil, fmt.Errorf("can't skip current chain message keys: %s", err)
	}
	mk := sc.RecvCh.Step()
	plaintext, err := s.Crypto.Decrypt(mk, m.Ciphertext, append(ad, m.Header.Encode()...))
	if err != nil {
		return nil, fmt.Errorf("can't decrypt: %s", err)
	}

	// Apply changes.
	s.state.applyChanges(sc, append(skippedKeys1, skippedKeys2...))
	if isDHStepped {
		s.state.deleteSkippedKeys(s.state.DHr)
	}

	return plaintext, nil
}

func (s *session) PublicKey() Key {
	return s.state.DHs.PublicKey()
}
<|endoftext|>


<commit_before>package stats

import (
	"math"
	"sort"
)

// Min finds the lowest number in a slice
func Min(input []float64) (min float64) {

	// Get the initial value
	// @todo add error if no length
	if len(input) > 0 {
		min = input[0]
	}

	// Iterate until done checking for a lower value
	for i := 1; i < len(input); i++ {
		if input[i] < min {
			min = input[i]
		}
	}
	return min
}

// Max finds the highest number in a slice
func Max(input []float64) (max float64) {
	if len(input) > 0 {
		max = input[0]
	}
	for i := 1; i < len(input); i++ {
		if input[i] > max {
			max = input[i]
		}
	}
	return max
}

// Sum adds all the numbers of a slice together
func Sum(input []float64) (sum float64) {
	for _, n := range input {
		sum += float64(n)
	}
	return sum
}

// Mean gets the average of a slice of numbers
func Mean(input []float64) (mean float64) {
	if len(input) == 0 {
		return 0.0
	}

	sum := Sum(input)

	return sum / float64(len(input))
}

// Median gets the median number in a slice of numbers
func Median(input []float64) (median float64) {

	// Start by sorting the slice
	sort.Float64s(input)

	l := len(input)

	// No math is needed if there are no numbers
	// For even numbers we add the two middle numbers
	// and divide by two using the mean function above
	// For odd numbers we just use the middle number
	if l == 0 {
		return 0.0
	} else if l%2 == 0 {
		median = Mean(input[l/2-1 : l/2+1])
	} else {
		median = float64(input[l/2])
	}

	return median
}

// Mode gets the mode of a slice of numbers
func Mode(input []float64) (mode []float64) {

	// Return the input if there's only one number
	// @todo add error for empty slice
	l := len(input)
	if l == 1 {
		return input
	}

	// Create a map with the counts for each number
	m := make(map[float64]int)
	for _, v := range input {
		m[v]++
	}

	// Find the highest counts to return as a slice
	// of ints to accomodate duplicate counts
	var current int
	for k, v := range m {

		// Depending if the count is lower, higher
		// or equal to the current numbers count
		// we return nothing, start a new mode or
		// append to the current mode
		switch {
		case v < current:
		case v > current:
			current = v
			mode = append(mode[:0], k)
		default:
			mode = append(mode, k)
		}
	}

	// Finally we check to see if there actually was
	// a mode by checking the length of the input and
	// mode against eachother
	lm := len(mode)
	if l == lm {
		return []float64{}
	}
	return mode
}

// Variance finds the variance for both population and sample data
func Variance(input []float64, sample int) (variance float64) {
	if len(input) == 0 {
		return 0.0
	}

	// Sum the square of the mean subtracted from each number
	m := Mean(input)
	for _, n := range input {
		variance += (float64(n) - m) * (float64(n) - m)
	}

	// When getting the mean of the squared differences
	// "sample" will allow us to know if it's a sample
	// or population and wether to subtract by one or not
	return variance / float64((len(input) - (1 * sample)))
}

// VarP finds the amount of variance within a population
func VarP(input []float64) (sdev float64) {
	return Variance(input, 0)
}

// VarS finds the amount of variance within a sample
func VarS(input []float64) (sdev float64) {
	return Variance(input, 1)
}

// StdDevP finds the amount of variation from the population
func StdDevP(input []float64) (sdev float64) {
	if len(input) == 0 {
		return 0.0
	}

	// Get the population variance
	m := VarP(input)

	// Return the population standard deviation
	return math.Pow(m, 0.5)
}

// StdDevS finds the amount of variation from a sample
func StdDevS(input []float64) (sdev float64) {
	if len(input) == 0 {
		return 0.0
	}

	// Get the sample variance
	m := VarS(input)

	// Return the sample standard deviation
	return math.Pow(m, 0.5)
}

// Round a float to a specific decimal place or precision
func Round(input float64, places int) (rounded float64) {

	// If the float is not a number we just return it
	// @todo add an error
	if math.IsNaN(input) {
		return input
	}

	// Find out the actual sign and correct the input for later
	sign := 1.0
	if input < 0 {
		sign = -1
		input *= -1
	}

	// Use the places arg to get the amount of precision wanted
	precision := math.Pow(10, float64(places))

	// Find the decimal place we are looking to round
	digit := input * precision

	// Get the actual decimal number as a fraction to be compared
	_, decimal := math.Modf(digit)

	// If the decimal is less than .5 we round down otherwise up
	if decimal >= 0.5 {
		rounded = math.Ceil(digit)
	} else {
		rounded = math.Floor(digit)
	}

	// Finally we do the math to actually create a rounded number
	return rounded / precision * sign
}

// Percentile finds the relative standing in a slice of floats
func Percentile(input []float64, percent float64) (percentile float64) {

	// Sort the data
	sort.Float64s(input)

	// Multiple percent by length of input
	index := (percent / 100) * float64(len(input))

	// Check if the index is a whole number
	if index == float64(int64(index)) {

		// Convert float to int
		i := Float64ToInt(index)

		// Find the average of the index and following values
		percentile = Mean([]float64{input[i-1], input[i]})

	} else {

		// Convert float to int
		i := Float64ToInt(index)

		// Find the value at the index
		percentile = input[i-1]

	}

	return percentile

}

// Float64ToInt rounds a float64 to an int
func Float64ToInt(input float64) (output int) {

	// Round input to nearest whole number and convert to int
	return int(Round(input, 0))

}

// Coordinate holds the data in a series
type Coordinate struct {
	X, Y float64
}

// LinReg finds the least squares linear regression on data series
func LinReg(s []Coordinate) (regressions []Coordinate) {

	// Placeholder for the math to be done
	var sum [5]float64

	// Loop over data keeping index in place
	i := 0
	for ; i < len(s); i++ {
		sum[0] += s[i].X
		sum[1] += s[i].Y
		sum[2] += s[i].X * s[i].X
		sum[3] += s[i].X * s[i].Y
		sum[4] += s[i].Y * s[i].Y
	}

	// Create gradient and intercepts
	f := float64(i)
	slope := (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
	intercept := (sum[1] / f) - (slope * sum[0] / f)

	// Create the new regression series
	for j := 0; j < len(s); j++ {
		regressions = append(regressions, Coordinate{
			X: s[j].X,
			Y: s[j].X*slope + intercept,
		})
	}

	return

}

// ExpReg returns an exponential regression on data series
func ExpReg(s []Coordinate) (regressions []Coordinate) {

	var sum [6]float64

	for i := 0; i < len(s); i++ {
		sum[0] += s[i].X
		sum[1] += s[i].Y
		sum[2] += s[i].X * s[i].X * s[i].Y
		sum[3] += s[i].Y * math.Log(s[i].Y)
		sum[4] += s[i].X * s[i].Y * math.Log(s[i].Y)
		sum[5] += s[i].X * s[i].Y
	}

	denominator := (sum[1]*sum[2] - sum[5]*sum[5])
	a := math.Pow(math.E, (sum[2]*sum[3]-sum[5]*sum[4])/denominator)
	b := (sum[1]*sum[4] - sum[5]*sum[3]) / denominator

	for j := 0; j < len(s); j++ {
		regressions = append(regressions, Coordinate{
			X: s[j].X,
			Y: a * math.Pow(2.718281828459045, b*s[j].X),
		})
	}

	return

}

// LogReg returns an logarithmic regression on data series
func LogReg(s []Coordinate) (regressions []Coordinate) {

	var sum [4]float64

	i := 0
	for ; i < len(s); i++ {
		sum[0] += math.Log(s[i].X)
		sum[1] += s[i].Y * math.Log(s[i].X)
		sum[2] += s[i].Y
		sum[3] += math.Pow(math.Log(s[i].X), 2)
	}

	f := float64(i)
	a := (f*sum[1] - sum[2]*sum[0]) / (f*sum[3] - sum[0]*sum[0])
	b := (sum[2] - a*sum[0]) / f

	for j := 0; j < len(s); j++ {
		regressions = append(regressions, Coordinate{
			X: s[j].X,
			Y: b + a*math.Log(s[j].X),
		})
	}

	return

}
<commit_msg>Consistent var naming<commit_after>package stats

import (
	"math"
	"sort"
)

// Min finds the lowest number in a slice
func Min(input []float64) (min float64) {

	// Get the initial value
	// @todo add error if no length
	if len(input) > 0 {
		min = input[0]
	}

	// Iterate until done checking for a lower value
	for i := 1; i < len(input); i++ {
		if input[i] < min {
			min = input[i]
		}
	}
	return min
}

// Max finds the highest number in a slice
func Max(input []float64) (max float64) {
	if len(input) > 0 {
		max = input[0]
	}
	for i := 1; i < len(input); i++ {
		if input[i] > max {
			max = input[i]
		}
	}
	return max
}

// Sum adds all the numbers of a slice together
func Sum(input []float64) (sum float64) {
	for _, n := range input {
		sum += float64(n)
	}
	return sum
}

// Mean gets the average of a slice of numbers
func Mean(input []float64) (mean float64) {
	if len(input) == 0 {
		return 0.0
	}

	sum := Sum(input)

	return sum / float64(len(input))
}

// Median gets the median number in a slice of numbers
func Median(input []float64) (median float64) {

	// Start by sorting the slice
	sort.Float64s(input)

	l := len(input)

	// No math is needed if there are no numbers
	// For even numbers we add the two middle numbers
	// and divide by two using the mean function above
	// For odd numbers we just use the middle number
	if l == 0 {
		return 0.0
	} else if l%2 == 0 {
		median = Mean(input[l/2-1 : l/2+1])
	} else {
		median = float64(input[l/2])
	}

	return median
}

// Mode gets the mode of a slice of numbers
func Mode(input []float64) (mode []float64) {

	// Return the input if there's only one number
	// @todo add error for empty slice
	l := len(input)
	if l == 1 {
		return input
	}

	// Create a map with the counts for each number
	m := make(map[float64]int)
	for _, v := range input {
		m[v]++
	}

	// Find the highest counts to return as a slice
	// of ints to accomodate duplicate counts
	var current int
	for k, v := range m {

		// Depending if the count is lower, higher
		// or equal to the current numbers count
		// we return nothing, start a new mode or
		// append to the current mode
		switch {
		case v < current:
		case v > current:
			current = v
			mode = append(mode[:0], k)
		default:
			mode = append(mode, k)
		}
	}

	// Finally we check to see if there actually was
	// a mode by checking the length of the input and
	// mode against eachother
	lm := len(mode)
	if l == lm {
		return []float64{}
	}
	return mode
}

// Variance finds the variance for both population and sample data
func Variance(input []float64, sample int) (variance float64) {
	if len(input) == 0 {
		return 0.0
	}

	// Sum the square of the mean subtracted from each number
	m := Mean(input)
	for _, n := range input {
		variance += (float64(n) - m) * (float64(n) - m)
	}

	// When getting the mean of the squared differences
	// "sample" will allow us to know if it's a sample
	// or population and wether to subtract by one or not
	return variance / float64((len(input) - (1 * sample)))
}

// VarP finds the amount of variance within a population
func VarP(input []float64) (sdev float64) {
	return Variance(input, 0)
}

// VarS finds the amount of variance within a sample
func VarS(input []float64) (sdev float64) {
	return Variance(input, 1)
}

// StdDevP finds the amount of variation from the population
func StdDevP(input []float64) (sdev float64) {
	if len(input) == 0 {
		return 0.0
	}

	// Get the population variance
	m := VarP(input)

	// Return the population standard deviation
	return math.Pow(m, 0.5)
}

// StdDevS finds the amount of variation from a sample
func StdDevS(input []float64) (sdev float64) {
	if len(input) == 0 {
		return 0.0
	}

	// Get the sample variance
	m := VarS(input)

	// Return the sample standard deviation
	return math.Pow(m, 0.5)
}

// Round a float to a specific decimal place or precision
func Round(input float64, places int) (rounded float64) {

	// If the float is not a number we just return it
	// @todo add an error
	if math.IsNaN(input) {
		return input
	}

	// Find out the actual sign and correct the input for later
	sign := 1.0
	if input < 0 {
		sign = -1
		input *= -1
	}

	// Use the places arg to get the amount of precision wanted
	precision := math.Pow(10, float64(places))

	// Find the decimal place we are looking to round
	digit := input * precision

	// Get the actual decimal number as a fraction to be compared
	_, decimal := math.Modf(digit)

	// If the decimal is less than .5 we round down otherwise up
	if decimal >= 0.5 {
		rounded = math.Ceil(digit)
	} else {
		rounded = math.Floor(digit)
	}

	// Finally we do the math to actually create a rounded number
	return rounded / precision * sign
}

// Percentile finds the relative standing in a slice of floats
func Percentile(input []float64, percent float64) (percentile float64) {

	// Sort the data
	sort.Float64s(input)

	// Multiple percent by length of input
	index := (percent / 100) * float64(len(input))

	// Check if the index is a whole number
	if index == float64(int64(index)) {

		// Convert float to int
		i := Float64ToInt(index)

		// Find the average of the index and following values
		percentile = Mean([]float64{input[i-1], input[i]})

	} else {

		// Convert float to int
		i := Float64ToInt(index)

		// Find the value at the index
		percentile = input[i-1]

	}

	return percentile

}

// Float64ToInt rounds a float64 to an int
func Float64ToInt(input float64) (output int) {

	// Round input to nearest whole number and convert to int
	return int(Round(input, 0))

}

// Coordinate holds the data in a series
type Coordinate struct {
	X, Y float64
}

// LinReg finds the least squares linear regression on data series
func LinReg(s []Coordinate) (regressions []Coordinate) {

	// Placeholder for the math to be done
	var sum [5]float64

	// Loop over data keeping index in place
	i := 0
	for ; i < len(s); i++ {
		sum[0] += s[i].X
		sum[1] += s[i].Y
		sum[2] += s[i].X * s[i].X
		sum[3] += s[i].X * s[i].Y
		sum[4] += s[i].Y * s[i].Y
	}

	// Find gradient and intercept
	f := float64(i)
	gradient := (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
	intercept := (sum[1] / f) - (gradient * sum[0] / f)

	// Create the new regression series
	for j := 0; j < len(s); j++ {
		regressions = append(regressions, Coordinate{
			X: s[j].X,
			Y: s[j].X*gradient + intercept,
		})
	}

	return

}

// ExpReg returns an exponential regression on data series
func ExpReg(s []Coordinate) (regressions []Coordinate) {

	var sum [6]float64

	for i := 0; i < len(s); i++ {
		sum[0] += s[i].X
		sum[1] += s[i].Y
		sum[2] += s[i].X * s[i].X * s[i].Y
		sum[3] += s[i].Y * math.Log(s[i].Y)
		sum[4] += s[i].X * s[i].Y * math.Log(s[i].Y)
		sum[5] += s[i].X * s[i].Y
	}

	denominator := (sum[1]*sum[2] - sum[5]*sum[5])
	a := math.Pow(math.E, (sum[2]*sum[3]-sum[5]*sum[4])/denominator)
	b := (sum[1]*sum[4] - sum[5]*sum[3]) / denominator

	for j := 0; j < len(s); j++ {
		regressions = append(regressions, Coordinate{
			X: s[j].X,
			Y: a * math.Pow(2.718281828459045, b*s[j].X),
		})
	}

	return

}

// LogReg returns an logarithmic regression on data series
func LogReg(s []Coordinate) (regressions []Coordinate) {

	var sum [4]float64

	i := 0
	for ; i < len(s); i++ {
		sum[0] += math.Log(s[i].X)
		sum[1] += s[i].Y * math.Log(s[i].X)
		sum[2] += s[i].Y
		sum[3] += math.Pow(math.Log(s[i].X), 2)
	}

	f := float64(i)
	a := (f*sum[1] - sum[2]*sum[0]) / (f*sum[3] - sum[0]*sum[0])
	b := (sum[2] - a*sum[0]) / f

	for j := 0; j < len(s); j++ {
		regressions = append(regressions, Coordinate{
			X: s[j].X,
			Y: b + a*math.Log(s[j].X),
		})
	}

	return

}
<|endoftext|>


<commit_before>package rkv

import (
	"fmt"
	"math/rand"
	"time"

	"golang.org/x/net/context"

	"github.com/relab/raft"
	commonpb "github.com/relab/raft/raftpb"
	cmdpb "github.com/relab/rkv/cmdpb"
)

// TODO Context timeout should depend on heartbeat setting.

// Store is a key-value store backed by a map.
type Store struct {
	store map[string]string

	nextID  uint64
	clients map[string]uint64

	waiting map[string]chan interface{}
	read    chan *readRequest

	raft raft.Raft
}

type readRequest struct {
	key   string
	value chan<- string
}

// NewStore returns a newly initialized store.
func NewStore(raft raft.Raft) *Store {
	s := &Store{
		store:   make(map[string]string),
		clients: make(map[string]uint64),
		waiting: make(map[string]chan interface{}),
		read:    make(chan *readRequest),
		raft:    raft,
	}

	go s.run()

	return s
}

func (s *Store) run() {
	for {
		select {
		case req := <-s.read:
			req.value <- s.store[req.key]

		case entries := <-s.raft.Committed():
			for _, entry := range entries {
				switch entry.EntryType {
				case commonpb.EntryNormal:
					var cmd cmdpb.Cmd
					err := cmd.Unmarshal(entry.Data)

					if err != nil {
						// TODO Ignore malformed requests. Log?
						continue
					}

					var res interface{}

					switch cmd.CmdType {
					case cmdpb.Register:
						id := fmt.Sprintf("%d", entry.Index)
						res = id
						if _, ok := s.clients[id]; ok {
							// Don't reset sequence
							// number if we receive
							// a duplicate.
							break
						}
						s.clients[id] = 0
					case cmdpb.Insert:
						// TODO We need to return
						// ErrSessionExpired, when the
						// session is expired. TODO If
						// we see seq > oldseq + 1, we
						// need to deal with that, i.e,
						// we might have stale data?
						if oldseq := s.clients[cmd.ClientID]; oldseq >= cmd.Seq {
							// Already applied.
							break
						}

						s.clients[cmd.ClientID] = cmd.Seq
						s.store[cmd.Key] = cmd.Value
					}

					cmdID := cmdUID(&cmd)
					if ch, ok := s.waiting[cmdID]; ok {
						ch <- res
						delete(s.waiting, cmdID)
					}
				}
			}
		}
	}
}

// randSeq is used to uniquely identify register command. There is a chance of a
// collision, but I'll take those odds any day.
func randSeq() uint64 {
	return uint64(rand.Uint32())<<32 + uint64(rand.Uint32())
}

func cmdUID(cmd *cmdpb.Cmd) string {
	switch cmd.CmdType {
	case cmdpb.Insert:
		return fmt.Sprintf("INSERT:%s%d", cmd.ClientID, cmd.Seq)
	case cmdpb.Lookup:
		return fmt.Sprintf("LOOKUP:%s%d", cmd.ClientID, cmd.Seq)
	}

	return fmt.Sprintf("REGISTER:%d", cmd.Seq)
}

func (s *Store) Register() (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	cmd := cmdpb.Cmd{CmdType: cmdpb.Register, Seq: randSeq()}
	b, err := cmd.Marshal()

	if err != nil {
		return "", err
	}

	done := make(chan interface{}, 1)
	// TODO Store cmds under clientID, so they can be expired.
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return "", err
	}

	select {
	case res := <-done:
		return res.(string), nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Lookup gets a value from the map given a key. If an error is returned, the
// client should retry the same request. Note that if the key doesn't exist, the empty string is
// returned.
func (s *Store) Lookup(key string, allowStale bool) (string, error) {
	// TODO Buffer reads to amortize cost.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	value := make(chan string, 1)

	if !allowStale {
		err := s.raft.Read(ctx)

		if err != nil {
			return "", err
		}
	}

	r := readRequest{
		key:   key,
		value: value,
	}

	s.read <- &r

	select {
	case v := <-value:
		return v, nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Insert inserts value in map given a key. If an error is returned, the client
// should retry the same request.
func (s *Store) Insert(id string, seq uint64, key, value string) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	// TODO Check if session is valid. Make it a function.

	cmd := cmdpb.Cmd{
		CmdType:  cmdpb.Register,
		ClientID: id,
		Seq:      seq,
		Key:      key,
		Value:    value,
	}
	b, err := cmd.Marshal()

	if err != nil {
		return err
	}

	done := make(chan interface{}, 1)
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return err
	}

	select {
	case <-done:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
<commit_msg>store.go: Ignore no-ops<commit_after>package rkv

import (
	"bytes"
	"fmt"
	"math/rand"
	"time"

	"golang.org/x/net/context"

	"github.com/relab/raft"
	commonpb "github.com/relab/raft/raftpb"
	cmdpb "github.com/relab/rkv/cmdpb"
)

// TODO Context timeout should depend on heartbeat setting.

// Store is a key-value store backed by a map.
type Store struct {
	store map[string]string

	nextID  uint64
	clients map[string]uint64

	waiting map[string]chan interface{}
	read    chan *readRequest

	raft raft.Raft
}

type readRequest struct {
	key   string
	value chan<- string
}

// NewStore returns a newly initialized store.
func NewStore(raft raft.Raft) *Store {
	s := &Store{
		store:   make(map[string]string),
		clients: make(map[string]uint64),
		waiting: make(map[string]chan interface{}),
		read:    make(chan *readRequest),
		raft:    raft,
	}

	go s.run()

	return s
}

func (s *Store) run() {
	for {
		select {
		case req := <-s.read:
			req.value <- s.store[req.key]

		case entries := <-s.raft.Committed():
			for _, entry := range entries {
				switch entry.EntryType {
				case commonpb.EntryNormal:
					// Ignore no-op. TODO Use this to allow
					// queued reads through?
					if bytes.Equal(raft.NOOP, entry.Data) {
						continue
					}

					var cmd cmdpb.Cmd
					err := cmd.Unmarshal(entry.Data)

					if err != nil {
						// TODO Ignore malformed requests. Log?
						continue
					}

					var res interface{}

					switch cmd.CmdType {
					case cmdpb.Register:
						id := fmt.Sprintf("%d", entry.Index)
						res = id
						if _, ok := s.clients[id]; ok {
							// Don't reset sequence
							// number if we receive
							// a duplicate.
							break
						}
						s.clients[id] = 0
					case cmdpb.Insert:
						// TODO We need to return
						// ErrSessionExpired, when the
						// session is expired. TODO If
						// we see seq > oldseq + 1, we
						// need to deal with that, i.e,
						// we might have stale data?
						if oldseq := s.clients[cmd.ClientID]; oldseq >= cmd.Seq {
							// Already applied.
							break
						}

						s.clients[cmd.ClientID] = cmd.Seq
						s.store[cmd.Key] = cmd.Value
					}

					cmdID := cmdUID(&cmd)
					if ch, ok := s.waiting[cmdID]; ok {
						ch <- res
						delete(s.waiting, cmdID)
					}
				}
			}
		}
	}
}

// randSeq is used to uniquely identify register command. There is a chance of a
// collision, but I'll take those odds any day.
func randSeq() uint64 {
	return uint64(rand.Uint32())<<32 + uint64(rand.Uint32())
}

func cmdUID(cmd *cmdpb.Cmd) string {
	switch cmd.CmdType {
	case cmdpb.Insert:
		return fmt.Sprintf("INSERT:%s%d", cmd.ClientID, cmd.Seq)
	case cmdpb.Lookup:
		return fmt.Sprintf("LOOKUP:%s%d", cmd.ClientID, cmd.Seq)
	}

	return fmt.Sprintf("REGISTER:%d", cmd.Seq)
}

func (s *Store) Register() (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	cmd := cmdpb.Cmd{CmdType: cmdpb.Register, Seq: randSeq()}
	b, err := cmd.Marshal()

	if err != nil {
		return "", err
	}

	done := make(chan interface{}, 1)
	// TODO Store cmds under clientID, so they can be expired.
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return "", err
	}

	select {
	case res := <-done:
		return res.(string), nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Lookup gets a value from the map given a key. If an error is returned, the
// client should retry the same request. Note that if the key doesn't exist, the empty string is
// returned.
func (s *Store) Lookup(key string, allowStale bool) (string, error) {
	// TODO Buffer reads to amortize cost.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	value := make(chan string, 1)

	if !allowStale {
		err := s.raft.Read(ctx)

		if err != nil {
			return "", err
		}
	}

	r := readRequest{
		key:   key,
		value: value,
	}

	s.read <- &r

	select {
	case v := <-value:
		return v, nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Insert inserts value in map given a key. If an error is returned, the client
// should retry the same request.
func (s *Store) Insert(id string, seq uint64, key, value string) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	// TODO Check if session is valid. Make it a function.

	cmd := cmdpb.Cmd{
		CmdType:  cmdpb.Register,
		ClientID: id,
		Seq:      seq,
		Key:      key,
		Value:    value,
	}
	b, err := cmd.Marshal()

	if err != nil {
		return err
	}

	done := make(chan interface{}, 1)
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return err
	}

	select {
	case <-done:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"gob"
	"io"
	"log"
	"os"
	"rpc"
	"sync"
)

type Store interface {
	Put(url, key *string) os.Error
	Get(key, url *string) os.Error
}

type PersistentStore struct {
	sync.Mutex
	urls  *UrlMap
	count int64
	filename string
}

func NewPersistentStore(filename string) *PersistentStore {
	s := &PersistentStore{urls: NewUrlMap(), filename: filename}
	if err := s.load(); err != nil {
		log.Println("PersistentStore:", err)
	}
	return s
}

func (s *PersistentStore) Get(key, url *string) os.Error {
	*url, _ = s.urls.Get(*key)
	return nil
}

func (s *PersistentStore) Put(url, key *string) os.Error {
	s.Lock()
	for {
		*key = genKey(s.count)
		s.count++
		if _, ok := s.urls.Get(*key); !ok {
			break
		}
	}
	s.Unlock()
	s.urls.Set(*key, *url)
	return s.save()
}

func (s *PersistentStore) load() os.Error {
	s.Lock()
	defer s.Unlock()
	f, err := os.Open(s.filename, os.O_RDONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	return s.urls.ReadFrom(f)
}

func (s *PersistentStore) save() os.Error {
	s.Lock()
	defer s.Unlock()
	f, err := os.Open(s.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	return s.urls.WriteTo(f)
}

type ProxyStore struct {
	sync.Mutex
	cache *UrlMap
	client *rpc.Client
}

func NewProxyStore(addr string) *ProxyStore {
	client, err := rpc.DialHTTP("tcp", addr)
	if err != nil {
		log.Println("ProxyStore:", err)
	}
	return &ProxyStore{cache: NewUrlMap(), client: client}
}

func (s *ProxyStore) Get(key, url *string) os.Error {
	if u, ok := s.cache.Get(*key); ok {
		*url = u
		return nil
	}
	err := s.client.Call("Store.Get", key, url)
	if err == nil {
		s.cache.Set(*key, *url)
	}
	return err
}

func (s *ProxyStore) Put(url, key *string) os.Error {
	err := s.client.Call("Store.Put", url, key)
	if err == nil {
		s.cache.Set(*key, *url)
	}
	return err
}

type UrlMap struct {
	sync.Mutex
	urls map[string]string
}

func NewUrlMap() *UrlMap {
	return &UrlMap{urls: make(map[string]string)}
}

func (m *UrlMap) Set(key, url string) {
	m.Lock()
	m.urls[key] = url
	m.Unlock()
	log.Println("Set", key, url)
}

func (m *UrlMap) Get(key string) (string, bool) {
	m.Lock()
	url, ok := m.urls[key]
	m.Unlock()
	log.Println("Get", key, url, ok)
	return url, ok
}

func (m *UrlMap) WriteTo(w io.Writer) os.Error {
	e := gob.NewEncoder(w)
	m.Lock()
	defer m.Unlock()
	return e.Encode(m.urls)
}

func (m *UrlMap) ReadFrom(r io.Reader) os.Error {
	d := gob.NewDecoder(r)
	m.Lock()
	defer m.Unlock()
	return d.Decode(&m.urls)
}
<commit_msg>return error when item not found<commit_after>package main

import (
	"gob"
	"io"
	"log"
	"os"
	"rpc"
	"sync"
)

type Store interface {
	Put(url, key *string) os.Error
	Get(key, url *string) os.Error
}

type PersistentStore struct {
	sync.Mutex
	urls  *UrlMap
	count int64
	filename string
}

func NewPersistentStore(filename string) *PersistentStore {
	s := &PersistentStore{urls: NewUrlMap(), filename: filename}
	if err := s.load(); err != nil {
		log.Println("PersistentStore:", err)
	}
	return s
}

func (s *PersistentStore) Get(key, url *string) os.Error {
	if u, ok := s.urls.Get(*key); ok {
		*url = u
		return nil
	}
	return os.NewError("key not found")
}

func (s *PersistentStore) Put(url, key *string) os.Error {
	s.Lock()
	for {
		*key = genKey(s.count)
		s.count++
		if _, ok := s.urls.Get(*key); !ok {
			break
		}
	}
	s.Unlock()
	s.urls.Set(*key, *url)
	return s.save()
}

func (s *PersistentStore) load() os.Error {
	s.Lock()
	defer s.Unlock()
	f, err := os.Open(s.filename, os.O_RDONLY, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	return s.urls.ReadFrom(f)
}

func (s *PersistentStore) save() os.Error {
	s.Lock()
	defer s.Unlock()
	f, err := os.Open(s.filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	return s.urls.WriteTo(f)
}

type ProxyStore struct {
	sync.Mutex
	cache *UrlMap
	client *rpc.Client
}

func NewProxyStore(addr string) *ProxyStore {
	client, err := rpc.DialHTTP("tcp", addr)
	if err != nil {
		log.Println("ProxyStore:", err)
	}
	return &ProxyStore{cache: NewUrlMap(), client: client}
}

func (s *ProxyStore) Get(key, url *string) os.Error {
	if u, ok := s.cache.Get(*key); ok {
		*url = u
		return nil
	}
	err := s.client.Call("Store.Get", key, url)
	if err == nil {
		s.cache.Set(*key, *url)
	}
	return err
}

func (s *ProxyStore) Put(url, key *string) os.Error {
	err := s.client.Call("Store.Put", url, key)
	if err == nil {
		s.cache.Set(*key, *url)
	}
	return err
}

type UrlMap struct {
	sync.Mutex
	urls map[string]string
}

func NewUrlMap() *UrlMap {
	return &UrlMap{urls: make(map[string]string)}
}

func (m *UrlMap) Set(key, url string) {
	m.Lock()
	m.urls[key] = url
	m.Unlock()
	log.Println("Set", key, url)
}

func (m *UrlMap) Get(key string) (string, bool) {
	m.Lock()
	url, ok := m.urls[key]
	m.Unlock()
	log.Println("Get", key, url, ok)
	return url, ok
}

func (m *UrlMap) WriteTo(w io.Writer) os.Error {
	e := gob.NewEncoder(w)
	m.Lock()
	defer m.Unlock()
	return e.Encode(m.urls)
}

func (m *UrlMap) ReadFrom(r io.Reader) os.Error {
	d := gob.NewDecoder(r)
	m.Lock()
	defer m.Unlock()
	return d.Decode(&m.urls)
}
<|endoftext|>


<commit_before>// +build windows

// To use it with windows, you need a tap driver installed on windows.
// https://github.com/OpenVPN/tap-windows6
// or just install OpenVPN
// https://github.com/OpenVPN/openvpn
package water

import (
	"bytes"
	"errors"
	"net"
	"os"
	"syscall"

	"golang.org/x/sys/windows/registry"
)

var (
	IfceNameNotFound  = errors.New("Failed to find the name of interface.")
	TapDeviceNotFound = errors.New("Failed to find the tap device in registry with specified ComponentId, TAP driver may be not installed.")
	RegistryOpenErr   = errors.New("Failed to open the adapter registry, TAP driver may be not installed.")
	// Device Control Codes
	tap_win_ioctl_get_mac             = tap_control_code(1, 0)
	tap_win_ioctl_get_version         = tap_control_code(2, 0)
	tap_win_ioctl_get_mtu             = tap_control_code(3, 0)
	tap_win_ioctl_get_info            = tap_control_code(4, 0)
	tap_ioctl_config_point_to_point   = tap_control_code(5, 0)
	tap_ioctl_set_media_status        = tap_control_code(6, 0)
	tap_win_ioctl_config_dhcp_masq    = tap_control_code(7, 0)
	tap_win_ioctl_get_log_line        = tap_control_code(8, 0)
	tap_win_ioctl_config_dhcp_set_opt = tap_control_code(9, 0)
	tap_ioctl_config_tun              = tap_control_code(10, 0)
	// w32 api
	file_device_unknown = uint32(0x00000022)
	// Driver maker specified ComponentId
	// ComponentId is defined here: https://github.com/OpenVPN/tap-windows6/blob/master/version.m4#L5
	componentId = "tap0901"
)

func ctl_code(device_type, function, method, access uint32) uint32 {
	return (device_type << 16) | (access << 14) | (function << 2) | method
}

func tap_control_code(request, method uint32) uint32 {
	return ctl_code(file_device_unknown, request, method, 0)
}

// getdeviceid finds out a TAP device from registry, it *may* requires privileged right to prevent some weird issue.
func getdeviceid() (string, error) {
	// TAP driver key location
	regkey := `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
	k, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.READ)
	if err != nil {
		return "", RegistryOpenErr
	}
	defer k.Close()
	// read all subkeys, it should not return an err here
	keys, err := k.ReadSubKeyNames(-1)
	if err != nil {
		return "", err
	}
	// find the one matched ComponentId
	for _, v := range keys {
		key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey+"\\"+v, registry.READ)
		if err != nil {
			continue
		}
		val, _, err := key.GetStringValue("ComponentId")
		if err != nil {
			key.Close()
			continue
		}
		if val == componentId {
			val, _, err = key.GetStringValue("NetCfgInstanceId")
			if err != nil {
				key.Close()
				continue
			}
			key.Close()
			return val, nil
		}
		key.Close()
	}
	return "", TapDeviceNotFound
}

// openDev find and open an interface.
func openDev(isTAP bool) (ifce *Interface, err error) {
	// ifName won't work
	// find the device in registry.
	deviceid, err := getdeviceid()
	if err != nil {
		return nil, err
	}
	path := "\\\\.\\Global\\" + deviceid + ".tap"
	pathp, err := syscall.UTF16PtrFromString(path)
	if err != nil {
		return nil, err
	}
	// type Handle uintptr
	file, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_SYSTEM, 0)
	// if err hanppens, close the interface.
	defer func() {
		if err != nil {
			syscall.Close(file)
		}
		if err := recover(); err != nil {
			syscall.Close(file)
		}
	}()
	if err != nil {
		return nil, err
	}
	var bytesReturned uint32
	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)

	//TUN
	if !isTAP {
		code2 := []byte{0x0a, 0x03, 0x00, 0x01, 0x0a, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00}
		err = syscall.DeviceIoControl(file, tap_ioctl_config_tun, &code2[0], uint32(12), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
		if err != nil {
			return
		}
	}

	// find the mac address of tap device, use this to find the name of interface
	mac := make([]byte, 6)
	err = syscall.DeviceIoControl(file, tap_win_ioctl_get_mac, &mac[0], uint32(len(mac)), &mac[0], uint32(len(mac)), &bytesReturned, nil)
	if err != nil {
		return nil, err
	}

	fd := os.NewFile(uintptr(file), path)
	ifce = &Interface{isTAP: isTAP, ReadWriteCloser: fd}

	// bring up device.
	code := []byte{0x01, 0x00, 0x00, 0x00}
	err = syscall.DeviceIoControl(file, tap_ioctl_set_media_status, &code[0], uint32(4), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
	if err != nil {
		return
	}
	// find the name of tap interface(u need it to set the ip or other command)
	ifces, err := net.Interfaces()
	if err != nil {
		return
	}

	for _, v := range ifces {
		if bytes.Equal(v.HardwareAddr[:6], mac[:6]) {
			ifce.name = v.Name
			return
		}
	}

	err = IfceNameNotFound
	return
}

func newTAP(ifName string) (ifce *Interface, err error) {
	// ifName won't work
	return openDev(true)
}

func newTUN(ifName string) (ifce *Interface, err error) {
	// ifName won't work
	return openDev(false)
}
<commit_msg>Fixed TUN issue.<commit_after>// +build windows

// To use it with windows, you need a tap driver installed on windows.
// https://github.com/OpenVPN/tap-windows6
// or just install OpenVPN
// https://github.com/OpenVPN/openvpn
package water

import (
	"bytes"
	"errors"
	"net"
	"os"
	"syscall"

	"golang.org/x/sys/windows/registry"
)

var (
	IfceNameNotFound  = errors.New("Failed to find the name of interface.")
	TapDeviceNotFound = errors.New("Failed to find the tap device in registry with specified ComponentId, TAP driver may be not installed.")
	RegistryOpenErr   = errors.New("Failed to open the adapter registry, TAP driver may be not installed.")
	// Device Control Codes
	tap_win_ioctl_get_mac             = tap_control_code(1, 0)
	tap_win_ioctl_get_version         = tap_control_code(2, 0)
	tap_win_ioctl_get_mtu             = tap_control_code(3, 0)
	tap_win_ioctl_get_info            = tap_control_code(4, 0)
	tap_ioctl_config_point_to_point   = tap_control_code(5, 0)
	tap_ioctl_set_media_status        = tap_control_code(6, 0)
	tap_win_ioctl_config_dhcp_masq    = tap_control_code(7, 0)
	tap_win_ioctl_get_log_line        = tap_control_code(8, 0)
	tap_win_ioctl_config_dhcp_set_opt = tap_control_code(9, 0)
	tap_ioctl_config_tun              = tap_control_code(10, 0)
	// w32 api
	file_device_unknown = uint32(0x00000022)
	// Driver maker specified ComponentId
	// ComponentId is defined here: https://github.com/OpenVPN/tap-windows6/blob/master/version.m4#L5
	componentId = "tap0901"
)

func ctl_code(device_type, function, method, access uint32) uint32 {
	return (device_type << 16) | (access << 14) | (function << 2) | method
}

func tap_control_code(request, method uint32) uint32 {
	return ctl_code(file_device_unknown, request, method, 0)
}

// getdeviceid finds out a TAP device from registry, it *may* requires privileged right to prevent some weird issue.
func getdeviceid() (string, error) {
	// TAP driver key location
	regkey := `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
	k, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.READ)
	if err != nil {
		return "", RegistryOpenErr
	}
	defer k.Close()
	// read all subkeys, it should not return an err here
	keys, err := k.ReadSubKeyNames(-1)
	if err != nil {
		return "", err
	}
	// find the one matched ComponentId
	for _, v := range keys {
		key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey+"\\"+v, registry.READ)
		if err != nil {
			continue
		}
		val, _, err := key.GetStringValue("ComponentId")
		if err != nil {
			key.Close()
			continue
		}
		if val == componentId {
			val, _, err = key.GetStringValue("NetCfgInstanceId")
			if err != nil {
				key.Close()
				continue
			}
			key.Close()
			return val, nil
		}
		key.Close()
	}
	return "", TapDeviceNotFound
}

// openDev find and open an interface.
func openDev(isTAP bool) (ifce *Interface, err error) {
	// ifName won't work
	// find the device in registry.
	deviceid, err := getdeviceid()
	if err != nil {
		return nil, err
	}
	path := "\\\\.\\Global\\" + deviceid + ".tap"
	pathp, err := syscall.UTF16PtrFromString(path)
	if err != nil {
		return nil, err
	}
	// type Handle uintptr
	file, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), nil, syscall.OPEN_EXISTING, syscall.FILE_ATTRIBUTE_SYSTEM, 0)
	// if err hanppens, close the interface.
	defer func() {
		if err != nil {
			syscall.Close(file)
		}
		if err := recover(); err != nil {
			syscall.Close(file)
		}
	}()
	if err != nil {
		return nil, err
	}
	var bytesReturned uint32
	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)

	// find the mac address of tap device, use this to find the name of interface
	mac := make([]byte, 6)
	err = syscall.DeviceIoControl(file, tap_win_ioctl_get_mac, &mac[0], uint32(len(mac)), &mac[0], uint32(len(mac)), &bytesReturned, nil)
	if err != nil {
		return nil, err
	}

	fd := os.NewFile(uintptr(file), path)
	ifce = &Interface{isTAP: isTAP, ReadWriteCloser: fd}

	// bring up device.
	code := []byte{0x01, 0x00, 0x00, 0x00}
	err = syscall.DeviceIoControl(file, tap_ioctl_set_media_status, &code[0], uint32(4), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
	if err != nil {
		return
	}

	//TUN
	if !isTAP {
		code2 := []byte{0x0a, 0x03, 0x00, 0x01, 0x0a, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00}
		err = syscall.DeviceIoControl(file, tap_ioctl_config_tun, &code2[0], uint32(12), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
		if err != nil {
			return
		}
	}

	// find the name of tap interface(u need it to set the ip or other command)
	ifces, err := net.Interfaces()
	if err != nil {
		return
	}

	for _, v := range ifces {
		if bytes.Equal(v.HardwareAddr[:6], mac[:6]) {
			ifce.name = v.Name
			return
		}
	}

	err = IfceNameNotFound
	return
}

func newTAP(ifName string) (ifce *Interface, err error) {
	// ifName won't work
	return openDev(true)
}

func newTUN(ifName string) (ifce *Interface, err error) {
	// ifName won't work
	return openDev(false)
}
<|endoftext|>


<commit_before>package rest

import (
	"log"
	"net/http"
	"os"
)

// Handler describes an HTTP request handler.
//
// A simple contract guarantees robust request handling: if a handler returns an
// error status (>= 400), then the response has not yet been written and the
// client must still be shown an error message. If the error value is not nil,
// then something went wrong on the server and it should be logged/reported.
//
// In other words, the first return value is for the client's benefit, and the
// second return value is for the server. They are completely independent; an
// error status doesn't always mean the error will be non-nil. (For example,
// 404 Not Found is not usually a server error.)
type Handler func(w http.ResponseWriter, r *http.Request) (code int, err error)

// ServeHTTP implements http.Handler interface.
func (fn Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	code, err := fn(w, r)
	if code == 0 {
		w.WriteHeader(http.StatusNoContent)
	} else if code >= 400 {
		http.Error(w, http.StatusText(code), code)
	}
	if err != nil {
		log.Println("handler error:", err)
	}
}

// Handlers Handler.
func Handlers(handlers ...Handler) Handler {
	if len(handlers) == 1 {
		return handlers[0]
	}
	return func(w http.ResponseWriter, r *http.Request) (code int, err error) {
		for _, handler := range handlers {
			if code, err := handler(w, r); code != 0 || err != nil {
				return code, err
			}
		}
		return 0, nil
	}
}
<commit_msg>ServeFile<commit_after>package rest

import (
	"log"
	"net/http"
	"os"
)

// Handler describes an HTTP request handler.
//
// A simple contract guarantees robust request handling: if a handler returns an
// error status (>= 400), then the response has not yet been written and the
// client must still be shown an error message. If the error value is not nil,
// then something went wrong on the server and it should be logged/reported.
//
// In other words, the first return value is for the client's benefit, and the
// second return value is for the server. They are completely independent; an
// error status doesn't always mean the error will be non-nil. (For example,
// 404 Not Found is not usually a server error.)
type Handler func(w http.ResponseWriter, r *http.Request) (code int, err error)

// ServeHTTP implements http.Handler interface.
func (fn Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	code, err := fn(w, r)
	if code == 0 {
		w.WriteHeader(http.StatusNoContent)
	} else if code >= 400 {
		http.Error(w, http.StatusText(code), code)
	}
	if err != nil {
		log.Println("handler error:", err)
	}
}

// Handlers Handler.
func Handlers(handlers ...Handler) Handler {
	if len(handlers) == 1 {
		return handlers[0]
	}
	return func(w http.ResponseWriter, r *http.Request) (code int, err error) {
		for _, handler := range handlers {
			if code, err := handler(w, r); code != 0 || err != nil {
				return code, err
			}
		}
		return 0, nil
	}
}

// ServeFile replies to the request with the contents of the named file.
func ServeFile(filename string) Handler {
	return func(w http.ResponseWriter, r *http.Request) (code int, err error) {
		var fi os.FileInfo
		file, err := os.Open(filename)
		if err == nil {
			defer file.Close()
			fi, err = file.Stat()
		}
		switch {
		case err == nil:
			http.ServeContent(w, r, filename, fi.ModTime(), file)
			return http.StatusOK, nil
		case os.IsNotExist(err):
			return http.StatusNotFound, nil
		case os.IsPermission(err):
			return http.StatusForbidden, nil
		default:
			return http.StatusInternalServerError, err
		}
	}
}
<|endoftext|>


<commit_before>package dhcpv4

import (
	"errors"
	"fmt"
	"net"
	"time"

	"github.com/insomniacslk/dhcp/dhcpv4"
	"github.com/insomniacslk/dhcp/dhcpv4/async"
	"github.com/pinterest/bender"
)

// ResponseValidator validates a DHCPv4 response.
type ResponseValidator func(request, response *dhcpv4.DHCPv4) error

// CreateExecutor creates a new DHCPv4 RequestExecutor.
func CreateExecutor(client *async.Client, validator ResponseValidator) (bender.RequestExecutor, error) {
	send, err := newSendFunc(client)
	if err != nil {
		return nil, err
	}
	return func(_ int64, request interface{}) (interface{}, error) {
		dis, ok := request.(*dhcpv4.DHCPv4)
		if !ok {
			return nil, fmt.Errorf("invalid request type %T, want: *dhcpv4.DHCPv4", request)
		}
		off, err := send(dis, dhcpv4.MessageTypeOffer)
		if err != nil {
			return nil, err
		}
		req, err := dhcpv4.NewRequestFromOffer(off)
		if err != nil {
			return nil, err
		}
		ack, err := send(req, dhcpv4.MessageTypeAck)
		if err != nil {
			return nil, err
		}
		err = validator(dis, ack)
		return ack, err
	}, nil
}

// sendFunc represents a function used to send dhcpv4 datagrams
type sendFunc = func(*dhcpv4.DHCPv4, dhcpv4.MessageType) (*dhcpv4.DHCPv4, error)

// newSendFunc creates a function which will send messages using the given client
func newSendFunc(client *async.Client) (sendFunc, error) {
	addr, ok := client.LocalAddr.(*net.UDPAddr)
	if !ok {
		return nil, fmt.Errorf("invalid local address %T, want *net.UDPAddr", client.LocalAddr)
	}
	m := dhcpv4.WithRelay(addr.IP)
	t := uint(client.ReadTimeout / time.Millisecond)

	// send a message and check that the response is of a given type
	return func(d *dhcpv4.DHCPv4, mt dhcpv4.MessageType) (*dhcpv4.DHCPv4, error) {
		response, err, timeout := client.Send(d, m).GetOrTimeout(t)
		if timeout {
			return nil, errors.New("timeout")
		} else if err != nil {
			return nil, err
		}
		res, ok := response.(*dhcpv4.DHCPv4)
		if !ok {
			return nil, fmt.Errorf("invalid response type %T, want: *dhcpv4.DHCPv4", response)
		}
		if err := assertMessageType(res, mt); err != nil {
			return nil, err
		}
		return res, nil
	}, nil
}

// assertMessageType extracts message type and checks if it matches expected
func assertMessageType(d *dhcpv4.DHCPv4, mt dhcpv4.MessageType) error {
	t := d.MessageType()
	if t == nil {
		return fmt.Errorf("unable to extract message type")
	}
	if *t != mt {
		return fmt.Errorf("invalid message type %s, want: %s", t.String(), mt.String())
	}
	return nil
}
<commit_msg>[dhcpv4] fix build<commit_after>package dhcpv4

import (
	"errors"
	"fmt"
	"net"
	"time"

	"github.com/insomniacslk/dhcp/dhcpv4"
	"github.com/insomniacslk/dhcp/dhcpv4/async"
	"github.com/pinterest/bender"
)

// ResponseValidator validates a DHCPv4 response.
type ResponseValidator func(request, response *dhcpv4.DHCPv4) error

// CreateExecutor creates a new DHCPv4 RequestExecutor.
func CreateExecutor(client *async.Client, validator ResponseValidator) (bender.RequestExecutor, error) {
	send, err := newSendFunc(client)
	if err != nil {
		return nil, err
	}
	return func(_ int64, request interface{}) (interface{}, error) {
		dis, ok := request.(*dhcpv4.DHCPv4)
		if !ok {
			return nil, fmt.Errorf("invalid request type %T, want: *dhcpv4.DHCPv4", request)
		}
		off, err := send(dis, dhcpv4.MessageTypeOffer)
		if err != nil {
			return nil, err
		}
		req, err := dhcpv4.NewRequestFromOffer(off)
		if err != nil {
			return nil, err
		}
		ack, err := send(req, dhcpv4.MessageTypeAck)
		if err != nil {
			return nil, err
		}
		err = validator(dis, ack)
		return ack, err
	}, nil
}

// sendFunc represents a function used to send dhcpv4 datagrams
type sendFunc = func(*dhcpv4.DHCPv4, dhcpv4.MessageType) (*dhcpv4.DHCPv4, error)

// newSendFunc creates a function which will send messages using the given client
func newSendFunc(client *async.Client) (sendFunc, error) {
	addr, ok := client.LocalAddr.(*net.UDPAddr)
	if !ok {
		return nil, fmt.Errorf("invalid local address %T, want *net.UDPAddr", client.LocalAddr)
	}
	m := dhcpv4.WithRelay(addr.IP)
	t := uint(client.ReadTimeout / time.Millisecond)

	// send a message and check that the response is of a given type
	return func(d *dhcpv4.DHCPv4, mt dhcpv4.MessageType) (*dhcpv4.DHCPv4, error) {
		response, err, timeout := client.Send(d, m).GetOrTimeout(t)
		if timeout {
			return nil, errors.New("timeout")
		} else if err != nil {
			return nil, err
		}
		res, ok := response.(*dhcpv4.DHCPv4)
		if !ok {
			return nil, fmt.Errorf("invalid response type %T, want: *dhcpv4.DHCPv4", response)
		}
		if err := assertMessageType(res, mt); err != nil {
			return nil, err
		}
		return res, nil
	}, nil
}

// assertMessageType extracts message type and checks if it matches expected
func assertMessageType(d *dhcpv4.DHCPv4, mt dhcpv4.MessageType) error {
	t := d.MessageType()
	if t != mt {
		return fmt.Errorf("invalid message type %s, want: %s", t.String(), mt.String())
	}
	return nil
}
<|endoftext|>


<commit_before>package item

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"unicode"

	"github.com/blevesearch/bleve"
	"github.com/blevesearch/bleve/mapping"
	uuid "github.com/satori/go.uuid"
	"golang.org/x/text/transform"
	"golang.org/x/text/unicode/norm"
)

// Sluggable makes a struct locatable by URL with it's own path.
// As an Item implementing Sluggable, slugs may overlap. If this is an issue,
// make your content struct (or one which embeds Item) implement Sluggable
// and it will override the slug created by Item's SetSlug with your own
type Sluggable interface {
	SetSlug(string)
	ItemSlug() string
}

// Identifiable enables a struct to have its ID set/get. Typically this is done
// to set an ID to -1 indicating it is new for DB inserts, since by default
// a newly initialized struct would have an ID of 0, the int zero-value, and
// BoltDB's starting key per bucket is 0, thus overwriting the first record.
type Identifiable interface {
	ItemID() int
	SetItemID(int)
	UniqueID() uuid.UUID
	String() string
}

// Sortable ensures data is sortable by time
type Sortable interface {
	Time() int64
	Touch() int64
}

// Hookable provides our user with an easy way to intercept or add functionality
// to the different lifecycles/events a struct may encounter. Item implements
// Hookable with no-ops so our user can override only whichever ones necessary.
type Hookable interface {
	BeforeAPICreate(http.ResponseWriter, *http.Request) error
	AfterAPICreate(http.ResponseWriter, *http.Request) error

	BeforeAPIUpdate(http.ResponseWriter, *http.Request) error
	AfterAPIUpdate(http.ResponseWriter, *http.Request) error

	BeforeAPIDelete(http.ResponseWriter, *http.Request) error
	AfterAPIDelete(http.ResponseWriter, *http.Request) error

	BeforeSave(http.ResponseWriter, *http.Request) error
	AfterSave(http.ResponseWriter, *http.Request) error

	BeforeDelete(http.ResponseWriter, *http.Request) error
	AfterDelete(http.ResponseWriter, *http.Request) error

	BeforeApprove(http.ResponseWriter, *http.Request) error
	AfterApprove(http.ResponseWriter, *http.Request) error

	BeforeReject(http.ResponseWriter, *http.Request) error
	AfterReject(http.ResponseWriter, *http.Request) error
}

// Hideable lets a user keep items hidden
type Hideable interface {
	Hide(http.ResponseWriter, *http.Request) error
}

// Pushable lets a user define which values of certain struct fields are
// 'pushed' down to  a client via HTTP/2 Server Push. All items in the slice
// should be the json tag names of the struct fields to which they correspond.
type Pushable interface {
	// the values contained by fields returned by Push must strictly be URL paths
	Push() []string
}

// Omittable lets a user define certin fields within a content struct to remove
// from an API response. Helpful when you want data in the CMS, but not entirely
// shown or available from the content API. All items in the slice should be the
// json tag names of the struct fields to which they correspond.
type Omittable interface {
	Omit() []string
}

// Item should only be embedded into content type structs.
type Item struct {
	UUID      uuid.UUID `json:"uuid"`
	ID        int       `json:"id"`
	Slug      string    `json:"slug"`
	Timestamp int64     `json:"timestamp"`
	Updated   int64     `json:"updated"`
}

// Time partially implements the Sortable interface
func (i Item) Time() int64 {
	return i.Timestamp
}

// Touch partially implements the Sortable interface
func (i Item) Touch() int64 {
	return i.Updated
}

// SetSlug sets the item's slug for its URL
func (i *Item) SetSlug(slug string) {
	i.Slug = slug
}

// ItemSlug sets the item's slug for its URL
func (i *Item) ItemSlug() string {
	return i.Slug
}

// ItemID gets the Item's ID field
// partially implements the Identifiable interface
func (i Item) ItemID() int {
	return i.ID
}

// SetItemID sets the Item's ID field
// partially implements the Identifiable interface
func (i *Item) SetItemID(id int) {
	i.ID = id
}

// UniqueID gets the Item's UUID field
// partially implements the Identifiable interface
func (i Item) UniqueID() uuid.UUID {
	return i.UUID
}

// String formats an Item into a printable value
// partially implements the Identifiable interface
func (i Item) String() string {
	return fmt.Sprintf("Item ID: %s", i.UniqueID())
}

// BeforeAPICreate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeAPICreate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterAPICreate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterAPICreate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeAPIUpdate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeAPIUpdate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterAPIUpdate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterAPIUpdate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeAPIDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeAPIDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterAPIDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterAPIDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeSave is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeSave(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterSave is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterSave(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeApprove is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeApprove(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterApprove is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterApprove(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeReject is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeReject(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterReject is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterReject(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// SearchMapping returns a default implementation of a Bleve IndexMappingImpl
// partially implements db.Searchable
func SearchMapping() *mapping.IndexMappingImpl {
	mapping := bleve.NewIndexMapping()
	mapping.StoreDynamic = false

	return mapping
}

// Slug returns a URL friendly string from the title of a post item
func Slug(i Identifiable) (string, error) {
	// get the name of the post item
	name := strings.TrimSpace(i.String())

	// filter out non-alphanumeric character or non-whitespace
	slug, err := stringToSlug(name)
	if err != nil {
		return "", err
	}

	return slug, nil
}

func isMn(r rune) bool {
	return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
}

// modified version of: https://www.socketloop.com/tutorials/golang-format-strings-to-seo-friendly-url-example
func stringToSlug(s string) (string, error) {
	src := []byte(strings.ToLower(s))

	// convert all spaces to dash
	rx := regexp.MustCompile("[[:space:]]")
	src = rx.ReplaceAll(src, []byte("-"))

	// remove all blanks such as tab
	rx = regexp.MustCompile("[[:blank:]]")
	src = rx.ReplaceAll(src, []byte(""))

	rx = regexp.MustCompile("[!/:-@[-`{-~]")
	src = rx.ReplaceAll(src, []byte(""))

	rx = regexp.MustCompile("/[^\x20-\x7F]/")
	src = rx.ReplaceAll(src, []byte(""))

	rx = regexp.MustCompile("`&(amp;)?#?[a-z0-9]+;`i")
	src = rx.ReplaceAll(src, []byte("-"))

	rx = regexp.MustCompile("`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);`i")
	src = rx.ReplaceAll(src, []byte("\\1"))

	rx = regexp.MustCompile("`[^a-z0-9]`i")
	src = rx.ReplaceAll(src, []byte("-"))

	rx = regexp.MustCompile("`[-]+`")
	src = rx.ReplaceAll(src, []byte("-"))

	str := strings.Replace(string(src), "'", "", -1)
	str = strings.Replace(str, `"`, "", -1)
	str = strings.Replace(str, "&", "-", -1)

	t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
	slug, _, err := transform.String(t, str)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(slug), nil
}

// NormalizeString removes and replaces illegal characters for URLs and other
// path entities. Useful for taking user input and converting it for keys or URLs.
func NormalizeString(s string) (string, error) {
	return stringToSlug(s)
}
<commit_msg>default implementation fix<commit_after>package item

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"
	"unicode"

	"github.com/blevesearch/bleve"
	"github.com/blevesearch/bleve/mapping"
	uuid "github.com/satori/go.uuid"
	"golang.org/x/text/transform"
	"golang.org/x/text/unicode/norm"
)

// Sluggable makes a struct locatable by URL with it's own path.
// As an Item implementing Sluggable, slugs may overlap. If this is an issue,
// make your content struct (or one which embeds Item) implement Sluggable
// and it will override the slug created by Item's SetSlug with your own
type Sluggable interface {
	SetSlug(string)
	ItemSlug() string
}

// Identifiable enables a struct to have its ID set/get. Typically this is done
// to set an ID to -1 indicating it is new for DB inserts, since by default
// a newly initialized struct would have an ID of 0, the int zero-value, and
// BoltDB's starting key per bucket is 0, thus overwriting the first record.
type Identifiable interface {
	ItemID() int
	SetItemID(int)
	UniqueID() uuid.UUID
	String() string
}

// Sortable ensures data is sortable by time
type Sortable interface {
	Time() int64
	Touch() int64
}

// Hookable provides our user with an easy way to intercept or add functionality
// to the different lifecycles/events a struct may encounter. Item implements
// Hookable with no-ops so our user can override only whichever ones necessary.
type Hookable interface {
	BeforeAPICreate(http.ResponseWriter, *http.Request) error
	AfterAPICreate(http.ResponseWriter, *http.Request) error

	BeforeAPIUpdate(http.ResponseWriter, *http.Request) error
	AfterAPIUpdate(http.ResponseWriter, *http.Request) error

	BeforeAPIDelete(http.ResponseWriter, *http.Request) error
	AfterAPIDelete(http.ResponseWriter, *http.Request) error

	BeforeSave(http.ResponseWriter, *http.Request) error
	AfterSave(http.ResponseWriter, *http.Request) error

	BeforeDelete(http.ResponseWriter, *http.Request) error
	AfterDelete(http.ResponseWriter, *http.Request) error

	BeforeApprove(http.ResponseWriter, *http.Request) error
	AfterApprove(http.ResponseWriter, *http.Request) error

	BeforeReject(http.ResponseWriter, *http.Request) error
	AfterReject(http.ResponseWriter, *http.Request) error
}

// Hideable lets a user keep items hidden
type Hideable interface {
	Hide(http.ResponseWriter, *http.Request) error
}

// Pushable lets a user define which values of certain struct fields are
// 'pushed' down to  a client via HTTP/2 Server Push. All items in the slice
// should be the json tag names of the struct fields to which they correspond.
type Pushable interface {
	// the values contained by fields returned by Push must strictly be URL paths
	Push() []string
}

// Omittable lets a user define certin fields within a content struct to remove
// from an API response. Helpful when you want data in the CMS, but not entirely
// shown or available from the content API. All items in the slice should be the
// json tag names of the struct fields to which they correspond.
type Omittable interface {
	Omit() []string
}

// Item should only be embedded into content type structs.
type Item struct {
	UUID      uuid.UUID `json:"uuid"`
	ID        int       `json:"id"`
	Slug      string    `json:"slug"`
	Timestamp int64     `json:"timestamp"`
	Updated   int64     `json:"updated"`
}

// Time partially implements the Sortable interface
func (i Item) Time() int64 {
	return i.Timestamp
}

// Touch partially implements the Sortable interface
func (i Item) Touch() int64 {
	return i.Updated
}

// SetSlug sets the item's slug for its URL
func (i *Item) SetSlug(slug string) {
	i.Slug = slug
}

// ItemSlug sets the item's slug for its URL
func (i *Item) ItemSlug() string {
	return i.Slug
}

// ItemID gets the Item's ID field
// partially implements the Identifiable interface
func (i Item) ItemID() int {
	return i.ID
}

// SetItemID sets the Item's ID field
// partially implements the Identifiable interface
func (i *Item) SetItemID(id int) {
	i.ID = id
}

// UniqueID gets the Item's UUID field
// partially implements the Identifiable interface
func (i Item) UniqueID() uuid.UUID {
	return i.UUID
}

// String formats an Item into a printable value
// partially implements the Identifiable interface
func (i Item) String() string {
	return fmt.Sprintf("Item ID: %s", i.UniqueID())
}

// BeforeAPICreate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeAPICreate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterAPICreate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterAPICreate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeAPIUpdate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeAPIUpdate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterAPIUpdate is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterAPIUpdate(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeAPIDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeAPIDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterAPIDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterAPIDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeSave is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeSave(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterSave is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterSave(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterDelete is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterDelete(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeApprove is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeApprove(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterApprove is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterApprove(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// BeforeReject is a no-op to ensure structs which embed Item implement Hookable
func (i Item) BeforeReject(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// AfterReject is a no-op to ensure structs which embed Item implement Hookable
func (i Item) AfterReject(res http.ResponseWriter, req *http.Request) error {
	return nil
}

// SearchMapping returns a default implementation of a Bleve IndexMappingImpl
// partially implements db.Searchable
func (i Item) SearchMapping() *mapping.IndexMappingImpl {
	mapping := bleve.NewIndexMapping()
	mapping.StoreDynamic = false

	return mapping
}

// Slug returns a URL friendly string from the title of a post item
func Slug(i Identifiable) (string, error) {
	// get the name of the post item
	name := strings.TrimSpace(i.String())

	// filter out non-alphanumeric character or non-whitespace
	slug, err := stringToSlug(name)
	if err != nil {
		return "", err
	}

	return slug, nil
}

func isMn(r rune) bool {
	return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
}

// modified version of: https://www.socketloop.com/tutorials/golang-format-strings-to-seo-friendly-url-example
func stringToSlug(s string) (string, error) {
	src := []byte(strings.ToLower(s))

	// convert all spaces to dash
	rx := regexp.MustCompile("[[:space:]]")
	src = rx.ReplaceAll(src, []byte("-"))

	// remove all blanks such as tab
	rx = regexp.MustCompile("[[:blank:]]")
	src = rx.ReplaceAll(src, []byte(""))

	rx = regexp.MustCompile("[!/:-@[-`{-~]")
	src = rx.ReplaceAll(src, []byte(""))

	rx = regexp.MustCompile("/[^\x20-\x7F]/")
	src = rx.ReplaceAll(src, []byte(""))

	rx = regexp.MustCompile("`&(amp;)?#?[a-z0-9]+;`i")
	src = rx.ReplaceAll(src, []byte("-"))

	rx = regexp.MustCompile("`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig|quot|rsquo);`i")
	src = rx.ReplaceAll(src, []byte("\\1"))

	rx = regexp.MustCompile("`[^a-z0-9]`i")
	src = rx.ReplaceAll(src, []byte("-"))

	rx = regexp.MustCompile("`[-]+`")
	src = rx.ReplaceAll(src, []byte("-"))

	str := strings.Replace(string(src), "'", "", -1)
	str = strings.Replace(str, `"`, "", -1)
	str = strings.Replace(str, "&", "-", -1)

	t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
	slug, _, err := transform.String(t, str)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(slug), nil
}

// NormalizeString removes and replaces illegal characters for URLs and other
// path entities. Useful for taking user input and converting it for keys or URLs.
func NormalizeString(s string) (string, error) {
	return stringToSlug(s)
}
<|endoftext|>