Ejemplo n.º 1
0
        private cTSOTopicUpdateMessage SerializeUpdateField(object value, uint[] path)
        {
            try
            {
                var clsid = Serializer.GetClsid(value);
                if (!clsid.HasValue)
                {
                    throw new Exception("Unable to serialize value with type: " + value.GetType());
                }

                var update = new cTSOTopicUpdateMessage();
                update.DotPath = path;
                update.Value   = value;
                return(update);
            }
            catch (Exception ex)
            {
                LOG.Error(ex);
                throw ex;
            }
        }
Ejemplo n.º 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.");
                }
            }
        }