lib

package module
v0.0.0-...-70bac33 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2016 License: Apache-2.0 Imports: 10 Imported by: 0

README

libgossamer

Build Status

libgossamer is a Go library for the Gossamer IRC server system. Servers on a Gossamer network use this library to maintain network state, communicate via the Gossamer server to server (s2s) protocol with other servers, and expose clients using its APIs. For example, the Gossamer daemon acts as a traditional ircd, accepting client connections and interfacing them to the network. The Gossamer services, on the other hand, expose a set of pseudoclients to the network such as NickServ, ChanServ, etc using the same library.

Difference with traditional IRC networks

Gossamer networks are different than traditional IRC networks. Not only is the s2s protocol incompatible, Gossamer defines additional concepts that have no analogue in other IRC systems. The most important of these is the realm.

Realms

Conventional IRC networks share a single namespace for user nicknames and channel names. This has a number of benefits, including the property that users can belong to disparate channels and participate in them all. However, a single namespace has significant drawbacks as well. Nicknames must be unique across the network, and new users might find their preferred nicknames already in use.

This problem is compounded by the fact that many of IRC’s newer, less experienced users come to the protocol as part of “third-party” communities - forums, subreddits, hobby sites, etc - with the intention of joining a chatroom specific to their community. They already have established identities in these “realms”, including nicknames. The disassociation between their existing identity and their IRC identity is frequently lost on them, and can be a source of frustration if their favored nickname is already taken.

Ideally, new users should be able to keep their existing identity when joining the channel(s) of an existing community, but still be able to explore and venture into other channels and communities on the network. This is the motivation behind Gossamer’s realms.

Gossamer divides the traditional IRC network into separate namespaces, called realms. Users and channels each belong to a specific realm, shown as a colon-separated prefix. For example, the user “test” in the realm “dev” has an effective nickname of “dev:test”, and the channel “help” in the same realm is effectively “#dev:help”.

Forcing every user to carry a prefix just adds clutter, though, so Gossamer employs a trick to hide the prefix in most cases: any two clients in the same realm will see each other without the prefix, while two clients in different realms will each observe the other with a fully identified nickname. This way, a user in a given realm can explore other channels and interact with the members there, while still maintaining an identity that’s associated with their realm.

It is also possible for a user, with the assistance of network services, to switch between realms, which generates a notification to other users of an effective nickname change. Services, however, should be able to manage a user with multiple identities (from different realms) and apply permissions accordingly.

Zero Configuration

Gossamer employs a zero configuration system for server setup and linking, meaning there is no traditional ircd.conf file to write. Instead, a few command line options for servers will bootstrap them to connect to the network, where a more extensive configuration can be retrieved from a central configuration authority.

To achieve a trusted link between servers without configuration, a Gossamer network includes a certificate authority (CA) which signs TLS certificates for each server in the network. When two of these servers connect, they can verify the validity of the other side’s certificate against the network CA, and determine if the link is legitimate.

Operation works the same way - users present a signed TLS certificate when connecting, which unlocks any oper privileges they have associated with their account. This way, no oper passwords must be configured in advance.

Binary Protocol

When linked with each other, Gossamer servers communicate using a binary protocol based on Go’s gob encoding. This allows much faster, more CPU friendly communication between servers, at the expense of human readability.

Documentation

Index

Constants

View Source
const (
	SS_MSG_TYPE_UNKNOWN uint32 = iota
	SS_MSG_TYPE_HELLO
	SS_MSG_TYPE_BURST_COMPLETE
	SS_MSG_TYPE_SYNC
	SS_MSG_TYPE_CLIENT
	SS_MSG_TYPE_SERVER
	SS_MSG_TYPE_KILL
	SS_MSG_TYPE_SPLIT
	SS_MSG_TYPE_CHANNEL
	SS_MSG_TYPE_CHANNEL_MODE
	SS_MSG_TYPE_MEMBERSHIP
	SS_MSG_TYPE_MEMBERSHIP_END
	SS_MSG_TYPE_PM
	SS_MSG_TYPE_CM
)

Message types. Sent on the wire - do not reorder or delete types.

Variables

View Source
var SendQFull error = errors.New("SendQFull")

