notification.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package notification
  2. import (
  3. "container/list"
  4. "strings"
  5. "imuslab.com/arozos/mod/info/logger"
  6. )
  7. /*
  8. Notification Producer and Consumer Queue
  9. This module is designed to route the notification from module that produce it
  10. to all the devices or agent that can reach the user
  11. */
  12. // Notification priority levels. A producer tags each notification with one of
  13. // these so that users can decide, per delivery channel, the minimum priority
  14. // they wish to receive.
  15. const (
  16. PriorityLow = 1
  17. PriorityMedium = 2
  18. PriorityHigh = 3
  19. )
  20. type NotificationPayload struct {
  21. ID string //Notification ID, generate by producer
  22. Title string //Title of the notification
  23. Message string //Message of the notification
  24. Receiver []string //Receiver, username in arozos system
  25. Sender string //Sender, the sender or module of the notification
  26. Priority int //Priority of the notification, see Priority* constants (0 = unset, treated as medium)
  27. Timestamp int64 //Unix timestamp (seconds) when the notification was produced
  28. Payload string //Optional payload, e.g. a JSON window-open option used by the desktop agent for click redirection
  29. ReciverAgents []string //Agent name that have access to this notification
  30. }
  31. type AgentProducerFunction func(*NotificationPayload) error
  32. type Agent interface {
  33. //Defination of the agent
  34. Name() string //The name of the notification agent, must be unique
  35. Desc() string //Basic description of the agent
  36. IsConsumer() bool //Can receive notification can arozos core
  37. IsProducer() bool //Can produce notification to arozos core
  38. ConsumerNotification(*NotificationPayload) error //Endpoint for arozos -> this agent
  39. ProduceNotification(*AgentProducerFunction) //Endpoint for this agent -> arozos
  40. }
  41. // Sender is implemented by anything (e.g. the ArozOS core notification router)
  42. // that can accept a notification for delivery. Injected into subsystems like
  43. // the AGI gateway so scripts can raise notifications without importing the
  44. // concrete queue implementation.
  45. type Sender interface {
  46. SendNotification(*NotificationPayload) error
  47. }
  48. type NotificationQueue struct {
  49. Agents []*Agent
  50. MasterQueue *list.List
  51. }
  52. func NewNotificationQueue() *NotificationQueue {
  53. thisQueue := list.New()
  54. return &NotificationQueue{
  55. Agents: []*Agent{},
  56. MasterQueue: thisQueue,
  57. }
  58. }
  59. // Add a notification agent to the queue
  60. func (q *NotificationQueue) RegisterNotificationAgent(agent Agent) {
  61. q.Agents = append(q.Agents, &agent)
  62. }
  63. // GetAgentByName returns the registered agent with the given name, or nil if
  64. // no such agent is registered.
  65. func (q *NotificationQueue) GetAgentByName(name string) Agent {
  66. for _, agent := range q.Agents {
  67. if (*agent).Name() == name {
  68. return *agent
  69. }
  70. }
  71. return nil
  72. }
  73. // ListConsumerAgentNames returns the names of all registered agents that can
  74. // consume (deliver) notifications.
  75. func (q *NotificationQueue) ListConsumerAgentNames() []string {
  76. names := []string{}
  77. for _, agent := range q.Agents {
  78. if (*agent).IsConsumer() {
  79. names = append(names, (*agent).Name())
  80. }
  81. }
  82. return names
  83. }
  84. func (q *NotificationQueue) BroadcastNotification(message *NotificationPayload) error {
  85. //Send notification to consumer agents
  86. for _, agent := range q.Agents {
  87. thisAgent := *agent
  88. inAgentList := false
  89. for _, enabledAgent := range message.ReciverAgents {
  90. if enabledAgent == thisAgent.Name() {
  91. //This agent is activated
  92. inAgentList = true
  93. break
  94. }
  95. }
  96. if !inAgentList {
  97. //Skip this agent and continue
  98. continue
  99. }
  100. //Send this notification via this agent
  101. err := thisAgent.ConsumerNotification(message)
  102. if err != nil {
  103. logger.PrintAndLog("Notification", "[Notification] Unable to send message via notification agent: "+thisAgent.Name(), nil)
  104. }
  105. }
  106. logger.PrintAndLog("Notification", "[Notification] Message titled: "+message.Title+" (ID: "+message.ID+") broadcasted", nil)
  107. return nil
  108. }
  109. // PriorityFromString converts a human readable priority string (low / medium /
  110. // high, case-insensitive) into one of the Priority* constants. Any unknown
  111. // value falls back to PriorityMedium.
  112. func PriorityFromString(priority string) int {
  113. switch strings.ToLower(strings.TrimSpace(priority)) {
  114. case "low":
  115. return PriorityLow
  116. case "medium", "med", "normal":
  117. return PriorityMedium
  118. case "high", "urgent":
  119. return PriorityHigh
  120. default:
  121. return PriorityMedium
  122. }
  123. }
  124. // PriorityToString converts a Priority* constant back into its human readable
  125. // form. Any unknown value is reported as "medium".
  126. func PriorityToString(priority int) string {
  127. switch priority {
  128. case PriorityLow:
  129. return "low"
  130. case PriorityHigh:
  131. return "high"
  132. default:
  133. return "medium"
  134. }
  135. }
  136. // NormalizePriority clamps an arbitrary integer into a valid Priority* value,
  137. // treating the zero value (unset) as PriorityMedium.
  138. func NormalizePriority(priority int) int {
  139. if priority < PriorityLow {
  140. return PriorityMedium
  141. }
  142. if priority > PriorityHigh {
  143. return PriorityHigh
  144. }
  145. return priority
  146. }