Example #1
0
        public DataService(IModelSerializer serializer, FSO.Content.Content content)
        {
            this.Serializer     = serializer;
            this.DataDefinition = content.DataDefinition;

            //Build Struct => Field[] maps for quicker serialization
            foreach (var derived in DataDefinition.DerivedStructs)
            {
                var type = MaskedStructUtils.FromID(derived.ID);
                List <StructField> fields = new List <StructField>();
                var parent = DataDefinition.Structs.First(x => x.ID == derived.Parent);

                foreach (var field in parent.Fields)
                {
                    var mask = derived.FieldMasks.FirstOrDefault(x => x.ID == field.ID);
                    if (mask == null)
                    {
                        continue;
                    }

                    /*
                     * var action = DerivedStructFieldMaskType.KEEP;
                     * if (mask != null){
                     *  action = mask.Type;
                     * }
                     * if (action == DerivedStructFieldMaskType.REMOVE){
                     *  //These seems wrong, ServerMyAvatar and MyAvatar both exclude bookmarks by this logic
                     *  //continue;
                     * }
                     */
                    fields.Add(field);
                }
                MaskedStructToActualFields.Add(type, fields.ToArray());
            }

            foreach (var _struct in DataDefinition.Structs)
            {
                StructToActualFields.Add(_struct.ID, _struct.Fields.ToArray());
            }

            var assembly = Assembly.GetAssembly(typeof(DataService));

            foreach (Type type in assembly.GetTypes())
            {
                System.Attribute[] attributes = System.Attribute.GetCustomAttributes(type);

                foreach (Attribute attribute in attributes)
                {
                    if (attribute is DataServiceModel)
                    {
                        var _struct = DataDefinition.GetStruct(type.Name);
                        if (_struct != null)
                        {
                            ModelTypeById.Add(_struct.ID, type);
                            ModelIdByType.Add(type, _struct.ID);
                        }
                    }
                }
            }
        }
Example #2
0
        public async void ApplyUpdate(cTSOTopicUpdateMessage update, ISecurityContext context)
        {
            try
            {
                var partialDotPath = new uint[update.DotPath.Length - 1];
                Array.Copy(update.DotPath, partialDotPath, partialDotPath.Length);
                var path = await ResolveDotPath(partialDotPath);

                var target = path.GetValue();
                if (target.Value == null)
                {
                    throw new Exception("Cannot set property on null value");
                }

                //Apply the change!
                var targetType = target.Value.GetType();
                var finalPath  = update.DotPath[update.DotPath.Length - 1];
                var value      = GetUpdateValue(update.Value);

                var provider = GetProvider(path.GetProvider());
                var entity   = path.GetEntity();

                if (IsList(targetType))
                {
                    //Array, we expect the final path component to be an array index
                    var arr         = (IList)target.Value;
                    var parent      = path.GetParent();
                    var objectField = parent.Value.GetType().GetProperty(target.Name);
                    if (finalPath < arr.Count)
                    {
                        //Update existing or remove on null (at index)
                        if (IsNull(value))
                        {
                            var removeItem = ((IList)target.Value)[(int)finalPath];
                            provider.DemandMutation(entity.Value, MutationType.ARRAY_REMOVE_ITEM, path.GetKeyPath(), removeItem, context);
                            objectField.SetValue(parent.Value, GetGenericMethod(targetType, "RemoveAt").Invoke(target.Value, new object[] { (int)finalPath }));

                            //TODO: make this async?
                            if (target.Persist)
                            {
                                provider.PersistMutation(entity.Value, MutationType.ARRAY_REMOVE_ITEM, path.GetKeyPath(), removeItem);
                            }
                        }
                        else
                        {
                            provider.DemandMutation(entity.Value, MutationType.ARRAY_SET_ITEM, path.GetKeyPath(), value, context);

                            objectField.SetValue(parent.Value, GetGenericMethod(targetType, "SetItem").Invoke(target.Value, new object[] { (int)finalPath, value }));
                            //arr[(int)finalPath] = value;

                            //TODO: make this async?
                            if (target.Persist)
                            {
                                provider.PersistMutation(entity.Value, MutationType.ARRAY_SET_ITEM, path.GetKeyPath(), value);
                            }
                        }
                    }
                    else if (finalPath >= arr.Count)
                    {
                        //Insert
                        provider.DemandMutation(entity.Value, MutationType.ARRAY_SET_ITEM, path.GetKeyPath(), value, context);

                        objectField.SetValue(parent.Value, GetGenericMethod(targetType, "Add").Invoke(target.Value, new object[] { value }));
                        //arr.Add(value);

                        if (target.Persist)
                        {
                            provider.PersistMutation(entity.Value, MutationType.ARRAY_SET_ITEM, path.GetKeyPath(), value);
                        }
                    }
                }
                else
                {
                    //We expect a field value
                    if (target.TypeId == 0)
                    {
                        throw new Exception("Trying to set field on unknown type");
                    }

                    var _struct = DataDefinition.GetStruct(target.TypeId);
                    var field   = _struct.Fields.FirstOrDefault(x => x.ID == finalPath);
                    if (field == null)
                    {
                        throw new Exception("Unknown field in dot path");
                    }

                    var objectField = target.Value.GetType().GetProperty(field.Name);
                    if (objectField == null)
                    {
                        throw new Exception("Unknown field in model: " + objectField.Name);
                    }

                    //If the value is null (0) and the field has a decoration of NullValueIndicatesDeletion
                    //Delete the value instead of setting it
                    var nullDelete = objectField.GetCustomAttribute <Key>();
                    if (nullDelete != null && IsNull(value))
                    {
                        var parent = path.GetParent();
                        if (IsList(parent.Value))
                        {
                            var listParent = path.Path[path.Path.Length - 3];
                            var lpField    = listParent.Value.GetType().GetProperty(parent.Name);

                            provider.DemandMutation(entity.Value, MutationType.ARRAY_REMOVE_ITEM, path.GetKeyPath(1), target.Value, context);
                            lpField.SetValue(listParent.Value, GetGenericMethod(parent.Value.GetType(), "Remove", new Type[] { parent.Value.GetType().GenericTypeArguments[0] })
                                             .Invoke(parent.Value, new object[] { target.Value }));
                            //((IList)parent.Value).Remove(target.Value);

                            if (parent.Persist)
                            {
                                provider.PersistMutation(entity.Value, MutationType.ARRAY_REMOVE_ITEM, path.GetKeyPath(1), target.Value);
                            }
                        }
                        else
                        {
                            //TODO
                        }
                    }
                    else
                    {
                        var persist       = objectField.GetCustomAttribute <Persist>();
                        var clientSourced = (target.Value as AbstractModel)?.ClientSourced ?? false;
                        //if the client is internally managing this value, do not update it.
                        if (!clientSourced || objectField.GetCustomAttribute <ClientSourced>() == null)
                        {
                            provider.DemandMutation(entity.Value, MutationType.SET_FIELD_VALUE, path.GetKeyPath(objectField.Name), value, context);
                            objectField.SetValue(target.Value, value);

                            if (persist != null)
                            {
                                provider.PersistMutation(entity.Value, MutationType.SET_FIELD_VALUE, path.GetKeyPath(objectField.Name), value);
                            }
                        }
                    }
                }
            } catch (Exception e)
            {
                if (e is SecurityException)
                {
                    LOG.Error("Unauthorised data service update:" + e.Message);
                }
                else
                {
                    LOG.Error(e, "Data service update failed.");
                }
            }
        }