Functions

func FilterChannelModes

func FilterChannelModes(channel *Channel, actor *Client, channelMode ChannelModeDelta, memberDelta []MemberModeDelta) (ChannelModeDelta, []MemberModeDelta)

func ParseChannelModeString

func ParseChannelModeString(modes string, args []string, resolveClient ResolveClientFn) (channel ChannelModeDelta, member []MemberModeDelta)

func StringifyChannelModes

func StringifyChannelModes(channel ChannelModeDelta, member []MemberModeDelta, serializeClient SerializeClientFn) string

Types

type AlreadyAMemberError

type AlreadyAMemberError struct{}

func (AlreadyAMemberError) Error

func (_ AlreadyAMemberError) Error() string

type Channel

type Channel struct {
	Node    *Node
	Subnet  *Subnet
	Name    string
	Lname   string
	Ts      time.Time
	Topic   string
	TopicTs time.Time
	TopicBy string

	LocalMember map[*Client]*Membership
	Member      map[*Client]*Membership

	Mode struct {
		TopicProtected     bool
		NoExternalMessages bool
		Moderated          bool
		Secret             bool
		Limit              uint32
		Key                string
	}
}

func NewChannel

func NewChannel(node *Node, subnet *Subnet, name string) *Channel

func (*Channel) ApplyModeDelta

func (ch *Channel) ApplyModeDelta(delta ChannelModeDelta, memberDelta []MemberModeDelta) (ChannelModeDelta, []MemberModeDelta)

func (*Channel) DebugString

func (ch *Channel) DebugString() string

func (*Channel) Id

func (ch *Channel) Id() SSChannelId

func (*Channel) Serialize

func (ch *Channel) Serialize() *SSChannel

type ChannelModeDelta

type ChannelModeDelta struct {
	TopicProtected, NoExternalMessages, Moderated, Secret ModeDelta
	Limit, Key                                            ModeDelta
	LimitValue                                            uint32
	KeyValue                                              string
}

func (*ChannelModeDelta) IsEmpty

func (cmd *ChannelModeDelta) IsEmpty() bool

func (*ChannelModeDelta) String

func (cmd *ChannelModeDelta) String() string

type Client

type Client struct {
	Subnet        *Subnet
	Server        *Server
	Nick, Lnick   string
	Ident, Vident string
	Host, Vhost   string
	Ip, Vip       string
	Gecos         string
	Ts            time.Time
	Member        map[*Channel]*Membership
}

func (*Client) DebugString

func (c *Client) DebugString() string

func (*Client) Id

func (c *Client) Id() SSClientId

func (*Client) IsLocal

func (c *Client) IsLocal() bool

func (*Client) Serialize

func (c *Client) Serialize() *SSClient

type Config

type Config struct {
	// Basic server name and info.
	ServerName, ServerDesc string

	// Network name.
	NetName string

	// Name of the default subnet (must match for networks to link)
	DefaultSubnetName string
}

Configuration spec for this node.

type EventHandler

type EventHandler interface {
	OnServerLink(server *Server, hub *Server)
	OnChannelJoin(channel *Channel, client *Client, membership *Membership)
	OnChannelMessage(from *Client, to *Channel, message string)
	OnChannelModeChange(channel *Channel, by *Client, delta ChannelModeDelta, memberDelta []MemberModeDelta)
	OnPrivateMessage(from *Client, to *Client, message string)
	OnChannelPart(channel *Channel, client *Client, reason string)
}
type Link struct {
	Silence bool
	// contains filtered or unexported fields
}

Represents a link between a local and a directly connected remote node.

func NewLink(reader io.ReadCloser, writer io.WriteCloser, sendBufferSize int, protoFactory ServerProtocolFactory, recv chan<- LinkMessage, wg *sync.WaitGroup) *Link

func (*Link) Close

func (l *Link) Close()

func (*Link) SetName

func (l *Link) SetName(name string)

func (*Link) Shutdown

func (l *Link) Shutdown()

func (*Link) WriteMessage

func (l *Link) WriteMessage(msg SSMessage) error

type LinkMessage

type LinkMessage struct {
	// contains filtered or unexported fields
}

