func processCommand(client Client, payload []byte) error {
	cmd, blob := payload[0], payload[1:]
	switch cmd {
	case RemoveTopic:
		if len(blob) != e4crypto.HashLen {
			return errors.New("invalid RemoveTopic length")
		}
		return client.removeTopic(blob)
	case ResetTopics:
		if len(blob) != 0 {
			return errors.New("invalid ResetTopics length")
		}
		return client.resetTopics()
	case SetIDKey:
		if len(blob) != e4crypto.KeyLen && len(blob) != ed25519.PrivateKeySize {
			return errors.New("invalid SetIDKey length")
		}
		return client.setIDKey(blob)
	case SetTopicKey:
		if len(blob) != e4crypto.KeyLen+e4crypto.HashLen {
			return errors.New("invalid SetTopicKey length")
		}
		return client.setTopicKey(blob[:e4crypto.KeyLen], blob[e4crypto.KeyLen:])
	case RemovePubKey:
		if len(blob) != e4crypto.IDLen {
			return errors.New("invalid RemovePubKey length")
		}
		return client.removePubKey(blob)
	case ResetPubKeys:
		if len(blob) != 0 {
			return errors.New("invalid ResetPubKeys length")
		}
		return client.resetPubKeys()
	case SetPubKey:
		if len(blob) != ed25519.PublicKeySize+e4crypto.IDLen {
			return errors.New("invalid SetPubKey length")
		}
		return client.setPubKey(blob[:ed25519.PublicKeySize], blob[ed25519.PublicKeySize:])
	case SetC2Key:
		if len(blob) != e4crypto.Curve25519PubKeyLen {
			return errors.New("invalid SetC2Key length")
		}
		return client.setC2Key(blob[:e4crypto.Curve25519PubKeyLen])
	default:
		return ErrInvalidCommand
	}
}
processCommand will attempt to parse given command
and extract arguments to call expected Client method
package e4
import (
	"errors"
	"fmt"
	"golang.org/x/crypto/ed25519"
	e4crypto "github.com/teserakt-io/e4go/crypto"
)
const (
	RemoveTopic byte = iota
	ResetTopics
	SetIDKey
	SetTopicKey
	RemovePubKey
	ResetPubKeys
	SetPubKey
	SetC2Key
	UnknownCommand = 0xFF
)
var (
	ErrInvalidCommand = errors.New("invalid command")
)