blob: ae0325708eb54f09e230dd2d0b3851afc010328a [file] [log] [blame]
// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package proto contains the protocol buffer definitions shared between RPC
// servers and clients, mirroring the interfaces and types in the upspin
// package itself.
//
// These protocol buffers are used in the networking API to talk to Upspin
// servers. The wire protocol is described by package upspin.io/rpc.
//
// Unlike in some other systems, the protocol buffer types themselves are not
// used within the rest of the Upspin implementation. Instead, native Go types
// are used internally and they are converted to the protocol buffer types
// across the boundary. Helper routines in this package assist in the
// translation.
//
// Within the protocol buffers, some of the types are stored as uninterpreted
// bytes that are transcoded with custom code. For instance, the
// upspin.io/errors.Error type is transmitted as a byte slice that is marshaled
// and unmarshaled using the MarshalError and UnmarshalError routines in the
// errors package. This technique preserves the properties of the Go type across
// the network.
package proto // import "upspin.io/upspin/proto"
import (
"time"
"upspin.io/errors"
"upspin.io/upspin"
)
// To regenerate the protocol buffer output for this package, run
// go generate
//go:generate protoc upspin.proto --go_out=.
// All these converters are an unfortunate side-effect of not letting protobufs rule our types.
// UpspinLocation converts a proto Location struct to upspin.Location.
func UpspinLocation(loc *Location) upspin.Location {
if loc == nil {
return upspin.Location{}
}
return upspin.Location{
Endpoint: upspin.Endpoint{
Transport: upspin.Transport(loc.Endpoint.Transport),
NetAddr: upspin.NetAddr(loc.Endpoint.NetAddr),
},
Reference: upspin.Reference(loc.Reference),
}
}
// UpspinLocations converts from slices of proto's Location struct to upspin's.
func UpspinLocations(l []*Location) []upspin.Location {
if len(l) == 0 {
return nil
}
ulocs := make([]upspin.Location, len(l))
for i := range ulocs {
ulocs[i] = UpspinLocation(l[i])
}
return ulocs
}
// UpspinDirEntry converts a slice of bytes struct to *upspin.DirEntry.
// If the slice is nil or empty, it returns nil.
func UpspinDirEntry(b []byte) (*upspin.DirEntry, error) {
const op errors.Op = "proto.UpspinDirEntry"
if len(b) == 0 {
return nil, nil
}
var d upspin.DirEntry
b, err := d.Unmarshal(b)
if err != nil {
return nil, err
}
if len(b) != 0 {
return nil, errors.E(op, errors.Invalid, "extra data")
}
return &d, nil
}
// Locations converts from slices of upspin's Location struct to proto's.
func Locations(ul []upspin.Location) []*Location {
if len(ul) == 0 {
return nil
}
locs := make([]*Location, len(ul))
for i := range locs {
loc := ul[i]
locs[i] = &Location{
Endpoint: &Endpoint{
Transport: int32(loc.Endpoint.Transport),
NetAddr: string(loc.Endpoint.NetAddr),
},
Reference: string(loc.Reference),
}
}
return locs
}
// UpspinEndpoints converts from slices of proto's Endpoint struct to upspin's.
func UpspinEndpoints(e []*Endpoint) []upspin.Endpoint {
if len(e) == 0 {
return nil
}
ueps := make([]upspin.Endpoint, len(e))
for i := range ueps {
ep := e[i]
ueps[i] = upspin.Endpoint{
Transport: upspin.Transport(ep.Transport),
NetAddr: upspin.NetAddr(ep.NetAddr),
}
}
return ueps
}
// Endpoints converts from slices of upspin's Endpoint struct to proto's.
func Endpoints(ue []upspin.Endpoint) []*Endpoint {
if len(ue) == 0 {
return nil
}
eps := make([]*Endpoint, len(ue))
for i := range eps {
ep := ue[i]
eps[i] = &Endpoint{
Transport: int32(ep.Transport),
NetAddr: string(ep.NetAddr),
}
}
return eps
}
// UpspinPublicKeys converts from slices of strings to upspin's PublicKeys.
func UpspinPublicKeys(s []string) []upspin.PublicKey {
if len(s) == 0 {
return nil
}
upk := make([]upspin.PublicKey, len(s))
for i := range upk {
upk[i] = upspin.PublicKey(s[i])
}
return upk
}
// PublicKeys converts from slices of upspin's PublicKey to string.
func PublicKeys(upk []upspin.PublicKey) []string {
if len(upk) == 0 {
return nil
}
s := make([]string, len(upk))
for i := range s {
s[i] = string(upk[i])
}
return s
}
// UpspinUser converts a proto.User to upspin.User.
func UpspinUser(user *User) *upspin.User {
return &upspin.User{
Name: upspin.UserName(user.Name),
Dirs: UpspinEndpoints(user.Dirs),
Stores: UpspinEndpoints(user.Stores),
PublicKey: upspin.PublicKey(user.PublicKey),
}
}
// UserProto converts an upspin.User to a proto.User.
func UserProto(user *upspin.User) *User {
return &User{
Name: string(user.Name),
Dirs: Endpoints(user.Dirs),
Stores: Endpoints(user.Stores),
PublicKey: string(user.PublicKey),
}
}
// RefdataProto converts an upspin.Refdata to a proto.Refdata.
func RefdataProto(refdata *upspin.Refdata) *Refdata {
if refdata == nil {
return nil
}
return &Refdata{
Reference: string(refdata.Reference),
Volatile: refdata.Volatile,
Duration: int64(refdata.Duration),
}
}
// UpspinRefdata converts a proto.Refdata to upspin.Refdata.
func UpspinRefdata(refdata *Refdata) *upspin.Refdata {
if refdata == nil {
return nil
}
return &upspin.Refdata{
Reference: upspin.Reference(refdata.Reference),
Volatile: refdata.Volatile,
Duration: time.Duration(refdata.Duration),
}
}
// UpspinDirEntries converts from slices of bytes to upspin's *DirEntries.
func UpspinDirEntries(b [][]byte) ([]*upspin.DirEntry, error) {
if len(b) == 0 {
return nil, nil
}
ude := make([]*upspin.DirEntry, len(b))
for i := range ude {
var err error
ude[i], err = UpspinDirEntry(b[i])
if err != nil {
return nil, err
}
}
return ude, nil
}
// DirEntryBytes converts from slices of upspin's *DirEntries to bytes.
func DirEntryBytes(ude []*upspin.DirEntry) ([][]byte, error) {
if len(ude) == 0 {
return nil, nil
}
b := make([][]byte, len(ude))
for i := range b {
var err error
b[i], err = ude[i].Marshal()
if err != nil {
return nil, err
}
}
return b, nil
}
// UpspinEvent converts a proto.DirWatchResponse to upspin.Event.
func UpspinEvent(event *Event) (*upspin.Event, error) {
entry, err := UpspinDirEntry(event.Entry)
if err != nil {
return nil, err
}
return &upspin.Event{
Entry: entry, // may be nil.
Delete: event.Delete,
Error: errors.UnmarshalError(event.Error),
}, nil
}
// EventProto converts an upspin.Event to proto.Event.
func EventProto(event *upspin.Event) (*Event, error) {
if event == nil {
// A nil proto is likely to cause GRPC to crash, according to
// https://github.com/grpc/grpc-go/issues/532.
// We don't use GRPC now for this protocol but we might again,
// so play it safe.
return &Event{}, nil
}
var b []byte
if event.Entry != nil {
var mErr error
b, mErr = event.Entry.Marshal()
if mErr != nil {
return nil, mErr
}
}
var err []byte
if event.Error != nil {
err = errors.MarshalError(event.Error)
}
return &Event{
Entry: b,
Delete: event.Delete,
Error: err,
}, nil
}