A message sent pertaining to a particular link.

type MemberModeDelta

type MemberModeDelta struct {
	Client                                    *Client
	IsOwner, IsAdmin, IsOp, IsHalfop, IsVoice ModeDelta
}

type Membership

type Membership struct {
	Ts                                        time.Time
	IsOwner, IsAdmin, IsOp, IsHalfop, IsVoice bool
}

func (*Membership) Serialize

func (m *Membership) Serialize(channel *Channel, client *Client) *SSMembership

type ModeDelta

type ModeDelta uint8
const (
	MODE_UNCHANGED ModeDelta = iota
	MODE_ADDED
	MODE_REMOVED
)

func (ModeDelta) String

func (delta ModeDelta) String() string

type NameInUseError

type NameInUseError struct{}

func (NameInUseError) Error

func (_ NameInUseError) Error() string

type Node

type Node struct {

	// Map of servers directly connected to this node.
	Local map[*Link]*Server

	// Map of all servers in the network.
	Network map[string]*Server

	NewLinks map[*Link]newLink

	Subnet map[string]*Subnet

	DefaultSubnet *Subnet
	Me            *Server
	Handler       EventHandler
	// contains filtered or unexported fields
}

Represents a Gossamer distributed node's current state.

func NewNode

func NewNode(config Config, handler EventHandler, wg *sync.WaitGroup) *Node

func (*Node) AttachChannel

func (n *Node) AttachChannel(channel *Channel) error

func (*Node) AttachClient

func (n *Node) AttachClient(client *Client) error
func (n *Node) BeginLink(reader io.ReadCloser, writer io.WriteCloser, logger io.Writer, name string)

func (*Node) BurstTo

func (n *Node) BurstTo(newServer *Server)

func (*Node) ChangeChannelMode

func (n *Node) ChangeChannelMode(client *Client, channel *Channel, channelModes ChannelModeDelta, memberModes []MemberModeDelta)

func (*Node) ChannelMessage

func (n *Node) ChannelMessage(client *Client, channel *Channel, message string)

func (*Node) Do

func (n *Node) Do(fn NodeDoFn)

func (*Node) JoinOrCreateChannel

func (n *Node) JoinOrCreateChannel(client *Client, subnet *Subnet, name string) (*Channel, error)

func (*Node) NetworkName

func (n *Node) NetworkName() string

func (*Node) PartChannel

func (n *Node) PartChannel(channel *Channel, client *Client, reason string)

func (*Node) PrivateMessage

func (n *Node) PrivateMessage(from, to *Client, message string)

func (*Node) Quit

func (n *Node) Quit(client *Client, reason string)

func (*Node) SendAll

func (n *Node) SendAll(msg SSMessage)

func (*Node) SendAllSkip

func (n *Node) SendAllSkip(msg SSMessage, skip *Server)

func (*Node) Shutdown

func (n *Node) Shutdown()

func (*Node) Sync

func (n *Node) Sync() chan struct{}

type NodeDoFn

type NodeDoFn func()

type ProxyEventHandler

type ProxyEventHandler struct {
	Delegate EventHandler
}

func (*ProxyEventHandler) OnChannelJoin

func (peh *ProxyEventHandler) OnChannelJoin(channel *Channel, client *Client, membership *Membership)

func (*ProxyEventHandler) OnChannelMessage

func (peh *ProxyEventHandler) OnChannelMessage(from *Client, to *Channel, message string)

func (*ProxyEventHandler) OnChannelModeChange

func (peh *ProxyEventHandler) OnChannelModeChange(channel *Channel, by *Client, delta ChannelModeDelta, memberDelta []MemberModeDelta)

func (*ProxyEventHandler) OnChannelPart

func (peh *ProxyEventHandler) OnChannelPart(channel *Channel, client *Client, reason string)

func (*ProxyEventHandler) OnPrivateMessage

func (peh *ProxyEventHandler) OnPrivateMessage(from *Client, to *Client, message string)
func (peh *ProxyEventHandler) OnServerLink(server *Server, hub *Server)

type ResolveClientFn

type ResolveClientFn func(name string) (*Client, bool)

type SSBurstComplete

