The hub type

The chat hub is responsible for maintaining a list of client connections and directing the chatbot to broadcast a message to the relevant client. For example, if Alice asked the question "What is Isomorphic Go?", the answer from the chatbot should go to Alice and not to Bob (who may not have even asked a question yet).

Here's what the Hub struct looks like:

type Hub struct {
chatbot bot.Bot
clients map[*Client]bool
broadcastmsg chan *ClientMessage
register chan *Client
unregister chan *Client
}

The chatbot is a chat bot (agent) that implements the Bot interface. This is the brain that will answer the questions received from clients.

The clients map is used to register clients. The key-value pair stored in the map consists of the key, a pointer to a Client instance, and the value consists of a Boolean value set to true to indicate that the client is connected. Clients communicate with the hub over the broadcastmsg, register, and unregister channels. The register channel registers a client with the hub. The unregister channel, unregisters a client with the hub. The client sends the message entered by the user over the broadcastmsg channel, a channel of type ClientMessage. Here's the ClientMessage struct that we have introduced:

type ClientMessage struct {
client *Client
message []byte
}

To fulfill the first major change we laid out previously, that is, the exclusivity of the conversation between the agent and the user, we use the ClientMessage struct to store, both the pointer to the Client instance that sent the user's message along with the user's message itself (a byte slice).

The constructor function, NewHub, takes in chatbot that implements the Bot interface and returns a new Hub instance:

func NewHub(chatbot bot.Bot) *Hub {
return &Hub{
chatbot: chatbot,
broadcastmsg: make(chan *ClientMessage),
register: make(chan *Client),
unregister: make(chan *Client),
clients: make(map[*Client]bool),
}
}

We implement an exported getter method, ChatBot, so that the chatbot can be accessed from the Hub object:

func (h *Hub) ChatBot() bot.Bot {
return h.chatbot
}

This action will be significant when we implement a Rest API endpoint to send the bot's details (its name, title, and avatar image) to the client.

The SendMessage method is responsible for broadcasting a message to a particular client:

func (h *Hub) SendMessage(client *Client, message []byte) {
client.send <- message
}

The method takes in a pointer to Client, and the message, which is a byte slice, that should be sent to that particular client. The message will be sent over the client's send channel.

The Run method is called to start the chat hub:

func (h *Hub) Run() {
for {
select {
case client := <-h.register:
h.clients[client] = true
greeting := h.chatbot.Greeting()
h.SendMessage(client, []byte(greeting))

case client := <-h.unregister:
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
case clientmsg := <-h.broadcastmsg:
client := clientmsg.client
reply := h.chatbot.Reply(string(clientmsg.message))
h.SendMessage(client, []byte(reply))
}
}
}

We use the select statement inside the for loop to wait on multiple client operations.

In the case that a pointer to a Client comes in over the hub's register channel, the hub will register the new client by adding the client pointer (as the key) to the clients map and set a value of true for it. We will fetch a greeting message to return to the client by calling the Greeting method on chatbot. Once we get the greeting (a string value), we call the SendMessage method passing in the client and the greeting converted to a byte slice.

In the case that a pointer to a Client comes in over the hub's unregister channel, the hub will remove the entry in map for the given client and close the client's send channel, which signifies that the client won't be sending any more messages to the server.

In the case that a pointer to a ClientMessage comes in over the hub's broadcastmsg channel, the hub will pass the client's message (as a string value) to the Reply method of the chatbot object. Once we get reply (a  string value) from the agent, we call the SendMessage method passing in the client and the reply converted to a byte slice.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.41.212