Files
oc-scheduler/infrastructure/nats/nats_handlers.go
2026-04-29 07:45:41 +02:00

147 lines
5.2 KiB
Go

package nats
import (
"encoding/json"
"oc-scheduler/infrastructure/execution"
"oc-scheduler/infrastructure/planner"
"oc-scheduler/infrastructure/scheduling_resources"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/models/booking"
"cloud.o-forge.io/core/oc-lib/models/peer"
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
libutils "cloud.o-forge.io/core/oc-lib/models/utils"
"cloud.o-forge.io/core/oc-lib/models/workflow"
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
"cloud.o-forge.io/core/oc-lib/tools"
)
// handleConfirm processes a CONFIRM_EVENT: sets IsDraft=false on the resource.
func handleConfirm(resp tools.NATSResponse) {
scheduling_resources.Confirm(string(resp.Payload), resp.Datatype)
}
// handleConsidersEvent routes CONSIDERS_EVENT to the execution service.
func handleConsidersEvent(resp tools.NATSResponse) {
switch resp.Datatype {
case tools.BOOKING, tools.PURCHASE_RESOURCE:
execution.UpdateExecutionState(resp.Payload, resp.Datatype)
case tools.WORKFLOW_EXECUTION:
execution.ConfirmExecutionDrafts(resp.Payload)
}
}
// handleRemoveResource routes REMOVE_RESOURCE to the appropriate service.
func handleRemoveResource(resp tools.NATSResponse) {
adminReq := &tools.APIRequest{Admin: true}
switch resp.Datatype {
case tools.WORKFLOW:
var wf workflow.Workflow
if err := json.Unmarshal(resp.Payload, &wf); err != nil {
return
}
planner.GetPlannerService().NotifyWorkflow(wf.GetID())
case tools.BOOKING:
var p scheduling_resources.RemoveResourcePayload
if err := json.Unmarshal(resp.Payload, &p); err != nil {
return
}
scheduling_resources.GetService().HandleRemoveBooking(p, adminReq)
case tools.PURCHASE_RESOURCE:
var p scheduling_resources.RemoveResourcePayload
if err := json.Unmarshal(resp.Payload, &p); err != nil {
return
}
scheduling_resources.GetService().HandleRemovePurchase(p, adminReq)
case tools.WORKFLOW_EXECUTION:
var p scheduling_resources.RemoveResourcePayload
if err := json.Unmarshal(resp.Payload, &p); err != nil || p.ID == "" {
return
}
// DeleteOne calls GenericDeleteOne internally which fires NotifyChange.
workflow_execution.NewAccessor(adminReq).DeleteOne(p.ID)
}
}
// handleCreateResource routes CREATE_RESOURCE to the appropriate service.
func handleCreateResource(resp tools.NATSResponse) {
adminReq := &tools.APIRequest{Admin: true}
switch resp.Datatype {
case tools.WORKFLOW:
var wf workflow.Workflow
if err := json.Unmarshal(resp.Payload, &wf); err != nil {
return
}
planner.GetPlannerService().Broadcast(&wf)
planner.GetPlannerService().NotifyWorkflow(wf.GetID())
case tools.BOOKING:
var bk booking.Booking
if err := json.Unmarshal(resp.Payload, &bk); err != nil {
return
}
if bk.FromNano != "" {
access := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
pp := access.LoadOne(bk.FromNano)
if p := pp.ToPeer(); p == nil || p.Relation == peer.NANO {
return
}
access = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.BOOKING), nil)
d := access.LoadOne(bk.GetID())
if d.Data == nil {
access.StoreOne(bk.Serialize(&bk))
} else {
access.UpdateOne(bk.Serialize(&bk), bk.GetID())
}
return
}
needsConsiders := scheduling_resources.GetService().HandleCreateBooking(&bk, adminReq)
if needsConsiders {
payload, _ := json.Marshal(execution.ConsidersPayload{ID: bk.GetID()})
execution.UpdateExecutionState(payload, tools.BOOKING)
}
case tools.PURCHASE_RESOURCE:
var pr purchase_resource.PurchaseResource
if err := json.Unmarshal(resp.Payload, &pr); err != nil {
return
}
if pr.FromNano != "" {
access := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil)
pp := access.LoadOne(pr.FromNano)
if p := pp.ToPeer(); p == nil || p.Relation == peer.NANO {
return
}
access = oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PURCHASE_RESOURCE), nil)
d := access.LoadOne(pr.GetID())
if d.Data == nil {
access.StoreOne(pr.Serialize(&pr))
} else {
access.UpdateOne(pr.Serialize(&pr), pr.GetID())
}
return
}
needsConsiders := scheduling_resources.GetService().HandleCreatePurchase(&pr, adminReq)
if needsConsiders {
payload, _ := json.Marshal(execution.ConsidersPayload{ID: pr.GetID()})
execution.UpdateExecutionState(payload, tools.PURCHASE_RESOURCE)
}
case tools.WORKFLOW_EXECUTION:
// Only propagate the state change onto an execution that oc-scheduler
// already owns. Never create executions from an external NATS event:
// creation is strictly oc-scheduler's responsibility (via the session
// flow), and blindly calling StoreOne here would trigger
// StoreDraftDefault (IsDraft=true, State=DRAFT), polluting the name-
// uniqueness index and breaking the check stream's first draft creation.
var update workflow_execution.WorkflowExecution
if err := json.Unmarshal(resp.Payload, &update); err != nil || update.GetID() == "" {
return
}
res, _, loadErr := workflow_execution.NewAccessor(adminReq).LoadOne(update.GetID())
if loadErr != nil || res == nil {
return
}
exec := res.(*workflow_execution.WorkflowExecution)
exec.State = update.State
libutils.GenericRawUpdateOne(exec, exec.GetID(), workflow_execution.NewAccessor(adminReq))
}
}