Ejemplo n.º 1
0
func (c *clg) calculate(ctx spec.Context) (string, error) {
	behaviourID, ok := ctx.GetBehaviourID()
	if !ok {
		return "", maskAnyf(invalidBehaviourIDError, "must not be empty")
	}

	behaviourIDKey := key.NewNetworkKey("behaviour-id:%s:separator", behaviourID)
	separator, err := c.Storage().General().Get(behaviourIDKey)
	if storage.IsNotFound(err) {
		randomKey, err := c.Storage().Feature().GetRandom()
		if err != nil {
			return "", maskAny(err)
		}

		// Make sure the fetched feature is valid based on its key structure. The
		// key itself already contains the feature. Knowing the key structure makes
		// it possible to simply parse the feature from the key fetched from the
		// feature storage. These features are stored by the split-features CLG.
		// Changes in the key structure there must be aligned with implementation
		// details here. The current key structure looks as follows.
		//
		//     feature:%s:positions
		//
		if len(randomKey) != 22 {
			return "", maskAnyf(invalidFeatureKeyError, "key '%s' must have length '22'", randomKey)
		}
		if !strings.HasPrefix(randomKey, "feature:") {
			return "", maskAnyf(invalidFeatureKeyError, "key '%s' prefix must be 'feature:'", randomKey)
		}
		if !strings.HasSuffix(randomKey, ":positions") {
			return "", maskAnyf(invalidFeatureKeyError, "key '%s' suffix must be ':positions'", randomKey)
		}

		// Create a new separator from the fetched random feature. Note that a
		// feature is considered 4 characters long and the random factory takes a
		// max parameter, which is exlusive.
		feature := randomKey[8:12]
		featureIndex, err := c.Service().Random().CreateMax(5)
		if err != nil {
			return "", maskAny(err)
		}
		separator = string(feature[featureIndex])

		// Store the newly created separator using the CLGs own behaviour ID. In case
		// this CLG is asked again to return its separator, it will lookup its
		// separator in the general storage.
		err = c.Storage().General().Set(behaviourIDKey, separator)
		if err != nil {
			return "", maskAny(err)
		}
	} else if err != nil {
		return "", maskAny(err)
	}

	return separator, nil
}
Ejemplo n.º 2
0
func (c *clg) forwardNetworkPayload(ctx spec.Context, informationSequence string) error {
	// Find the original information sequence using the information ID from the
	// context.
	informationID, ok := ctx.GetInformationID()
	if !ok {
		return maskAnyf(invalidInformationIDError, "must not be empty")
	}
	informationSequenceKey := key.NewNetworkKey("information-id:%s:information-sequence", informationID)
	informationSequence, err := c.Storage().General().Get(informationSequenceKey)
	if err != nil {
		return maskAny(err)
	}

	// Find the first behaviour ID using the CLG tree ID from the context. The
	// behaviour ID we are looking up here is the ID of the initial input CLG.
	clgTreeID, ok := ctx.GetCLGTreeID()
	if !ok {
		return maskAnyf(invalidCLGTreeIDError, "must not be empty")
	}
	firstBehaviourIDKey := key.NewNetworkKey("clg-tree-id:%s:first-behaviour-id", clgTreeID)
	inputBehaviourID, err := c.Storage().General().Get(firstBehaviourIDKey)
	if err != nil {
		return maskAny(err)
	}

	// Lookup the behaviour ID of the current output CLG. Below we are using this
	// to set the source of the new network payload accordingly.
	outputBehaviourID, ok := ctx.GetBehaviourID()
	if !ok {
		return maskAnyf(invalidBehaviourIDError, "must not be empty")
	}

	// Create a new contect using the given context and adapt the new context with
	// the information of the current scope.
	newCtx := ctx.Clone()
	newCtx.SetBehaviourID(inputBehaviourID)
	newCtx.SetCLGName("input")
	newCtx.SetCLGTreeID(clgTreeID)
	// We do not need to set the expectation because it never changes.
	// We do not need to set the session ID because it never changes.

	// Create a new network payload.
	newNetworkPayloadConfig := networkpayload.DefaultConfig()
	newNetworkPayloadConfig.Args = []reflect.Value{reflect.ValueOf(informationSequence)}
	newNetworkPayloadConfig.Context = newCtx
	newNetworkPayloadConfig.Destination = string(inputBehaviourID)
	newNetworkPayloadConfig.Sources = []string{string(outputBehaviourID)}
	newNetworkPayload, err := networkpayload.New(newNetworkPayloadConfig)
	if err != nil {
		return maskAny(err)
	}

	// Write the transformed network payload to the queue.
	networkPayloadKey := key.NewNetworkKey("events:network-payload")
	b, err := json.Marshal(newNetworkPayload)
	if err != nil {
		return maskAny(err)
	}
	err = c.Storage().General().PushToList(networkPayloadKey, string(b))
	if err != nil {
		return maskAny(err)
	}

	return nil
}