type SSBurstComplete struct {
	Server string
}

func (SSBurstComplete) String

func (msg SSBurstComplete) String() string

type SSChannel

type SSChannel struct {
	Name    string
	Subnet  string
	Ts      time.Time
	Members []*SSMembership
}

func (SSChannel) String

func (msg SSChannel) String() string

type SSChannelId

type SSChannelId struct {
	Subnet string
	Name   string
}

func (SSChannelId) String

func (id SSChannelId) String() string

type SSChannelMessage

type SSChannelMessage struct {
	From    SSClientId
	To      SSChannelId
	Message string
}

func (SSChannelMessage) String

func (msg SSChannelMessage) String() string

type SSChannelMode

type SSChannelMode struct {
	From       SSClientId
	Channel    SSChannelId
	Mode       SSChannelModeDelta
	MemberMode []SSMemberModeDelta
}

func SerializeChannelModeChange

func SerializeChannelModeChange(channel *Channel, actor *Client, channelMode ChannelModeDelta, memberDelta []MemberModeDelta) *SSChannelMode

func (SSChannelMode) String

func (msg SSChannelMode) String() string

type SSChannelModeDelta

type SSChannelModeDelta struct {
	TopicProtected, NoExternalMessages, Moderated, Secret SSModeDelta
	Limit, Key                                            SSModeDelta
	LimitValue                                            uint32
	KeyValue                                              string
}

func ChannelModeDeltaToSSChannelModeDelta

func ChannelModeDeltaToSSChannelModeDelta(value ChannelModeDelta) SSChannelModeDelta

func (SSChannelModeDelta) ToChannelModeDelta

func (delta SSChannelModeDelta) ToChannelModeDelta() ChannelModeDelta

type SSClient

type SSClient struct {
	Subnet                           string
	Server                           string
	Nick, Ident, Vident, Host, Vhost string
	Ip, Vip                          string
	Gecos                            string
	Ts                               time.Time
}

func (SSClient) String

func (msg SSClient) String() string

type SSClientId

type SSClientId struct {
	Server string
	Subnet string
	Nick   string
}

TODO Why does SSClientId have Server?

func (SSClientId) String

func (id SSClientId) String() string

type SSHello

type SSHello struct {
	Protocol      uint32
	LocalTimeMs   uint64
	Name          string
	Description   string
	DefaultSubnet string
}

/ Introduction message sent by one server to another at the beginning of link.

func (SSHello) String

func (msg SSHello) String() string

type SSKill

type SSKill struct {
	// Id of the client being killed.
	Id SSClientId

	// Server doing the killing.
	Server string

	// Whether this kill message is instructional (server A telling server B to kill B's client)
	// or authoritative (server B broadcasting a kill of its own client)
	Authority bool

	// If this kill was initiated by another client, who it was.
	By SSClientId

	// Textual reason for the kill.
	Reason string

	// Numerical code indicating the reason for the kill (for statistics, etc).
	ReasonCode SSKillReason
}

func (SSKill) String

func (msg SSKill) String() string

type SSKillReason

type SSKillReason uint8
const (
	SS_KILL_REASON_QUIT SSKillReason = iota
	SS_KILL_REASON_COLLISION
	SS_KILL_REASON_SENDQ
	SS_KILL_REASON_RECVQ
)

type SSMemberModeDelta

type SSMemberModeDelta struct {
	Client                                    SSClientId
	IsOwner, IsAdmin, IsOp, IsHalfop, IsVoice SSModeDelta
}

func SSMemberModeDeltaFromMemberModeDelta

func SSMemberModeDeltaFromMemberModeDelta(value MemberModeDelta) SSMemberModeDelta

func (SSMemberModeDelta) ToMemberModeDelta

func (delta SSMemberModeDelta) ToMemberModeDelta(n *Node) (MemberModeDelta, bool)

type SSMembership

type SSMembership struct {
	Client                                    SSClientId
	Channel                                   SSChannelId
	Ts                                        time.Time
	IsOwner, IsAdmin, IsOp, IsHalfop, IsVoice bool
}

func (SSMembership) String

func (msg SSMembership) String() string

type SSMembershipEnd

type SSMembershipEnd struct {
	Channel SSChannelId
	Client  SSClientId
	Reason  string
}

func (SSMembershipEnd) String

func (msg SSMembershipEnd) String() string

type SSMessage

type SSMessage interface {
	String() string
	// contains filtered or unexported methods
}

A Gossamer server-to-server message.

type SSMessageHeader

type SSMessageHeader struct {
	Type uint32
}

Message header used to identify what message is being transmitted next.

type SSModeDelta

type SSModeDelta uint8
const (
	SS_MODE_UNCHANGED SSModeDelta = iota
	SS_MODE_ADDED
	SS_MODE_REMOVED
)

func SSModeDeltaFromModeDelta

func SSModeDeltaFromModeDelta(value ModeDelta) SSModeDelta

func (SSModeDelta) ToModeDelta

func (value SSModeDelta) ToModeDelta() ModeDelta

type SSPrivateMessage

type SSPrivateMessage struct {
	From    SSClientId
	To      SSClientId
	Message string
}

func (SSPrivateMessage) String

func (msg SSPrivateMessage) String() string

type SSServer

type SSServer struct {
	Name string
	Desc string
	Via  string
}

func (SSServer) String

func (msg SSServer) String() string

type SSSplit

type SSSplit struct {
	Server string
	Reason string
}

func (SSSplit) String

func (msg SSSplit) String() string

type SSSync

type SSSync struct {
	Sequence  uint32
	Reply     bool
	Origin    string
	ReplyFrom string
}

func (SSSync) String

func (msg SSSync) String() string

type SendQ

type SendQ struct {
	// contains filtered or unexported fields
}

A SendQ is an io.Writer that implements fixed buffering. Once the buffer buffer is exhausted, a QueueFull error is raised. Writing to the buffer always succeeds, though - any errors are delivered asynchronously. All errors are fatal - the queue shuts down and becomes a noop after an error is encountered.

func NewSendQ

func NewSendQ(writer io.WriteCloser, n int, wg *sync.WaitGroup) *SendQ

func (*SendQ) Close

func (sq *SendQ) Close()

func (*SendQ) ErrChan

func (sq *SendQ) ErrChan() <-chan error

func (*SendQ) FlushAndClose

func (sq *SendQ) FlushAndClose()

Close the writer after all data has been flushed.

func (*SendQ) Write

func (sq *SendQ) Write(p []byte) (int, error)

type SerializeClientFn

type SerializeClientFn func(client *Client) string

type Server

type Server struct {
	Name string
	Desc string

	Link  *Link
	Route *Server
	Hub   *Server

	Links map[string]*Server
}

func NewLocalServer

func NewLocalServer(name, desc string, link *Link, hub *Server) *Server

func NewRemoteServer

func NewRemoteServer(name, desc string, hub *Server) *Server

func (*Server) Send

func (s *Server) Send(msg SSMessage)

func (*Server) Serialize

func (s *Server) Serialize() SSMessage

type ServerProtocolFactory

type ServerProtocolFactory interface {
	Reader(reader io.Reader) ServerProtocolReader
	Writer(writer io.Writer) ServerProtocolWriter
}
var GobServerProtocolFactory ServerProtocolFactory = &gobServerProtocolFactory{}

type ServerProtocolReader

type ServerProtocolReader interface {
	ReadMessage() (msg SSMessage, err error)
}

A Gossamer server-to-server message reader.

func NewGobServerProtocolReader

func NewGobServerProtocolReader(reader io.Reader) ServerProtocolReader

Construct a ServerProtcolReader from the underlying io.Reader which interprets incoming data using the gob encoding.

type ServerProtocolWriter

type ServerProtocolWriter interface {
	WriteMessage(msg SSMessage) error
}

A Gossamer server-to-server message writer.

func NewGobServerProtocolWriter

func NewGobServerProtocolWriter(writer io.Writer) ServerProtocolWriter

Construct a ServerProtocolWriter from the underlying io.Writer which serializes outgoing messages using the gob encoding.

type Subnet

type Subnet struct {
	Name string

	Client  map[string]*Client
	Channel map[string]*Channel
}

func NewSubnet

func NewSubnet(name string) *Subnet

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL