func (f *forwarder) GetNetworkPayloads(CLG systemspec.CLG, networkPayload objectspec.NetworkPayload) ([]objectspec.NetworkPayload, error) { ctx := networkPayload.GetContext() // Check if there are behaviour IDs known that we can use to forward the // current network payload to. behaviourID, ok := ctx.GetBehaviourID() if !ok { return nil, maskAnyf(invalidBehaviourIDError, "must not be empty") } behaviourIDsKey := key.NewNetworkKey("forward:configuration:behaviour-id:%s:behaviour-ids", behaviourID) newBehaviourIDs, err := f.Storage().General().GetAllFromSet(behaviourIDsKey) if storage.IsNotFound(err) { // No configuration of behaviour IDs is stored. Thus we return an error. // Eventually some other lookup is able to find sufficient network payloads. return nil, maskAny(networkPayloadsNotFoundError) } else if err != nil { return nil, maskAny(err) } // Create a list of new network payloads. var newNetworkPayloads []objectspec.NetworkPayload for _, behaviourID := range newBehaviourIDs { // Prepare a new context for the new network payload. newCtx := ctx.Clone() newCtx.SetBehaviourID(behaviourID) // Create a new network payload. newNetworkPayloadConfig := networkpayload.DefaultConfig() newNetworkPayloadConfig.Args = networkPayload.GetArgs() newNetworkPayloadConfig.Context = newCtx newNetworkPayloadConfig.Destination = string(behaviourID) newNetworkPayloadConfig.Sources = []string{networkPayload.GetDestination()} newNetworkPayload, err := networkpayload.New(newNetworkPayloadConfig) if err != nil { return nil, maskAny(err) } newNetworkPayloads = append(newNetworkPayloads, newNetworkPayload) } return newNetworkPayloads, nil }
func (n *network) Calculate(CLG systemspec.CLG, networkPayload objectspec.NetworkPayload) (objectspec.NetworkPayload, error) { n.Log.WithTags(systemspec.Tags{C: nil, L: "D", O: n, V: 13}, "call Calculate") outputs, err := filterError(reflect.ValueOf(CLG.GetCalculate()).Call(networkPayload.GetCLGInput())) if err != nil { return nil, maskAny(err) } newNetworkPayloadConfig := networkpayload.DefaultConfig() newNetworkPayloadConfig.Args = outputs newNetworkPayloadConfig.Context = networkPayload.GetContext() newNetworkPayloadConfig.Destination = networkPayload.GetDestination() newNetworkPayloadConfig.Sources = networkPayload.GetSources() newNetworkPayload, err := networkpayload.New(newNetworkPayloadConfig) if err != nil { return nil, maskAny(err) } return newNetworkPayload, nil }
func (f *forwarder) News(CLG systemspec.CLG, networkPayload objectspec.NetworkPayload) ([]objectspec.NetworkPayload, error) { ctx := networkPayload.GetContext() // Decide how many new behaviour IDs should be created. This defines the // number of signals being forwarded to other CLGs. Here we want to make a // pseudo random decision. CreateMax takes a max paramater which is exclusive. // Therefore we increment the configuration for the maximum signals desired by // one, to reflect the maximum setting properly. maxSignals, err := f.Service().Random().CreateMax(f.GetMaxSignals() + 1) if err != nil { return nil, maskAny(err) } // Create the desired number of behaviour IDs. var newBehaviourIDs []string for i := 0; i < maxSignals; i++ { newBehaviourID, err := f.Service().ID().New() if err != nil { return nil, maskAny(err) } newBehaviourIDs = append(newBehaviourIDs, string(newBehaviourID)) } // TODO find a CLG name that can be connected to the current CLG for each new // behaviour ID and pair these combinations (network event tracker) // Store each new behaviour ID in the underlying storage. behaviourID, ok := ctx.GetBehaviourID() if !ok { return nil, maskAnyf(invalidBehaviourIDError, "must not be empty") } behaviourIDsKey := key.NewNetworkKey("forward:configuration:behaviour-id:%s:behaviour-ids", behaviourID) for _, behaviourID := range newBehaviourIDs { // TODO store asynchronuously err = f.Storage().General().PushToSet(behaviourIDsKey, behaviourID) if err != nil { return nil, maskAny(err) } } // Create a list of new network payloads. var newNetworkPayloads []objectspec.NetworkPayload for _, behaviourID := range newBehaviourIDs { // Prepare a new context for the new network payload. newCtx := ctx.Clone() newCtx.SetBehaviourID(behaviourID) // TODO set the paired CLG name to the new context // Create a new network payload. newNetworkPayloadConfig := networkpayload.DefaultConfig() newNetworkPayloadConfig.Args = networkPayload.GetArgs() newNetworkPayloadConfig.Context = newCtx newNetworkPayloadConfig.Destination = string(behaviourID) newNetworkPayloadConfig.Sources = []string{networkPayload.GetDestination()} newNetworkPayload, err := networkpayload.New(newNetworkPayloadConfig) if err != nil { return nil, maskAny(err) } newNetworkPayloads = append(newNetworkPayloads, newNetworkPayload) } return newNetworkPayloads, nil }
func (a *activator) Activate(CLG systemspec.CLG, networkPayload objectspec.NetworkPayload) (objectspec.NetworkPayload, error) { a.Log.WithTags(systemspec.Tags{C: nil, L: "D", O: a, V: 13}, "call Activate") // Fetch the queued network payloads. queue is a string of comma separated // JSON objects representing a specific network payload. behaviourID, ok := networkPayload.GetContext().GetBehaviourID() if !ok { return nil, maskAnyf(invalidBehaviourIDError, "must not be empty") } queueKey := key.NewNetworkKey("activate:queue:behaviour-id:%s:network-payload", behaviourID) s, err := a.Storage().General().Get(queueKey) if err != nil { return nil, maskAny(err) } queue, err := stringToQueue(s) if err != nil { return nil, maskAny(err) } // Merge the given network payload with the queue that we just fetched from // storage. We store the extended queue directly after merging it with the // given network payload to definitely track the received network payload, // even if something goes wrong and we need to return an error on the code // below. In case the current queue exeeds a certain amount of payloads, it is // unlikely that the queue is going to be helpful when growing any further. // Thus we cut the queue at some point beyond the interface capabilities of // the requested CLG. Note that it is possible to have multiple network // payloads sent by the same CLG. That might happen in case a specific CLG // wants to fulfil the interface of the requested CLG on its own, even it is // not able to do so with the output of a single calculation. queue = append(queue, networkPayload) queueBuffer := len(getInputTypes(CLG.GetCalculate())) + 1 if len(queue) > queueBuffer { queue = queue[1:] } err = a.persistQueue(queueKey, queue) if err != nil { return nil, maskAny(err) } // This is the list of lookup functions which is executed seuqentially. lookups := []func(CLG systemspec.CLG, queue []objectspec.NetworkPayload) (objectspec.NetworkPayload, error){ a.GetNetworkPayload, a.New, } // Execute one lookup after another. As soon as we find a network payload, we // return it. var newNetworkPayload objectspec.NetworkPayload for _, lookup := range lookups { newNetworkPayload, err = lookup(CLG, queue) if IsNetworkPayloadNotFound(err) { // There could no network payload be found by this lookup. Go on and try // the next one. continue } else if err != nil { return nil, maskAny(err) } // The current lookup was successful. We do not need to execute any further // lookup, but can go on with the network payload found. break } // Filter all network payloads from the queue that are merged into the new // network payload. var newQueue []objectspec.NetworkPayload for _, s := range newNetworkPayload.GetSources() { for _, np := range queue { // At this point there is only one source given. That is the CLG that // forwarded the current network payload to here. If this is not the case, // we return an error. sources := np.GetSources() if len(sources) != 1 { return nil, maskAnyf(invalidSourcesError, "there must be one source") } if s == sources[0] { // The current network payload is part of the merged network payload. // Thus we do not add it to the new queue. continue } newQueue = append(newQueue, np) } } // Update the modified queue in the underlying storage. err = a.persistQueue(queueKey, newQueue) if err != nil { return nil, maskAny(err) } // The current lookup was able to find a network payload. Thus we simply // return it. return newNetworkPayload, nil }