2018-09-04 22:55:52 +00:00
|
|
|
package message
|
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"time"
|
|
|
|
)
|
2018-09-04 22:55:52 +00:00
|
|
|
|
|
|
|
type Extension func(message *Message)
|
|
|
|
|
2018-09-11 10:09:30 +00:00
|
|
|
type Extensions struct {
|
|
|
|
In []Extension
|
|
|
|
Out []Extension
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Extensions) ApplyOutExtensions(m *Message) {
|
|
|
|
for i := range e.Out {
|
|
|
|
e.Out[i](m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Extensions) ApplyInExtensions(m *Message) {
|
|
|
|
for i := range e.In {
|
|
|
|
e.In[i](m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-06 11:03:21 +00:00
|
|
|
type Data = interface{}
|
|
|
|
|
2018-09-04 22:55:52 +00:00
|
|
|
type Message struct {
|
|
|
|
Channel string `json:"channel,omitempty"`
|
|
|
|
Version string `json:"version,omitempty"`
|
|
|
|
SupportedConnectionTypes []string `json:"supportedConnectionTypes,omitempty"`
|
2018-09-04 23:22:43 +00:00
|
|
|
ConnectionType string `json:"connectionType,omitempty"`
|
2018-09-04 22:55:52 +00:00
|
|
|
MinimumVersion string `json:"minimumVersion,omitempty"`
|
|
|
|
Successful bool `json:"successful,omitempty"`
|
|
|
|
Ext interface{} `json:"ext,omitempty"`
|
|
|
|
Id string `json:"id,omitempty"`
|
|
|
|
ClientId string `json:"clientId,omitempty"`
|
2018-09-06 11:23:53 +00:00
|
|
|
Advice *Advise `json:"advice,omitempty"`
|
2018-09-06 11:03:21 +00:00
|
|
|
Data Data `json:"data,omitempty"`
|
2018-09-04 22:55:52 +00:00
|
|
|
Timestamp uint64 `json:"timestamp,omitempty"`
|
|
|
|
AuthSuccessful bool `json:"authSuccessful,omitempty"`
|
|
|
|
Error string `json:"error,omitempty"`
|
|
|
|
Subscription string `json:"subscription,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Message) GetError() error {
|
|
|
|
if m.Error == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return errors.New(m.Error)
|
|
|
|
}
|
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
type Reconnect string
|
|
|
|
|
|
|
|
const (
|
|
|
|
//ReconnectRetry indicates that a client MAY attempt to reconnect with a /meta/connect message,
|
|
|
|
//after the interval (as defined by interval advice field or client-default backoff), and with the same credentials.
|
|
|
|
ReconnectRetry Reconnect = "retry"
|
|
|
|
|
|
|
|
//ReconnectHandshake indicates that the server has terminated any prior connection status and the client MUST reconnect
|
|
|
|
// with a /meta/handshake message.
|
|
|
|
//A client MUST NOT automatically retry when a reconnect advice handshake has been received.
|
|
|
|
ReconnectHandshake Reconnect = "handshake"
|
|
|
|
|
|
|
|
//ReconnectNone indicates a hard failure for the connect attempt.
|
|
|
|
//A client MUST respect reconnect advice none and MUST NOT automatically retry or handshake.
|
|
|
|
ReconnectNone Reconnect = "none"
|
|
|
|
)
|
|
|
|
|
2018-09-04 22:55:52 +00:00
|
|
|
type Advise struct {
|
2018-09-07 15:50:16 +00:00
|
|
|
Reconnect Reconnect `json:"reconnect,omitempty"`
|
|
|
|
Interval time.Duration `json:"interval,omitempty"`
|
|
|
|
Timeout time.Duration `json:"timeout,omitempty"`
|
|
|
|
MultipleClients bool `json:"multiple-clients,omitempty"`
|
|
|
|
Hosts []string `json:"hosts,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Advise) MarshalJSON() ([]byte, error) {
|
|
|
|
type jsonStruct struct {
|
|
|
|
Reconnect string `json:"reconnect,omitempty"`
|
|
|
|
Interval int64 `json:"interval,omitempty"`
|
|
|
|
Timeout int64 `json:"timeout,omitempty"`
|
|
|
|
MultipleClients bool `json:"multiple-clients,omitempty"`
|
|
|
|
Hosts []string `json:"hosts,omitempty"`
|
|
|
|
}
|
2018-09-24 14:13:57 +00:00
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
var builder bytes.Buffer
|
2018-09-24 14:13:57 +00:00
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
err := json.NewEncoder(&builder).Encode(jsonStruct{
|
|
|
|
Reconnect: string(a.Reconnect),
|
|
|
|
Interval: int64(a.Interval / time.Millisecond),
|
|
|
|
Timeout: int64(a.Timeout / time.Millisecond),
|
|
|
|
MultipleClients: a.MultipleClients,
|
|
|
|
Hosts: a.Hosts,
|
|
|
|
})
|
|
|
|
|
|
|
|
return builder.Bytes(), err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Advise) UnmarshalJSON(b []byte) error {
|
|
|
|
var raw map[string]interface{}
|
|
|
|
err := json.Unmarshal(b, &raw)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-09-24 14:13:57 +00:00
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
reconnect, ok := raw["reconnect"]
|
|
|
|
if ok {
|
|
|
|
a.Reconnect = Reconnect(reconnect.(string))
|
|
|
|
}
|
2018-09-24 14:13:57 +00:00
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
interval, ok := raw["interval"]
|
|
|
|
if ok {
|
|
|
|
a.Interval = time.Duration(interval.(float64)) * time.Millisecond
|
|
|
|
}
|
2018-09-24 14:13:57 +00:00
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
timeout, ok := raw["timeout"]
|
|
|
|
if ok {
|
|
|
|
a.Timeout = time.Duration(timeout.(float64)) * time.Millisecond
|
|
|
|
}
|
2018-09-24 14:13:57 +00:00
|
|
|
|
2018-09-07 15:50:16 +00:00
|
|
|
mc, ok := raw["multiple-clients"]
|
|
|
|
if ok {
|
|
|
|
a.MultipleClients = mc.(bool)
|
|
|
|
}
|
|
|
|
|
|
|
|
hosts, ok := raw["hosts"]
|
|
|
|
if ok {
|
|
|
|
a.Hosts = hosts.([]string)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2018-09-04 22:55:52 +00:00
|
|
|
}
|
2018-09-24 14:13:57 +00:00
|
|
|
func IsEventDelivery(msg *Message) bool {
|
|
|
|
if IsMetaMessage(msg) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if msg.Data != nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
//MetaMessage are channels commencing with the /meta/ segment ans, are the channels used by the faye protocol itself.
|
|
|
|
type MetaMessage = string
|
|
|
|
|
|
|
|
const (
|
|
|
|
MetaSubscribe MetaMessage = "/meta/subscribe"
|
|
|
|
MetaConnect MetaMessage = "/meta/connect"
|
|
|
|
MetaDisconnect MetaMessage = "/meta/disconnect"
|
|
|
|
MetaUnsubscribe MetaMessage = "/meta/unsubscribe"
|
|
|
|
MetaHandshake MetaMessage = "/meta/handshake"
|
|
|
|
)
|
|
|
|
|
|
|
|
//EventMessage are published in event messages sent from a faye client to a faye server
|
|
|
|
//and are delivered in event messages sent from a faye server to a faye client.
|
|
|
|
type EventMessage = int
|
|
|
|
|
|
|
|
const (
|
|
|
|
//
|
|
|
|
EventPublish EventMessage = iota
|
|
|
|
EventDelivery
|
|
|
|
)
|
|
|
|
|
|
|
|
var metaMessages = []MetaMessage{MetaSubscribe, MetaConnect, MetaUnsubscribe, MetaHandshake, MetaDisconnect}
|
|
|
|
|
|
|
|
func IsMetaMessage(msg *Message) bool {
|
|
|
|
for i := range metaMessages {
|
|
|
|
if msg.Channel == metaMessages[i] {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func IsEventPublish(msg *Message) bool {
|
|
|
|
if IsMetaMessage(msg) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return !IsEventDelivery(msg)
|
|
|
|
}
|