Commit fcd6f9f6 authored by Kirill Smelkov's avatar Kirill Smelkov

go/neo/proto: String/Error/Address/UUID conversion

Provide routines to convert selected types to string and also for
UUID and Address <-> string  encoding/decoding.
parent 6301c23f
// Copyright (C) 2017-2018 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
//go:generate stringer -output zproto-str.go -type ErrorCode,ClusterState,NodeType,NodeState,CellState proto.go
package proto
// supporting code for types defined in proto.go
import (
"fmt"
"math"
"net"
"strconv"
"strings"
"time"
)
func (e *Error) Error() string {
// NOTE here, not in proto.go - because else stringer will be confused.
// XXX better translate to some other errors?
s := e.Code.String()
if e.Message != "" {
s += ": " + e.Message
}
return s
}
// node type -> character representing it.
const nodeTypeChar = "SMCA" // NOTE neo/py does this out of sync with NodeType constants.
// String returns string representation of a node uuid.
//
// It returns ex 'S1', 'M2', ...
func (nodeUUID NodeUUID) String() string {
if nodeUUID == 0 {
return "?(0)0"
}
num := nodeUUID & (1<<24 - 1)
// XXX UUID_NAMESPACES description does not match neo/py code
//typ := nodeUUID >> 24
//temp := typ&(1 << 7) != 0
//typ &= 1<<7 - 1
//nodeType := typ >> 4
typ := uint8(-int8(nodeUUID>>24)) >> 4
if typ < 4 {
return fmt.Sprintf("%c%d", nodeTypeChar[typ], num)
}
return fmt.Sprintf("?(%d)%d", typ, num)
/*
// 's1', 'm2', for temporary nids
if temp {
s = strings.ToLower(s)
}
return s
*/
}
// XXX goes out of sync wrt NodeType constants
var nodeTypeNum = [...]int8{
STORAGE: 0x00,
MASTER: -0x10,
CLIENT: -0x20,
ADMIN: -0x30,
}
// UUID creates node uuid from node type and number.
func UUID(typ NodeType, num int32) NodeUUID {
// XXX neo/py does not what UUID_NAMESPACES describes
/*
temp := uint32(0)
if num < 0 {
temp = 1
num = -num
}
*/
if int(typ) >= len(nodeTypeNum) {
panic("typ invalid")
}
typn := nodeTypeNum[typ]
if (num < 0) || num>>24 != 0 {
panic("node number out of range")
}
//uuid := temp << (7 + 3*8) | uint32(typ) << (4 + 3*8) | uint32(num)
uuid := uint32(uint8(typn))<<(3*8) | uint32(num)
return NodeUUID(uuid)
}
// ----------------------------------------
// IdTimeNone represents None passed as identification time.
var IdTimeNone = IdTime(math.Inf(-1))
func (t IdTime) String() string {
if float64(t) == math.Inf(-1) {
return "ø"
}
sec := int64(t)
nsec := int64((float64(t) - float64(sec)) * 1E9)
return time.Unix(sec, nsec).String()
}
// ----------------------------------------
// AddrString converts network address string into NEO Address.
//
// TODO make neo.Address just string without host:port split
func AddrString(network, addr string) (Address, error) {
// empty is always empty
if addr == "" {
return Address{}, nil
}
// e.g. on unix, networks there is no host/port split - the address there
// is single string -> we put it into .Host and set .Port=0 to indicate such cases
switch {
default:
return Address{Host: addr, Port: 0}, nil
// networks that have host:port split
case strings.HasPrefix(network, "tcp"):
case strings.HasPrefix(network, "udp"):
case strings.HasPrefix(network, "pipe"):
}
host, portstr, err := net.SplitHostPort(addr)
if err != nil {
return Address{}, err
}
// XXX also lookup portstr in /etc/services (net.LookupPort) ?
port, err := strconv.ParseUint(portstr, 10, 16)
if err != nil {
return Address{}, &net.AddrError{Err: "invalid port", Addr: addr}
}
return Address{Host: host, Port: uint16(port)}, nil
}
// Addr converts net.Addr into NEO Address.
func Addr(addr net.Addr) (Address, error) {
return AddrString(addr.Network(), addr.String())
}
// String formats Address to networked address string.
func (addr Address) String() string {
// XXX in py if .Host == "" -> whole Address is assumed to be empty
// see Addr ^^^ about .Port=0 meaning no host:port split was applied
switch addr.Port {
case 0:
return addr.Host
default:
return net.JoinHostPort(addr.Host, fmt.Sprintf("%d", addr.Port))
}
}
// Copyright (C) 2016-2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.
package proto
import (
"testing"
)
func TestUUID(t *testing.T) {
var testv = []struct{typ NodeType; num int32; uuid uint32; str string}{
{STORAGE, 1, 0x00000001, "S1"},
{MASTER, 2, 0xf0000002, "M2"},
{CLIENT, 3, 0xe0000003, "C3"},
{ADMIN, 4, 0xd0000004, "A4"},
}
for _, tt := range testv {
uuid := UUID(tt.typ, tt.num)
if uint32(uuid) != tt.uuid {
t.Errorf("%v: uuid=%08x ; want %08x", tt, uuid, tt.uuid)
}
if uuids := uuid.String(); uuids != tt.str {
t.Errorf("%v: str(uuid): %q ; want %q", tt, uuids, tt.str)
}
}
}
func TestUUIDDecode(t *testing.T) {
var testv = []struct{uuid uint32; str string}{
{0, "?(0)0"},
{0x00000001, "S1"},
{0xf0000002, "M2"},
{0xe0000003, "C3"},
{0xd0000004, "A4"},
{0xc0000005, "?(4)5"},
{0xb0000006, "?(5)6"},
{0xa0000007, "?(6)7"},
{0x90000008, "?(7)8"},
{0x80000009, "?(8)9"},
{0x7000000a, "?(9)10"},
{0x6000000b, "?(10)11"},
{0x5000000c, "?(11)12"},
{0x4000000d, "?(12)13"},
{0x3000000e, "?(13)14"},
{0x2000000f, "?(14)15"},
{0x10000010, "?(15)16"},
{0x00000011, "S17"},
}
for _, tt := range testv {
str := NodeUUID(tt.uuid).String()
if str != tt.str {
t.Errorf("%08x -> %q ; want %q", tt.uuid, str, tt.str)
}
}
}
// Code generated by "stringer -output zproto-str.go -type ErrorCode,ClusterState,NodeType,NodeState,CellState proto.go"; DO NOT EDIT.
package proto
import "strconv"
const _ErrorCode_name = "ACKNOT_READYOID_NOT_FOUNDTID_NOT_FOUNDOID_DOES_NOT_EXISTPROTOCOL_ERRORREPLICATION_ERRORCHECKING_ERRORBACKEND_NOT_IMPLEMENTEDNON_READABLE_CELLREAD_ONLY_ACCESSINCOMPLETE_TRANSACTION"
var _ErrorCode_index = [...]uint8{0, 3, 12, 25, 38, 56, 70, 87, 101, 124, 141, 157, 179}
func (i ErrorCode) String() string {
if i >= ErrorCode(len(_ErrorCode_index)-1) {
return "ErrorCode(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
}
const _ClusterState_name = "ClusterRecoveringClusterVerifyingClusterRunningClusterStoppingSTARTING_BACKUPBACKINGUPSTOPPING_BACKUP"
var _ClusterState_index = [...]uint8{0, 17, 33, 47, 62, 77, 86, 101}
func (i ClusterState) String() string {
if i < 0 || i >= ClusterState(len(_ClusterState_index)-1) {
return "ClusterState(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _ClusterState_name[_ClusterState_index[i]:_ClusterState_index[i+1]]
}
const _NodeType_name = "MASTERSTORAGECLIENTADMIN"
var _NodeType_index = [...]uint8{0, 6, 13, 19, 24}
func (i NodeType) String() string {
if i < 0 || i >= NodeType(len(_NodeType_index)-1) {
return "NodeType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _NodeType_name[_NodeType_index[i]:_NodeType_index[i+1]]
}
const _NodeState_name = "UNKNOWNDOWNRUNNINGPENDING"
var _NodeState_index = [...]uint8{0, 7, 11, 18, 25}
func (i NodeState) String() string {
if i < 0 || i >= NodeState(len(_NodeState_index)-1) {
return "NodeState(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _NodeState_name[_NodeState_index[i]:_NodeState_index[i+1]]
}
const _CellState_name = "UP_TO_DATEOUT_OF_DATEFEEDINGDISCARDEDCORRUPTED"
var _CellState_index = [...]uint8{0, 10, 21, 28, 37, 46}
func (i CellState) String() string {
if i < 0 || i >= CellState(len(_CellState_index)-1) {
return "CellState(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _CellState_name[_CellState_index[i]:_CellState_index[i+1]]
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment