mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	
		
			
				
	
	
		
			169 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package gomemcached
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/binary"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| type TapConnectFlag uint32
 | |
| 
 | |
| // Tap connect option flags
 | |
| const (
 | |
| 	BACKFILL           = TapConnectFlag(0x01)
 | |
| 	DUMP               = TapConnectFlag(0x02)
 | |
| 	LIST_VBUCKETS      = TapConnectFlag(0x04)
 | |
| 	TAKEOVER_VBUCKETS  = TapConnectFlag(0x08)
 | |
| 	SUPPORT_ACK        = TapConnectFlag(0x10)
 | |
| 	REQUEST_KEYS_ONLY  = TapConnectFlag(0x20)
 | |
| 	CHECKPOINT         = TapConnectFlag(0x40)
 | |
| 	REGISTERED_CLIENT  = TapConnectFlag(0x80)
 | |
| 	FIX_FLAG_BYTEORDER = TapConnectFlag(0x100)
 | |
| )
 | |
| 
 | |
| // Tap opaque event subtypes
 | |
| const (
 | |
| 	TAP_OPAQUE_ENABLE_AUTO_NACK       = 0
 | |
| 	TAP_OPAQUE_INITIAL_VBUCKET_STREAM = 1
 | |
| 	TAP_OPAQUE_ENABLE_CHECKPOINT_SYNC = 2
 | |
| 	TAP_OPAQUE_CLOSE_TAP_STREAM       = 7
 | |
| 	TAP_OPAQUE_CLOSE_BACKFILL         = 8
 | |
| )
 | |
| 
 | |
| // Tap item flags
 | |
| const (
 | |
| 	TAP_ACK                     = 1
 | |
| 	TAP_NO_VALUE                = 2
 | |
| 	TAP_FLAG_NETWORK_BYTE_ORDER = 4
 | |
| )
 | |
| 
 | |
| // TapConnectFlagNames for TapConnectFlag
 | |
| var TapConnectFlagNames = map[TapConnectFlag]string{
 | |
| 	BACKFILL:           "BACKFILL",
 | |
| 	DUMP:               "DUMP",
 | |
| 	LIST_VBUCKETS:      "LIST_VBUCKETS",
 | |
| 	TAKEOVER_VBUCKETS:  "TAKEOVER_VBUCKETS",
 | |
| 	SUPPORT_ACK:        "SUPPORT_ACK",
 | |
| 	REQUEST_KEYS_ONLY:  "REQUEST_KEYS_ONLY",
 | |
| 	CHECKPOINT:         "CHECKPOINT",
 | |
| 	REGISTERED_CLIENT:  "REGISTERED_CLIENT",
 | |
| 	FIX_FLAG_BYTEORDER: "FIX_FLAG_BYTEORDER",
 | |
| }
 | |
| 
 | |
| // TapItemParser is a function to parse a single tap extra.
 | |
| type TapItemParser func(io.Reader) (interface{}, error)
 | |
| 
 | |
| // TapParseUint64 is a function to parse a single tap uint64.
 | |
| func TapParseUint64(r io.Reader) (interface{}, error) {
 | |
| 	var rv uint64
 | |
| 	err := binary.Read(r, binary.BigEndian, &rv)
 | |
| 	return rv, err
 | |
| }
 | |
| 
 | |
| // TapParseUint16 is a function to parse a single tap uint16.
 | |
| func TapParseUint16(r io.Reader) (interface{}, error) {
 | |
| 	var rv uint16
 | |
| 	err := binary.Read(r, binary.BigEndian, &rv)
 | |
| 	return rv, err
 | |
| }
 | |
| 
 | |
| // TapParseBool is a function to parse a single tap boolean.
 | |
| func TapParseBool(r io.Reader) (interface{}, error) {
 | |
| 	return true, nil
 | |
| }
 | |
| 
 | |
| // TapParseVBList parses a list of vBucket numbers as []uint16.
 | |
| func TapParseVBList(r io.Reader) (interface{}, error) {
 | |
| 	num, err := TapParseUint16(r)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	n := int(num.(uint16))
 | |
| 
 | |
| 	rv := make([]uint16, n)
 | |
| 	for i := 0; i < n; i++ {
 | |
| 		x, err := TapParseUint16(r)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		rv[i] = x.(uint16)
 | |
| 	}
 | |
| 
 | |
| 	return rv, err
 | |
| }
 | |
| 
 | |
| // TapFlagParsers parser functions for TAP fields.
 | |
| var TapFlagParsers = map[TapConnectFlag]TapItemParser{
 | |
| 	BACKFILL:      TapParseUint64,
 | |
| 	LIST_VBUCKETS: TapParseVBList,
 | |
| }
 | |
| 
 | |
| // SplitFlags will split the ORed flags into the individual bit flags.
 | |
| func (f TapConnectFlag) SplitFlags() []TapConnectFlag {
 | |
| 	rv := []TapConnectFlag{}
 | |
| 	for i := uint32(1); f != 0; i = i << 1 {
 | |
| 		if uint32(f)&i == i {
 | |
| 			rv = append(rv, TapConnectFlag(i))
 | |
| 		}
 | |
| 		f = TapConnectFlag(uint32(f) & (^i))
 | |
| 	}
 | |
| 	return rv
 | |
| }
 | |
| 
 | |
| func (f TapConnectFlag) String() string {
 | |
| 	parts := []string{}
 | |
| 	for _, x := range f.SplitFlags() {
 | |
| 		p := TapConnectFlagNames[x]
 | |
| 		if p == "" {
 | |
| 			p = fmt.Sprintf("0x%x", int(x))
 | |
| 		}
 | |
| 		parts = append(parts, p)
 | |
| 	}
 | |
| 	return strings.Join(parts, "|")
 | |
| }
 | |
| 
 | |
| type TapConnect struct {
 | |
| 	Flags         map[TapConnectFlag]interface{}
 | |
| 	RemainingBody []byte
 | |
| 	Name          string
 | |
| }
 | |
| 
 | |
| // ParseTapCommands parse the tap request into the interesting bits we may
 | |
| // need to do something with.
 | |
| func (req *MCRequest) ParseTapCommands() (TapConnect, error) {
 | |
| 	rv := TapConnect{
 | |
| 		Flags: map[TapConnectFlag]interface{}{},
 | |
| 		Name:  string(req.Key),
 | |
| 	}
 | |
| 
 | |
| 	if len(req.Extras) < 4 {
 | |
| 		return rv, fmt.Errorf("not enough extra bytes: %x", req.Extras)
 | |
| 	}
 | |
| 
 | |
| 	flags := TapConnectFlag(binary.BigEndian.Uint32(req.Extras))
 | |
| 
 | |
| 	r := bytes.NewReader(req.Body)
 | |
| 
 | |
| 	for _, f := range flags.SplitFlags() {
 | |
| 		fun := TapFlagParsers[f]
 | |
| 		if fun == nil {
 | |
| 			fun = TapParseBool
 | |
| 		}
 | |
| 
 | |
| 		val, err := fun(r)
 | |
| 		if err != nil {
 | |
| 			return rv, err
 | |
| 		}
 | |
| 
 | |
| 		rv.Flags[f] = val
 | |
| 	}
 | |
| 
 | |
| 	var err error
 | |
| 	rv.RemainingBody, err = ioutil.ReadAll(r)
 | |
| 
 | |
| 	return rv, err
 | |
| }
 |