2024-08-21 10:04:09 +02:00
package tools
import (
"encoding/json"
2026-01-27 09:35:47 +01:00
"fmt"
2024-08-21 10:04:09 +02:00
"strings"
2026-01-27 09:35:47 +01:00
"sync"
2025-06-24 08:49:53 +02:00
"time"
2024-08-21 10:04:09 +02:00
2024-09-04 10:53:12 +02:00
"cloud.o-forge.io/core/oc-lib/config"
2024-10-17 13:53:57 +02:00
"cloud.o-forge.io/core/oc-lib/logs"
2024-08-21 10:04:09 +02:00
"github.com/nats-io/nats.go"
2026-01-27 09:35:47 +01:00
"github.com/rs/zerolog"
2024-08-21 10:04:09 +02:00
)
2026-01-28 15:05:48 +01:00
type NATSResponse struct {
FromApp string ` json:"from_app" `
Datatype DataType ` json:"datatype" `
Method int ` json:"method" `
Payload [ ] byte ` json:"payload" `
}
2024-08-30 14:50:48 +02:00
// NATS Method Enum defines the different methods that can be used to interact with the NATS server
2024-08-21 10:04:09 +02:00
type NATSMethod int
2026-01-28 15:05:48 +01:00
var meths = [ ] string { "remove execution" , "create execution" , "discovery" , "workflow event" , "peer discovery" }
2026-01-27 09:35:47 +01:00
2024-08-21 10:04:09 +02:00
const (
2026-01-27 09:35:47 +01:00
REMOVE_EXECUTION NATSMethod = iota
CREATE_EXECTUTION
2024-10-17 13:53:57 +02:00
DISCOVERY
2026-01-12 15:40:37 +01:00
WORKFLOW_EVENT
2026-01-28 15:05:48 +01:00
REMOVE_PEER
CREATE_PEER
CREATE_RESOURCE
REMOVE_RESOURCE
2024-08-21 10:04:09 +02:00
)
2026-01-27 09:35:47 +01:00
func ( n NATSMethod ) String ( ) string {
return meths [ n ]
}
2024-08-30 14:50:48 +02:00
// NameToMethod returns the NATSMethod enum value from a string
2024-08-21 10:04:09 +02:00
func NameToMethod ( name string ) NATSMethod {
2026-01-28 15:06:32 +01:00
for _ , v := range [ ... ] NATSMethod { REMOVE_EXECUTION , CREATE_EXECTUTION , DISCOVERY , WORKFLOW_EVENT ,
REMOVE_PEER , CREATE_PEER , CREATE_RESOURCE , REMOVE_RESOURCE } {
2024-08-21 10:04:09 +02:00
if strings . Contains ( strings . ToLower ( v . String ( ) ) , strings . ToLower ( name ) ) {
return v
}
}
return - 1
}
2024-08-30 14:50:48 +02:00
// GenerateKey generates a key for the NATSMethod usefull for standard key based on data name & method
2026-01-27 09:35:47 +01:00
func ( d NATSMethod ) GenerateKey ( ) string {
return strings . ReplaceAll ( d . String ( ) , " " , "_" )
2024-08-21 10:04:09 +02:00
}
2024-08-21 10:21:17 +02:00
type natsCaller struct { }
2024-08-21 10:04:09 +02:00
2024-08-30 14:50:48 +02:00
// NewNATSCaller creates a new instance of the NATS Caller
2024-08-21 10:21:17 +02:00
func NewNATSCaller ( ) * natsCaller {
return & natsCaller { }
2024-08-21 10:04:09 +02:00
}
2024-10-17 13:53:57 +02:00
// on workflows' scheduling. Messages must contain
// workflow execution ID, to allow retrieval of execution infos
2026-01-27 09:37:51 +01:00
func ( s * natsCaller ) ListenNats ( execs map [ NATSMethod ] func ( map [ string ] string ) ) {
2024-10-17 13:53:57 +02:00
log := logs . GetLogger ( )
if config . GetConfig ( ) . NATSUrl == "" {
log . Error ( ) . Msg ( " -> NATS_SERVER is not set" )
return
}
2025-06-24 08:49:53 +02:00
for {
nc , err := nats . Connect ( config . GetConfig ( ) . NATSUrl )
if err != nil {
2026-01-27 09:35:47 +01:00
log . Error ( ) . Msg ( "Could not connect to NATS" )
2025-06-24 08:49:53 +02:00
time . Sleep ( 1 * time . Minute )
continue
}
2026-01-27 09:35:47 +01:00
defer nc . Close ( )
var wg sync . WaitGroup
wg . Add ( len ( execs ) )
for k , v := range execs {
go s . listenForChange ( log , nc , k , v , & wg )
2025-06-24 08:49:53 +02:00
}
2026-01-27 09:35:47 +01:00
wg . Wait ( )
2025-06-24 08:49:53 +02:00
break
2024-10-17 13:53:57 +02:00
}
}
2024-08-30 14:50:48 +02:00
// SetNATSPub sets a message to the NATS server
2026-01-28 15:08:07 +01:00
func ( o * natsCaller ) SetNATSPub ( method NATSMethod , data NATSResponse ) string {
2024-09-04 10:53:12 +02:00
if config . GetConfig ( ) . NATSUrl == "" {
2024-08-21 10:04:09 +02:00
return " -> NATS_SERVER is not set"
}
2025-06-24 08:49:53 +02:00
for {
nc , err := nats . Connect ( config . GetConfig ( ) . NATSUrl )
if err != nil {
time . Sleep ( 1 * time . Minute )
continue
}
defer nc . Close ( )
js , err := json . Marshal ( data )
if err != nil {
return " -> " + err . Error ( )
}
2026-01-27 09:35:47 +01:00
err = nc . Publish ( method . GenerateKey ( ) , js ) // Publish the message on the NATS server with a channel name based on the data name (or whatever start) and the method
2025-06-24 08:49:53 +02:00
if err != nil {
time . Sleep ( 1 * time . Minute )
continue
}
break
2024-08-21 10:04:09 +02:00
}
return ""
}
2026-01-27 09:35:47 +01:00
// Goroutine listening to a NATS server for updates
// on workflows' scheduling. Messages must contain
// workflow execution ID, to allow retrieval of execution infos
func ( o * natsCaller ) listenForChange ( logger zerolog . Logger , nc * nats . Conn , natsTools NATSMethod ,
function func ( map [ string ] string ) , wg * sync . WaitGroup ) {
defer wg . Done ( )
ch := make ( chan * nats . Msg , 64 )
logger . Info ( ) . Msg ( "Listening to " + natsTools . GenerateKey ( ) )
subs , err := nc . ChanSubscribe ( natsTools . GenerateKey ( ) , ch )
if err != nil {
logger . Error ( ) . Msg ( "Error listening to NATS : " + err . Error ( ) )
}
defer subs . Unsubscribe ( )
for msg := range ch {
map_mess := map [ string ] string { }
json . Unmarshal ( msg . Data , & map_mess )
fmt . Println ( "Catching " + natsTools . String ( ) + " workflow... " + map_mess [ "id" ] )
function ( map_mess )
}
}