Skip to content

Commit

Permalink
feat: add text, command, location, custom message implementation (#12)
Browse files Browse the repository at this point in the history
* Change the JSONPayload Content field to any

* feat(message: users, groups, rooms): Add support text, command, location, custom message
  • Loading branch information
ycj3 authored Sep 14, 2024
1 parent 5e68729 commit be96353
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 53 deletions.
110 changes: 80 additions & 30 deletions agora-chat/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,6 @@ type MessageManager struct {
client *client
}

type MessageType string

const (
MessageTypeText MessageType = "txt" // Text message
MessageTypeImage MessageType = "img" // Image message
MessageTypeAudio MessageType = "audio" // Voice message
MessageTypeVideo MessageType = "video" // Video message
MessageTypeFile MessageType = "file" // File message
MessageTypeLoc MessageType = "loc" // Location message
MessageTypeCmd MessageType = "cmd" // Command message
MessageTypeCustom MessageType = "custom" // Custom message
)

type messageResponseResult struct {
Response
Path string `json:"path"`
Expand All @@ -36,53 +23,116 @@ type messageResponseResult struct {
ApplicationName string `json:"applicationName"`
}

func (mm *MessageManager) SendUserMessage(from string, to []string, msgType MessageType, body map[string]interface{}, options map[string]interface{}) (map[string]string, error) {
request := mm.sendUserMessageRequest(from, to, msgType, body, options)
// SendUserMessage sends a Message to users via Agora Chat Server.
func (mm *MessageManager) SendUsersMessage(message *Message) (map[string]string, error) {
request, err := mm.sendUsersMessageRequest(message)
if err != nil {
return nil, err
}

res, err := mm.client.messageClient.Send(request)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
return res.Data.Data, nil
}

func (mm *MessageManager) sendUserMessageRequest(from string, to []string, msgType MessageType, body map[string]interface{}, options map[string]interface{}) http.Request {

var reqBody = map[string]interface{}{
"from": from,
"to": to,
"type": msgType,
"body": body,
}

for key, value := range options {
reqBody[key] = value
func (mm *MessageManager) sendUsersMessageRequest(message *Message) (http.Request, error) {
if err := validateMessage(message); err != nil {
return http.Request{}, err
}

req := http.Request{
URL: mm.sendUserMessageURL(),
URL: mm.sendUsersMessageURL(),
Method: http.MethodPOST,
ResponseFormat: http.ResponseFormatJSON,
Headers: map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer " + mm.client.appToken,
},
Payload: &http.JSONPayload{
Content: reqBody,
Content: message,
},
}
return req
return req, nil
}

func (mm *MessageManager) sendUserMessageURL() string {
func (mm *MessageManager) sendUsersMessageURL() string {
baseURL := mm.client.appConfig.BaseURL
return fmt.Sprintf("%s/messages/users", baseURL)
}

// SendGroupMessage sends a Message to groups via Agora Chat Server.
func (mm *MessageManager) SendGroupsMessage(message *Message) (map[string]string, error) {
request, err := mm.sendGroupsMessageRequest(message)
if err != nil {
return nil, err
}

res, err := mm.client.messageClient.Send(request)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
return res.Data.Data, nil
}

func (mm *MessageManager) sendGroupsMessageRequest(message *Message) (http.Request, error) {
if err := validateMessage(message); err != nil {
return http.Request{}, err
}

req := http.Request{
URL: mm.sendChatgroupMessageURL(),
Method: http.MethodPOST,
ResponseFormat: http.ResponseFormatJSON,
Headers: map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer " + mm.client.appToken,
},
Payload: &http.JSONPayload{
Content: message,
},
}
return req, nil
}
func (mm *MessageManager) sendChatgroupMessageURL() string {
baseURL := mm.client.appConfig.BaseURL
return fmt.Sprintf("%s/messages/chatgroups", baseURL)
}

// SendRoomsMessage sends a Message to rooms via Agora Chat Server.
func (mm *MessageManager) SendRoomsMessage(message *Message) (map[string]string, error) {
request, err := mm.sendRoomsMessageRequest(message)
if err != nil {
return nil, err
}

res, err := mm.client.messageClient.Send(request)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
return res.Data.Data, nil
}

func (mm *MessageManager) sendRoomsMessageRequest(message *Message) (http.Request, error) {
if err := validateMessage(message); err != nil {
return http.Request{}, err
}

req := http.Request{
URL: mm.sendChatroomMessageURL(),
Method: http.MethodPOST,
ResponseFormat: http.ResponseFormatJSON,
Headers: map[string]string{
"Content-Type": "application/json",
"Authorization": "Bearer " + mm.client.appToken,
},
Payload: &http.JSONPayload{
Content: message,
},
}
return req, nil
}
func (mm *MessageManager) sendChatroomMessageURL() string {
baseURL := mm.client.appConfig.BaseURL
return fmt.Sprintf("%s/messages/chatrooms", baseURL)
Expand Down
27 changes: 13 additions & 14 deletions agora-chat/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,21 @@ var _ = Describe("MessageManager", func() {
ctrl.Finish()
})

Context("SendUserMessage", func() {
Context("SendUsersMessage", func() {
var (
from string
to []string
msgType MessageType
body map[string]interface{}
options map[string]interface{}
message *Message
response http.Result[messageResponseResult]
)

BeforeEach(func() {
from = "user1"
to = []string{"user2"}
msgType = MessageTypeText
body = map[string]interface{}{"msg": "Hello"}
options = map[string]interface{}{"option1": "value1"}
message = &Message{
From: "user1",
To: []string{"user2"},
Type: MessageTypeText,
Body: TextMessageBody{
Msg: "Hello",
},
}
response = http.Result[messageResponseResult]{
StatusCode: gohttp.StatusOK,
Data: messageResponseResult{
Expand All @@ -61,7 +60,7 @@ var _ = Describe("MessageManager", func() {
Send(gomock.Any()).
Return(response, nil)

result, err := messageManager.SendUserMessage(from, to, msgType, body, options)
result, err := messageManager.SendUsersMessage(message)
Expect(err).To(BeNil())
Expect(result).To(Equal(map[string]string{"message": "Message sent successfully"}))
})
Expand All @@ -71,7 +70,7 @@ var _ = Describe("MessageManager", func() {
Send(gomock.Any()).
Return(http.Result[messageResponseResult]{}, errors.New("request failed"))

result, err := messageManager.SendUserMessage(from, to, msgType, body, options)
result, err := messageManager.SendUsersMessage(message)
Expect(err).To(HaveOccurred())
Expect(result).To(BeNil())
Expect(err.Error()).To(Equal("request failed: request failed"))
Expand All @@ -87,7 +86,7 @@ var _ = Describe("MessageManager", func() {
// Send(gomock.Any()).
// Return(response, nil)

// result, err := messageManager.SendUserMessage(from, to, msgType, body, options)
// result, err := messageManager.SendUsersMessage(from, to, msgType, body, options)
// Expect(err).To(HaveOccurred())
// Expect(result).To(BeNil())
// })
Expand Down
47 changes: 47 additions & 0 deletions agora-chat/message_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
Copyright © 2024 Carlson <[email protected]>
*/
package agora_chat

type MessageType string

const (
MessageTypeText MessageType = "txt" // Text message
MessageTypeImage MessageType = "img" // Image message
MessageTypeAudio MessageType = "audio" // Voice message
MessageTypeVideo MessageType = "video" // Video message
MessageTypeFile MessageType = "file" // File message
MessageTypeLoc MessageType = "loc" // Location message
MessageTypeCmd MessageType = "cmd" // Command message
MessageTypeCustom MessageType = "custom" // Custom message
)

// TextMessageBody represents the payload data for a text type message.
type TextMessageBody struct {
Msg string `json:"msg,omitempty"`
}

// CMDMessageBody represents the payload data of the command type message.
type CMDMessageBody struct {
Action string `json:"action,omitempty"`
}

// LocationMessageBody represents the payload data of the location type message.
type LocationMessageBody struct {
Lat string `json:"lat,omitempty"`
Lng string `json:"lng,omitempty"`
Addr string `json:"addr,omitempty"`
}

// CustomMessageBody represents the payload data of the custom type message.
type CustomMessageBody struct {
CustomEvent string `json:"customEvent,omitempty"`
CustomExts map[string]string `json:"customExts,omitempty"`
}

type Message struct {
From string `json:"from,omitempty"`
To []string `json:"to,omitempty"`
Type MessageType `json:"type,omitempty"`
Body interface{} `json:"body,omitempty"`
}
83 changes: 83 additions & 0 deletions agora-chat/message_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
Copyright © 2024 Carlson <[email protected]>
*/
package agora_chat

import (
"fmt"
)

func validateMessage(message *Message) error {
if message == nil {
return fmt.Errorf("message must not be nil")
}

if message.To == nil || len(message.To) <= 0 {
return fmt.Errorf("to must be specified")
}

if message.Type == "" {
return fmt.Errorf("type must be specified")
}

if message.Body == nil {
return fmt.Errorf("body must be specified")
}

if message.Type == MessageTypeText {
textBody, ok := message.Body.(TextMessageBody)
if !ok {
return fmt.Errorf("invalid type: expected TextMessageBody")
}
return validateTextMessageBody(textBody)
}

if message.Type == MessageTypeCmd {
cmdBody, ok := message.Body.(CMDMessageBody)
if !ok {
return fmt.Errorf("invalid type: expected CMDMessageBody")
}
return validateCMDMessageBody(cmdBody)
}

if message.Type == MessageTypeLoc {
locBody, ok := message.Body.(LocationMessageBody)
if !ok {
return fmt.Errorf("invalid type: expected CMDMessageBody")
}
return validateLocationMessageBody(locBody)
}

return nil

}

func validateTextMessageBody(body TextMessageBody) error {
if body.Msg == "" {
return fmt.Errorf("msg is required when specifying TextMessageBody")
}
return nil
}

func validateCMDMessageBody(body CMDMessageBody) error {
if body.Action == "" {
return fmt.Errorf("action is required when specifying CMDMessageBody")
}
return nil
}

func validateLocationMessageBody(body LocationMessageBody) error {
if body.Lat == "" {
return fmt.Errorf("lat is required when specifying LocationMessageBody")
}

if body.Lng == "" {
return fmt.Errorf("lng is required when specifying LocationMessageBody")
}

if body.Addr == "" {
return fmt.Errorf("addr is required when specifying LocationMessageBody")
}

return nil
}
16 changes: 8 additions & 8 deletions cmd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ var logUploadCmd = &cobra.Command{
}

func sendUploadLogsCMD(userIDs []string) {
msgIDs, err := client.Message().SendUserMessage(
"admin",
userIDs,
ac.MessageTypeCmd,
map[string]interface{}{
"type": "cmd",
"action": "em_upload_log",
message := ac.Message{
From: "admin",
To: userIDs,
Type: ac.MessageTypeCmd,
Body: ac.CMDMessageBody{
Action: "em_upload_log",
},
nil)
}
msgIDs, err := client.Message().SendUsersMessage(&message)
if err != nil {
fmt.Println(err)
}
Expand Down
Loading

0 comments on commit be96353

Please sign in to comment.