123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- package neffos
- import (
- "fmt"
- "io"
- "net"
- "os"
- "strings"
- )
- // MessageHandlerFunc is the definition type of the events' callback.
- // Its error can be written to the other side on specific events,
- // i.e on `OnNamespaceConnect` it will abort a remote namespace connection.
- // See examples for more.
- type MessageHandlerFunc func(*NSConn, Message) error
- var (
- // OnNamespaceConnect is the event name which its callback is fired right before namespace connect,
- // if non-nil error then the remote connection's `Conn.Connect` will fail and send that error text.
- // Connection is not ready to emit data to the namespace.
- OnNamespaceConnect = "_OnNamespaceConnect"
- // OnNamespaceConnected is the event name which its callback is fired after namespace successfully connected.
- // Connection is ready to emit data back to the namespace.
- OnNamespaceConnected = "_OnNamespaceConnected"
- // OnNamespaceDisconnect is the event name which its callback is fired when
- // remote namespace disconnection or local namespace disconnection is happening.
- // For server-side connections the reply matters, so if error returned then the client-side cannot disconnect yet,
- // for client-side the return value does not matter.
- OnNamespaceDisconnect = "_OnNamespaceDisconnect" // if allowed to connect then it's allowed to disconnect as well.
- // OnRoomJoin is the event name which its callback is fired right before room join.
- OnRoomJoin = "_OnRoomJoin" // able to check if allowed to join.
- // OnRoomJoined is the event name which its callback is fired after the connection has successfully joined to a room.
- OnRoomJoined = "_OnRoomJoined" // able to broadcast messages to room.
- // OnRoomLeave is the event name which its callback is fired right before room leave.
- OnRoomLeave = "_OnRoomLeave" // able to broadcast bye-bye messages to room.
- // OnRoomLeft is the event name which its callback is fired after the connection has successfully left from a room.
- OnRoomLeft = "_OnRoomLeft" // if allowed to join to a room, then its allowed to leave from it.
- // OnAnyEvent is the event name which its callback is fired when incoming message's event is not declared to the ConnHandler(`Events` or `Namespaces`).
- OnAnyEvent = "_OnAnyEvent" // when event no match.
- // OnNativeMessage is fired on incoming native/raw websocket messages.
- // If this event defined then an incoming message can pass the check (it's an invalid message format)
- // with just the Message's Body filled, the Event is "OnNativeMessage" and IsNative always true.
- // This event should be defined under an empty namespace in order this to work.
- OnNativeMessage = "_OnNativeMessage"
- )
- // IsSystemEvent reports whether the "event" is a system event,
- // OnNamespaceConnect, OnNamespaceConnected, OnNamespaceDisconnect,
- // OnRoomJoin, OnRoomJoined, OnRoomLeave and OnRoomLeft.
- func IsSystemEvent(event string) bool {
- switch event {
- case OnNamespaceConnect, OnNamespaceConnected, OnNamespaceDisconnect,
- OnRoomJoin, OnRoomJoined, OnRoomLeave, OnRoomLeft:
- return true
- default:
- return false
- }
- }
- // CloseError can be used to send and close a remote connection in the event callback's return statement.
- type CloseError struct {
- error
- Code int
- }
- func (err CloseError) Error() string {
- return fmt.Sprintf("[%d] %s", err.Code, err.error.Error())
- }
- // IsDisconnectError reports whether the "err" is a timeout or a closed connection error.
- func IsDisconnectError(err error) bool {
- if err == nil {
- return false
- }
- return IsCloseError(err) || IsTimeoutError(err)
- }
- func isManualCloseError(err error) bool {
- if _, ok := err.(CloseError); ok {
- return true
- }
- return false
- }
- // IsCloseError reports whether the "err" is a "closed by the remote host" network connection error.
- func IsCloseError(err error) bool {
- if err == nil {
- return false
- }
- if isManualCloseError(err) {
- return true
- }
- if err == io.ErrUnexpectedEOF || err == io.EOF {
- return true
- }
- if netErr, ok := err.(*net.OpError); ok {
- if netErr.Err == nil {
- return false
- }
- if sysErr, ok := netErr.Err.(*os.SyscallError); ok {
- return sysErr != nil
- // return strings.HasSuffix(sysErr.Err.Error(), "closed by the remote host.")
- }
- return strings.HasSuffix(err.Error(), "use of closed network connection")
- }
- return false
- }
- // IsTimeoutError reports whether the "err" is caused by a defined timeout.
- func IsTimeoutError(err error) bool {
- if err == nil {
- return false
- }
- if netErr, ok := err.(*net.OpError); ok {
- // poll.TimeoutError is the /internal/poll of the go language itself, we can't use it directly.
- return netErr.Timeout()
- }
- return false
- }
- type reply struct {
- Body []byte
- }
- func (r reply) Error() string {
- return ""
- }
- func isReply(err error) ([]byte, bool) {
- if err != nil {
- if r, ok := err.(reply); ok {
- return r.Body, true
- }
- }
- return nil, false
- }
- // Reply is a special type of custom error which sends a message back to the other side
- // with the exact same incoming Message's Namespace (and Room if specified)
- // except its body which would be the given "body".
- func Reply(body []byte) error {
- return reply{body}
- }
|