268 lines
8.0 KiB
Go
268 lines
8.0 KiB
Go
/*
|
|
Copyright NetFoundry Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package channel
|
|
|
|
import (
|
|
"context"
|
|
"crypto/x509"
|
|
"github.com/openziti/transport/v2"
|
|
"github.com/pkg/errors"
|
|
"io"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
// Channel represents an asynchronous, message-passing framework, designed to sit on top of an underlay.
|
|
type Channel interface {
|
|
Identity
|
|
SetLogicalName(logicalName string)
|
|
Sender
|
|
io.Closer
|
|
IsClosed() bool
|
|
Underlay() Underlay
|
|
Headers() map[int32][]byte
|
|
GetTimeSinceLastRead() time.Duration
|
|
GetUserData() interface{}
|
|
}
|
|
|
|
type MultiChannel interface {
|
|
Channel
|
|
UnderlayAcceptor
|
|
DialUnderlay(factory GroupedUnderlayFactory, underlayType string)
|
|
GetUnderlayCountsByType() map[string]int
|
|
GetUnderlayHandler() UnderlayHandler
|
|
}
|
|
|
|
type Sender interface {
|
|
// Send will send the given Sendable. If the Sender is busy, it will wait until either the Sender
|
|
// can process the Sendable, the channel is closed or the associated context.Context times out
|
|
Send(s Sendable) error
|
|
|
|
// TrySend will send the given Sendable. If the Sender is busy (outgoing message queue is full), it will return
|
|
// immediately rather than wait. The boolean return indicates whether the message was queued or not
|
|
TrySend(s Sendable) (bool, error)
|
|
}
|
|
|
|
// Sendable encapsulates all the data and callbacks that a Channel requires when sending a Message.
|
|
type Sendable interface {
|
|
// Msg return the Message to send
|
|
Msg() *Message
|
|
|
|
// SetSequence sets a sequence number indicating in which order the message was received
|
|
SetSequence(seq int32)
|
|
|
|
// Sequence returns the sequence number
|
|
Sequence() int32
|
|
|
|
// Priority returns the Priority of the Message
|
|
Priority() Priority
|
|
|
|
// Context returns the Context used for timeouts/cancelling message sends, etc
|
|
Context() context.Context
|
|
|
|
// SendListener returns the SendListener to invoke at each stage of the send operation
|
|
SendListener() SendListener
|
|
|
|
// ReplyReceiver returns the ReplyReceiver to be invoked when a reply for the message or received, or nil if
|
|
// no ReplyReceiver should be invoked if or when a reply is received
|
|
ReplyReceiver() ReplyReceiver
|
|
}
|
|
|
|
// Envelope allows setting message priority and context. Message is an Envelope (as well as a Sendable)
|
|
type Envelope interface {
|
|
// WithPriority returns an Envelope with the given priority
|
|
WithPriority(p Priority) Envelope
|
|
|
|
// WithTimeout returns a TimeoutEnvelope with a context using the given timeout
|
|
WithTimeout(duration time.Duration) TimeoutEnvelope
|
|
|
|
// WithContext returns a TimeoutEnvelope which uses the given context for timeout/cancellation
|
|
WithContext(c context.Context) TimeoutEnvelope
|
|
|
|
// Send sends the envelope on the given Channel
|
|
Send(sender Sender) error
|
|
|
|
// ReplyTo allows setting the reply header in a fluent style
|
|
ReplyTo(msg *Message) Envelope
|
|
|
|
// ToSendable converts the Envelope into a Sendable, which can be submitted to a Channel for sending
|
|
ToSendable() Sendable
|
|
}
|
|
|
|
// TimeoutEnvelope has timeout related convenience methods, such as waiting for a Message to be written to
|
|
// the wire or waiting for a Message reply
|
|
type TimeoutEnvelope interface {
|
|
Envelope
|
|
|
|
// SendAndWaitForWire will wait until the configured timeout or until the message is sent, whichever comes first
|
|
// If the timeout happens first, the context error will be returned, wrapped by a TimeoutError
|
|
SendAndWaitForWire(sender Sender) error
|
|
|
|
// SendForReply will wait until the configured timeout or until a reply is received, whichever comes first
|
|
// If the timeout happens first, the context error will be returned, wrapped by a TimeoutError
|
|
SendForReply(sender Sender) (*Message, error)
|
|
}
|
|
|
|
// SendListener is notified at the various stages of a message send
|
|
type SendListener interface {
|
|
// Notify Queued is called when the message has been queued for send
|
|
NotifyQueued()
|
|
// NotifyBeforeWrite is called before send is called
|
|
NotifyBeforeWrite()
|
|
// NotifyAfterWrite is called after the message has been written to the Underlay
|
|
NotifyAfterWrite()
|
|
// NotifyErr is called if the Sendable context errors before send or if writing to the Underlay fails
|
|
NotifyErr(error)
|
|
}
|
|
|
|
// ReplyReceiver is used to get notified when a Message reply arrives
|
|
type ReplyReceiver interface {
|
|
AcceptReply(*Message)
|
|
}
|
|
|
|
type Identity interface {
|
|
// The Id used to represent the identity of this channel to lower-level resources.
|
|
//
|
|
Id() string
|
|
|
|
// The LogicalName represents the purpose or usage of this channel (i.e. 'ctrl', 'mgmt' 'r/001', etc.) Usually used
|
|
// by humans in understand the logical purpose of a channel.
|
|
//
|
|
LogicalName() string
|
|
|
|
// The ConnectionId represents the identity of this Channel to internal API components ("instance identifier").
|
|
// Usually used by the Channel framework to differentiate Channel instances.
|
|
//
|
|
ConnectionId() string
|
|
|
|
// Certificates contains the identity certificates provided by the peer.
|
|
//
|
|
Certificates() []*x509.Certificate
|
|
|
|
// Label constructs a consistently-formatted string used for context logging purposes, from the components above.
|
|
//
|
|
Label() string
|
|
}
|
|
|
|
// UnderlayListener represents a component designed to listen for incoming peer connections.
|
|
type UnderlayListener interface {
|
|
Listen(handlers ...ConnectionHandler) error
|
|
UnderlayFactory
|
|
io.Closer
|
|
}
|
|
|
|
// UnderlayFactory is used by Channel to obtain an Underlay instance. An underlay "dialer" or "listener" implement
|
|
// UnderlayFactory, to provide instances to Channel.
|
|
type UnderlayFactory interface {
|
|
Create(timeout time.Duration) (Underlay, error)
|
|
}
|
|
|
|
type DialUnderlayFactory interface {
|
|
UnderlayFactory
|
|
CreateWithHeaders(timeout time.Duration, headers map[int32][]byte) (Underlay, error)
|
|
}
|
|
|
|
type GroupedUnderlayFactory interface {
|
|
CreateGroupedUnderlay(groupId string, groupedSecret []byte, underlayType string, timeout time.Duration) (Underlay, error)
|
|
DialFailed(channel MultiChannel, underlayType string, attempt int)
|
|
}
|
|
|
|
// Underlay abstracts a physical communications channel, typically sitting on top of 'transport'.
|
|
type Underlay interface {
|
|
Rx() (*Message, error)
|
|
Tx(m *Message) error
|
|
Identity
|
|
io.Closer
|
|
IsClosed() bool
|
|
Headers() map[int32][]byte
|
|
SetWriteTimeout(duration time.Duration) error
|
|
SetWriteDeadline(time time.Time) error
|
|
GetLocalAddr() net.Addr
|
|
GetRemoteAddr() net.Addr
|
|
}
|
|
|
|
type classicUnderlay interface {
|
|
Underlay
|
|
getPeer() transport.Conn
|
|
init(id string, connectionId string, headers Headers)
|
|
rxHello() (*Message, error)
|
|
}
|
|
|
|
const AnyContentType = -1
|
|
const HelloSequence = -1
|
|
|
|
// TimeoutError is used to indicate a timeout happened
|
|
type TimeoutError struct {
|
|
error
|
|
}
|
|
|
|
func (self TimeoutError) Unwrap() error {
|
|
return self.error
|
|
}
|
|
|
|
func IsTimeout(err error) bool {
|
|
return errors.As(err, &TimeoutError{})
|
|
}
|
|
|
|
type ClosedError struct{}
|
|
|
|
func (ClosedError) Error() string {
|
|
return "channel closed"
|
|
}
|
|
|
|
var ListenerClosedError = listenerClosedError{}
|
|
|
|
type listenerClosedError struct{}
|
|
|
|
func (err listenerClosedError) Error() string {
|
|
return "closed"
|
|
}
|
|
|
|
// BaseSendable is a type that may be used to provide default methods for Sendable implementation
|
|
type BaseSendable struct{}
|
|
|
|
func (BaseSendable) Msg() *Message {
|
|
return nil
|
|
}
|
|
|
|
func (BaseSendable) Priority() Priority {
|
|
return Standard
|
|
}
|
|
|
|
func (BaseSendable) Context() context.Context {
|
|
return context.Background()
|
|
}
|
|
|
|
func (BaseSendable) SendListener() SendListener {
|
|
return &BaseSendListener{}
|
|
}
|
|
|
|
func (BaseSendable) ReplyReceiver() ReplyReceiver {
|
|
return nil
|
|
}
|
|
|
|
// BaseSendListener is a type that may be used to provide default methods for SendListener implementation
|
|
type BaseSendListener struct{}
|
|
|
|
func (BaseSendListener) NotifyQueued() {}
|
|
|
|
func (BaseSendListener) NotifyBeforeWrite() {}
|
|
|
|
func (BaseSendListener) NotifyAfterWrite() {}
|
|
|
|
func (BaseSendListener) NotifyErr(error) {}
|