github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/integration/activemq/activemq.go (about) 1 package activemq 2 3 import ( 4 "crypto/x509" 5 "database/sql" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/signal" 11 "strconv" 12 "syscall" 13 "time" 14 15 "github.com/go-stomp/stomp" 16 "github.com/google/uuid" 17 "github.com/mdaxf/iac-signalr/signalr" 18 "github.com/mdaxf/iac/com" 19 dbconn "github.com/mdaxf/iac/databases" 20 "github.com/mdaxf/iac/documents" 21 "github.com/mdaxf/iac/framework/queue" 22 "github.com/mdaxf/iac/logger" 23 ) 24 25 type ActiveMQconfigs struct { 26 ActiveMQs []ActiveMQconfig `json:"activemqs"` 27 ApiKey string `json:"apikey"` 28 } 29 30 // ActiveMQ struct 31 type ActiveMQconfig struct { 32 Host string `json:"host"` 33 Port string `json:"port"` 34 Username string `json:"username"` 35 Password string `json:"passwrod"` 36 TLS string `json:"tls"` 37 TLSVerify bool `json:"tlsverify"` 38 CAPath string `json:"CAPath"` 39 CertPath string `json:"CertPath"` 40 KeyPath string `json:"keypath"` 41 Topics []ActiveMQtopic `json:"topics"` 42 } 43 44 type ActiveMQtopic struct { 45 Topic string `json:"topic"` 46 Handler string `json:"handler"` 47 SQLQuery string `json:"sqlquery"` 48 Mode string `json:"mode"` 49 Type string `json:"type"` 50 } 51 52 // ActiveMQ struct 53 type ActiveMQ struct { 54 Config ActiveMQconfig 55 Conn *stomp.Conn 56 Subs []*stomp.Subscription 57 ConnectionID string 58 QueueID string 59 iLog logger.Log 60 Queue *queue.MessageQueue 61 DocDBconn *documents.DocDB 62 DB *sql.DB 63 SignalRClient signalr.Client 64 AppServer string 65 ApiKey string 66 } 67 68 /* 69 type msghandler struct { 70 Topic string 71 Handler string 72 Message stomp.Message 73 } 74 */ 75 func NewActiveMQConnection(config ActiveMQconfig) *ActiveMQ { 76 77 activeMQ := connectActiveMQ(config) 78 79 if activeMQ == nil { 80 iLog := logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "ActiveMQConnection"} 81 82 iLog.Critical(fmt.Sprintf(("Fail to create activeMQ connection with configuration : %s"), logger.ConvertJson(config))) 83 84 return nil 85 } 86 activeMQ.iLog.Debug(fmt.Sprintf("Create ActiveMQ connection successful!")) 87 88 uuid_ := uuid.New().String() 89 90 activeMQ.DocDBconn = documents.DocDBCon 91 activeMQ.DB = dbconn.DB 92 activeMQ.SignalRClient = com.IACMessageBusClient 93 activeMQ.Queue = queue.NewMessageQueue(uuid_, "ActiveMQ") 94 activeMQ.Queue.DocDBconn = documents.DocDBCon 95 activeMQ.Queue.DB = dbconn.DB 96 activeMQ.Queue.SignalRClient = com.IACMessageBusClient 97 98 activeMQ.Subscribes() 99 100 return activeMQ 101 } 102 103 func NewActiveMQConnectionExternal(config ActiveMQconfig, docDBconn *documents.DocDB, db *sql.DB, signalRClient signalr.Client) *ActiveMQ { 104 105 activeMQ := connectActiveMQ(config) 106 107 if activeMQ == nil { 108 iLog := logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "ActiveMQConnection"} 109 110 iLog.Critical(fmt.Sprintf(("Fail to create activeMQ connection with configuration : %s"), logger.ConvertJson(config))) 111 112 return nil 113 } 114 activeMQ.iLog.Debug(fmt.Sprintf("Create ActiveMQ connection successful!")) 115 116 uuid_ := uuid.New().String() 117 activeMQ.Queue = queue.NewMessageQueue(uuid_, "ActiveMQ") 118 activeMQ.Queue.DocDBconn = docDBconn 119 activeMQ.Queue.DB = db 120 activeMQ.Queue.SignalRClient = signalRClient 121 122 activeMQ.DocDBconn = docDBconn 123 activeMQ.DB = db 124 activeMQ.SignalRClient = signalRClient 125 126 // activeMQ.Subscribes() 127 128 return activeMQ 129 130 } 131 func CheckConnection(activemq ActiveMQ) bool { 132 if activemq.Conn == nil { 133 return false 134 } 135 136 return true 137 } 138 func connectActiveMQ(config ActiveMQconfig) *ActiveMQ { 139 140 iLog := logger.Log{ModuleName: logger.Framework, User: "System", ControllerName: "ActiveMQConnection"} 141 142 iLog.Debug(fmt.Sprintf(("Create activeMQ connection with configuration : %s"), logger.ConvertJson(config))) 143 144 if config.Host == "" { 145 iLog.Error("Host is required") 146 return nil 147 } 148 149 if config.Port == "" { 150 iLog.Error("Port is required") 151 return nil 152 } 153 154 var conn *stomp.Conn 155 var err error 156 157 if config.Username == "" && config.TLS == "" { 158 conn, err = stomp.Dial( 159 "tcp", 160 config.Host+":"+config.Port, 161 stomp.ConnOpt.AcceptVersion(stomp.V12), 162 ) 163 } else if config.Username != "" && config.TLS == "" { 164 conn, err = stomp.Dial( 165 "tcp", 166 config.Host+":"+config.Port, 167 stomp.ConnOpt.Login(config.Username, config.Password), 168 ) 169 } else if config.Username == "" && config.TLS != "" && config.TLSVerify == false { 170 conn, err = stomp.Dial( 171 "tcp", 172 config.Host+":"+config.Port, 173 stomp.ConnOpt.AcceptVersion(stomp.V12), 174 // stomp.ConnOpt.TLSConfig(&tls.Config{InsecureSkipVerify: true}), // Set to true for testing purposes only 175 ) 176 } else if config.Username != "" && config.TLS != "" && config.TLSVerify == false { 177 conn, err = stomp.Dial( 178 "tcp", 179 config.Host+":"+config.Port, 180 stomp.ConnOpt.Login(config.Username, config.Password), 181 stomp.ConnOpt.AcceptVersion(stomp.V12), 182 // stomp.ConnOpt.TLSConfig(&tls.Config{InsecureSkipVerify: true}), // Set to true for testing purposes only 183 ) 184 } else if config.Username == "" && config.TLSVerify == true && config.CAPath != "" && config.CertPath != "" { 185 // cert, err := tls.LoadX509KeyPair(config.CertPath, config.KeyPath) 186 if err != nil { 187 iLog.Critical(fmt.Sprintf("Failed to load client certificates: %v", err)) 188 return nil 189 } 190 191 conn, err = stomp.Dial( 192 "tcp", 193 config.Host+":"+config.Port, 194 stomp.ConnOpt.AcceptVersion(stomp.V12), 195 /* stomp.ConnOpt.TLSConfig(&tls.Config{ 196 InsecureSkipVerify: false, // Set to true for testing purposes only 197 RootCAs: loadCACert(config.CAPath, iLog), 198 Certificates: []tls.Certificate{cert}, 199 }), */ 200 ) 201 } else if config.Username != "" && config.Password != "" && config.TLSVerify == true && config.CAPath != "" && config.CertPath != "" { 202 // cert, err := tls.LoadX509KeyPair(config.CertPath, config.KeyPath) 203 if err != nil { 204 iLog.Critical(fmt.Sprintf("Failed to load client certificates: %v", err)) 205 return nil 206 } 207 208 conn, err = stomp.Dial( 209 "tcp", 210 config.Host+":"+config.Port, 211 stomp.ConnOpt.Login(config.Username, config.Password), 212 stomp.ConnOpt.AcceptVersion(stomp.V12), 213 /* stomp.ConnOpt.TLSConfig(&tls.Config{ 214 InsecureSkipVerify: false, // Set to true for testing purposes only 215 RootCAs: loadCACert(config.CAPath, iLog), 216 Certificates: []tls.Certificate{cert}, 217 }), */ 218 ) 219 } else { 220 iLog.Error("Invalid configuration") 221 return nil 222 } 223 224 if err != nil { 225 iLog.Error(fmt.Sprintf("Error while connecting to ActiveMQ: %s", err.Error())) 226 return nil 227 } 228 activeMQ := &ActiveMQ{ 229 Config: config, 230 Conn: conn, 231 iLog: iLog, 232 } 233 234 return activeMQ 235 236 } 237 238 func loadCACert(caCertFile string, iLog logger.Log) *x509.CertPool { 239 caCert, err := ioutil.ReadFile(caCertFile) 240 if err != nil { 241 iLog.Error(fmt.Sprintf("Failed to read CA certificate: %v", err)) 242 } 243 caCertPool := x509.NewCertPool() 244 caCertPool.AppendCertsFromPEM(caCert) 245 return caCertPool 246 } 247 248 func (a *ActiveMQ) Subscribes() { 249 /* 250 messageChannel := make(chan msghandler) 251 252 messageHandler := func(msg stomp.Message) { 253 messageChannel <- msg 254 } */ 255 256 for _, item := range a.Config.Topics { 257 topic := item.Topic 258 handler := item.Handler 259 // mode := item.Mode 260 executetype := item.Type 261 262 sub, err := a.Conn.Subscribe(topic, stomp.AckAuto) 263 if err != nil { 264 a.iLog.Error(fmt.Sprintf("Error while subscribing to topic %s: %s", topic, err.Error())) 265 } 266 a.Subs = append(a.Subs, sub) 267 go func() { 268 if executetype == "local" { 269 msgID := 0 270 for { 271 msg := <-sub.C 272 msgID += 1 273 fmt.Println("Received message", string(msg.Body)) 274 message := queue.Message{ 275 Id: strconv.FormatUint(uint64(msgID), 10), 276 UUID: uuid.New().String(), 277 Retry: 3, 278 Execute: 0, 279 Topic: topic, 280 PayLoad: msg.Body, 281 Handler: handler, 282 CreatedOn: time.Now().UTC(), 283 } 284 285 a.iLog.Debug(fmt.Sprintf("Push message %v to queue: %s", message, a.Queue.QueueID)) 286 a.Queue.Push(message) 287 } 288 } else { 289 for { 290 msg := <-sub.C 291 fmt.Println("Received message", string(msg.Body)) 292 a.CallWebService(msg, topic, handler) 293 } 294 } 295 }() 296 } 297 298 a.waitForTerminationSignal() 299 300 } 301 302 func (a *ActiveMQ) CallWebService(msg *stomp.Message, topic string, handler string) { 303 304 method := "POST" 305 url := a.AppServer + "/trancode/execute" 306 307 var result map[string]interface{} 308 err := json.Unmarshal(msg.Body, &result) 309 if err != nil { 310 a.iLog.Error(fmt.Sprintf("Error:", err)) 311 return 312 } 313 var inputs map[string]interface{} 314 315 inputs["Payload"] = result 316 inputs["Topic"] = topic 317 318 msgdata := make(map[string]interface{}) 319 msgdata["TranCode"] = handler 320 msgdata["Inputs"] = inputs 321 322 headers := make(map[string]string) 323 headers["Content-Type"] = "application/json" 324 headers["Authorization"] = "apikey " + a.ApiKey 325 326 result, err = com.CallWebService(url, method, msgdata, headers) 327 328 if err != nil { 329 a.iLog.Error(fmt.Sprintf("Error in WebServiceCallFunc.Execute: %s", err)) 330 return 331 } 332 333 a.iLog.Debug(fmt.Sprintf("Response data: %v", result)) 334 335 } 336 337 func (a *ActiveMQ) waitForTerminationSignal() { 338 c := make(chan os.Signal, 1) 339 signal.Notify(c, os.Interrupt, syscall.SIGTERM) 340 <-c 341 fmt.Println("\nShutting down...") 342 343 for _, sub := range a.Subs { 344 sub.Unsubscribe() 345 } 346 347 a.Conn.Disconnect() 348 time.Sleep(2 * time.Second) // Add any cleanup or graceful shutdown logic here 349 os.Exit(0) 350 }