-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathprotocol.go
110 lines (93 loc) · 4.22 KB
/
protocol.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
Copyright 2013 Niklas Voss
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
http://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 golem
import (
"encoding/json"
"errors"
"strings"
)
const (
protocolSeperator = " "
// BinaryMode represents binary WebSocket operations
BinaryMode = 1
// TextMode represents text-based WebSocket operations
TextMode = 2
)
var (
// protocol routers will initially be using
initialProtocol Protocol = Protocol(&DefaultJSONProtocol{})
)
// Protocol-interface provides the required methods necessary for any
// protocol, that should be used with golem, to implement.
// The evented system of golem needs several steps to process incoming data:
// 1. Unpack to extract the name of the event that was emitted.
// (next golem checks if an event handler exists, if does, the next method is called with the associated structure of the event)
// 2. Unmarshal the interstage product from unpack into the desired type.
// For emitting data the process is reversed, but merged in a single function,
// because evaluation the desired unmarshaled type is not necessary:
// 1. MarshalAndPack marhals the data and the event name into an array of bytes.
// The GetReadMode and GetWriteMode functions define what kind of WebSocket-
// Communication will be used.
type Protocol interface {
// Unpack splits/extracts event name from incoming data.
// Takes incoming data bytes as parameter and returns the event name, interstage data and if an error occured the error.
Unpack([]byte) (string, interface{}, error)
// Unmarshals leftover data into associated type of callback.
// Takes interstage product and desired type as parameters and returns error if unsuccessful.
Unmarshal(interface{}, interface{}) error
// Marshal and pack data into byte array
// Takes event name and type pointer as parameters and returns byte array or error if unsuccessful.
MarshalAndPack(string, interface{}) ([]byte, error)
// Returns read mode, that should be used for this protocol.
GetReadMode() int
// Returns write mode, that should be used for this protocol
GetWriteMode() int
}
// SetDefaultProtocol sets the protocol that should be used by newly created routers. Therefore every router
// created after changing the default protocol will use the new protocol by default.
func SetDefaultProtocol(protocol Protocol) {
initialProtocol = protocol
}
// DefaultJSONProtocol is the initial protocol used by golem. It implements the
// Protocol-Interface.
// (Note: there is an article about this simple protocol in golem's wiki)
type DefaultJSONProtocol struct{}
// Unpack splits the event name from the incoming message.
func (_ *DefaultJSONProtocol) Unpack(data []byte) (string, interface{}, error) {
result := strings.SplitN(string(data), protocolSeperator, 2)
if len(result) != 2 {
return "", nil, errors.New("Unable to extract event name from data.")
}
return result[0], []byte(result[1]), nil
}
// Unmarshals data into requested structure. If not successful the function return an error.
func (_ *DefaultJSONProtocol) Unmarshal(data interface{}, typePtr interface{}) error {
return json.Unmarshal(data.([]byte), typePtr)
}
// Marshals structure into JSON and packs event name in as well. If not successful second return value is an error.
func (_ *DefaultJSONProtocol) MarshalAndPack(name string, structPtr interface{}) ([]byte, error) {
if data, err := json.Marshal(structPtr); err == nil {
result := []byte(name + protocolSeperator)
return append(result, data...), nil
} else {
return nil, err
}
}
// Return TextMode because JSON is transmitted using the text mode of WebSockets.
func (_ *DefaultJSONProtocol) GetReadMode() int {
return TextMode
}
// Return TextMode because JSON is transmitted using the text mode of WebSockets.
func (_ *DefaultJSONProtocol) GetWriteMode() int {
return TextMode
}