예제 #1
0
파일: calculate.go 프로젝트: xh3b4sd/anna
// calculate fetches the information ID associated with the given information
// sequence. In case the information sequence is not found within the underlying
// storage, a new information ID is generated and used to store the given
// information sequence. In any case the information ID is added to the given
// context.
func (c *clg) calculate(ctx spec.Context, informationSequence string) error {
	informationIDKey := key.NewNetworkKey("information-sequence:%s:information-id", informationSequence)
	informationID, err := c.Storage().General().Get(informationIDKey)
	if storage.IsNotFound(err) {
		// The given information sequence was never seen before. Thus we register it
		// now with its own very unique information ID.
		newID, err := c.Service().ID().New()
		if err != nil {
			return maskAny(err)
		}
		informationID = string(newID)

		err = c.Storage().General().Set(informationIDKey, informationID)
		if err != nil {
			return maskAny(err)
		}

		informationSequenceKey := key.NewNetworkKey("information-id:%s:information-sequence", informationID)
		err = c.Storage().General().Set(informationSequenceKey, informationSequence)
		if err != nil {
			return maskAny(err)
		}
	} else if err != nil {
		return maskAny(err)
	}

	ctx.SetInformationID(informationID)

	return nil
}
예제 #2
0
파일: calculate.go 프로젝트: xh3b4sd/anna
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
}
예제 #3
0
파일: forwarder.go 프로젝트: xh3b4sd/anna
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
}
예제 #4
0
파일: calculate.go 프로젝트: xh3b4sd/anna
// TODO there is nothing that reads pairs
func (c *clg) calculate(ctx spec.Context) error {
	// The counter keeps track of the work already being done. We only increment
	// the counter in case we were not able to do our job. As soon as some
	// threshold is reached, we stop trying.
	var counter int

	for {
		// Fetch two random features from the feature storage. This is done by
		// fetching random keys. The keys itself already contain the features. Knowing
		// the key structure makes it possible to simply parse the features from the
		// keys 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
		//
		key1, err := c.Storage().Feature().GetRandom()
		if err != nil {
			return maskAny(err)
		}
		key2, err := c.Storage().Feature().GetRandom()
		if err != nil {
			return maskAny(err)
		}

		// Validate the fetched keys.
		for _, k := range []string{key1, key2} {
			if len(k) != 22 {
				return maskAnyf(invalidFeatureKeyError, "key '%s' must have length '22'", k)
			}
			if !strings.HasPrefix(key1, "feature:") {
				return maskAnyf(invalidFeatureKeyError, "key '%s' prefix must be 'feature:'", k)
			}
			if !strings.HasSuffix(key1, ":positions") {
				return maskAnyf(invalidFeatureKeyError, "key '%s' suffix must be ':positions'", k)
			}
		}

		// Combine the fetched keys to a new pair.
		pair := key1[8:12] + key2[8:12]

		// Write the new pair into the general storage.
		pairIDKey := key.NewNetworkKey("pair:syntactic:feature:%s:pair-id", pair)
		_, err = c.Storage().General().Get(pairIDKey)
		if storage.IsNotFound(err) {
			// The created pair was not found within the feature storage. That means
			// we created a new one which we can store. Once we stored the new pair,
			// we break the outer loop to be done.
			newID, err := c.Service().ID().New()
			if err != nil {
				return maskAny(err)
			}
			pairID := string(newID)

			err = c.Storage().General().Set(pairIDKey, pairID)
			if err != nil {
				return maskAny(err)
			}

			break
		}

		if counter >= 3 {
			// We tried to create a new pair 3 times, but it looks like there is not
			// enough data. That is why the created pair was found all the time. It
			// looks like we cannot create any new pair and stop doing anything here.
			break
		}

		counter++
	}

	return nil
}
예제 #5
0
파일: activator.go 프로젝트: xh3b4sd/anna
func (a *activator) GetNetworkPayload(CLG systemspec.CLG, queue []objectspec.NetworkPayload) (objectspec.NetworkPayload, error) {
	// Fetch the combination of successful behaviour IDs which are known to be
	// useful for the activation of the requested CLG. The network payloads sent
	// by the CLGs being fetched here are known to be useful because they have
	// already been helpful for the execution of the current CLG tree.
	behaviourID, ok := queue[0].GetContext().GetBehaviourID()
	if !ok {
		return nil, maskAnyf(invalidBehaviourIDError, "must not be empty")
	}
	behaviourIDsKey := key.NewNetworkKey("activate:configuration:behaviour-id:%s:behaviour-ids", behaviourID)
	s, err := a.Storage().General().Get(behaviourIDsKey)
	if storage.IsNotFound(err) {
		// No successful combination of behaviour IDs is stored. Thus we return an
		// error. Eventually some other lookup is able to find a sufficient network
		// payload.
		return nil, maskAny(networkPayloadNotFoundError)
	} else if err != nil {
		return nil, maskAny(err)
	}
	behaviourIDs := strings.Split(s, ",")
	if len(behaviourIDs) == 0 {
		// No activation configuration of the requested CLG is stored. Thus we
		// return an error. Eventually some other lookup is able to find a
		// sufficient network payload.
		return nil, maskAny(networkPayloadNotFoundError)
	}

	// Check if there is a queued network payload for each behaviour ID we found in the
	// storage. Here it is important to obtain the order of the behaviour IDs
	// stored as connections. They represent the input interface of the requested
	// CLG. Thus there must not be any variation applied to the lookup here,
	// because we need the lookup to be reproducible.
	var matches []objectspec.NetworkPayload
	for _, behaviourID := range behaviourIDs {
		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 behaviourID == string(sources[0]) {
				// The current behaviour ID belongs to the current network payload. We
				// add the matching network payload to our list and go on to find the
				// network payload belonging to the next behabiour ID.
				matches = append(matches, np)
				break
			}
		}
	}
	if len(behaviourIDs) != len(matches) {
		// No match using the stored configuration associated with the requested CLG
		// can be found. Thus we return an error. Eventually some other lookup is
		// able to find a sufficient network payload.
		return nil, maskAny(networkPayloadNotFoundError)
	}

	// The received network payloads are able to satisfy the interface of the
	// requested CLG. We merge the matching network payloads together and return
	// the result.
	newNetworkPayload, err := mergeNetworkPayloads(matches)
	if err != nil {
		return nil, maskAny(err)
	}

	return newNetworkPayload, nil
}