/
chat.go
157 lines (127 loc) · 4.11 KB
/
chat.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package chat
import (
"crypto/rand"
"encoding/json"
"fmt"
"github.com/gorilla/websocket"
)
// ======================================= //
// A Client will connect to the Olivia's server using the Token the Information and the Locale
type Client struct {
Information *map[string]interface{}
Locale string
Token string
Connection *websocket.Conn
Channel chan string
}
// RequestMessage is the structure that uses entry connections to chat with the websocket
type RequestMessage struct {
Type int `json:"type"` // 0 for handshakes and 1 for messages
Content string `json:"content"`
Token string `json:"user_token"`
Information map[string]interface{} `json:"information"`
Locale string `json:"locale"`
}
// ResponseMessage is the structure used to reply to the user through the websocket
type ResponseMessage struct {
Content string `json:"content"`
Tag string `json:"tag"`
Information map[string]interface{} `json:"information"`
}
// ======================================= //
// ======================================= //
// NewClient creates a new Client by generating a random token, and setting english as the
// default langauge.
// You need to give a pointer of the information map of your client.
// The host is also required with a boolean, if the SSL certificate is required.
func NewClient(host string, ssl bool, information *map[string]interface{}) (client Client, err error) {
// Initialite the scheme and the url
scheme := "ws"
if ssl {
scheme += "s"
}
url := fmt.Sprintf("%s://%s/websocket", scheme, host)
// Create the websocket connection
connection, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
return
}
client = Client{
Information: information,
Locale: "en",
Token: generateToken(),
Connection: connection,
Channel: make(chan string),
}
// Execute the handshake
err = client.handshake()
return
}
// ======================================= //
// ======================================= //
// Close closes the websocket connection
func (client *Client) Close() {
client.Connection.Close()
}
// ======================================= //
// ======================================= //
// SendMessage sends the given content to the websocket of Olivia and returns her response with
// an error.
func (client *Client) SendMessage(content string) (ResponseMessage, error) {
// Marshal the RequestMessage with type 1
message := RequestMessage{
Type: 1,
Content: content,
Token: client.Token,
Information: *client.Information,
Locale: client.Locale,
}
bytes, err := json.Marshal(message)
if err != nil {
return ResponseMessage{}, err
}
// Write the message to the websocket
if err = client.Connection.WriteMessage(websocket.TextMessage, bytes); err != nil {
return ResponseMessage{}, err
}
_, bytes, err = client.Connection.ReadMessage()
if err != nil {
return ResponseMessage{}, err
}
// Unmarshal the json content of the message
var response ResponseMessage
if err = json.Unmarshal(bytes, &response); err != nil {
return ResponseMessage{}, err
}
return response, nil
}
// ======================================= //
// ======================================= //
// handshake performs the handshake request to the websocket
func (client *Client) handshake() error {
// Marshal the RequestMessage with type 0
bytes, err := json.Marshal(RequestMessage{
Type: 0,
Content: "",
Token: client.Token,
Information: *client.Information,
})
if err != nil {
return err
}
// Write the message to the websocket
if err = client.Connection.WriteMessage(websocket.TextMessage, bytes); err != nil {
return err
}
return nil
}
// ======================================= //
// ======================================= //
// generateToken returns a random token of 50 characters
func generateToken() string {
b := make([]byte, 50)
rand.Read(b)
return fmt.Sprintf("%x", b)
}
// ======================================= //
// ======================================= //