Example #1
0
        /// <summary>
        /// Given parsed untyped JSON in full compatible format, construct it into a typed daton
        /// </summary>
        public static Daton FromCompatibleWireFull(DataDictionary dbdef, JObject jroot)
        {
            var datonKey = DatonKey.Parse(jroot.Value <string>("key"));
            var datondef = dbdef.FindDef(datonKey);
            var daton    = Utils.ConstructDaton(datondef.Type, datondef);

            daton.Key     = datonKey;
            daton.Version = jroot.Value <string>("version");
            if (daton is Viewon viewon && jroot.Value <bool>("isComplete") == false)
            {
                viewon.IsCompleteLoad = false;
            }

            var mainRowsNode = jroot[CamelCasify(datondef.MainTableDef.Name)];

            if (mainRowsNode == null)
            {
                return(daton);
            }
            if (!(mainRowsNode is JArray mainRowsArray))
            {
                throw new Exception($"{datondef.MainTableDef.Name} node must be an array");
            }
            if (datondef.MultipleMainRows)
            {
                var targetListInfo = datondef.Type.GetField(datondef.MainTableDef.Name);
                if (targetListInfo == null)
                {
                    throw new Exception($"Expected {datondef.MainTableDef.Name} to be a member of {datondef.Type.Name}");
                }
                var targetList = Utils.CreateOrGetFieldValue <IList>(daton, targetListInfo) as IList;
                ReadCompatibleJsonRowArray(mainRowsArray, datondef.MainTableDef, (IList)targetList);
            }
            else
            {
                if (mainRowsArray.Count != 1)
                {
                    throw new Exception($"{datondef.MainTableDef.Name} node must have one element for this daton type");
                }
                ReadCompatibleJsonRow(mainRowsArray[0] as JObject, datondef.MainTableDef, daton);
            }

            daton.Recompute(datondef);
            return(daton);
        }
Example #2
0
        /// <summary>
        /// Get the list of daton keys with version numbers that were updated by other servers since the given time
        /// </summary>
        /// <param name="serverLifeNumber">the number for this server; updates from this server are excluded from the query</param>
        public static List <(DatonKey, string)> GetRecentUpdatesByOtherServers(DbConnection db, DateTime sinceUtc, int serverLifeNumber)
        {
            var ret = new List <(DatonKey, string)>();

            using (var cmd = db.CreateCommand())
            {
                cmd.CommandText = $"select DatonKey,DatonVersion from RetroLock where Touched>@t and UpdatedByServer<>@u";
                Utils.AddParameterWithValue(cmd, "t", sinceUtc);
                Utils.AddParameterWithValue(cmd, "u", serverLifeNumber);
                using (var rdr = cmd.ExecuteReader())
                {
                    while (rdr.Read())
                    {
                        var    key     = DatonKey.Parse(Utils.Read <string>(rdr, 0));
                        string version = Utils.Read <string>(rdr, 1);
                        ret.Add((key, version));
                    }
                }
            }
            return(ret);
        }
Example #3
0
        /// <summary>
        /// Given parsed untyped JSON in diff format, construct a PersistonDiff
        /// </summary>
        public static PersistonDiff FromDiff(DataDictionary dbdef, JObject jroot)
        {
            var datonKey = DatonKey.Parse(jroot.Value <string>("key"));
            var datondef = dbdef.FindDef(datonKey);
            var diff     = new PersistonDiff(datondef, datonKey, jroot.Value <string>("version"));

            ReadJsonDiffRowArray(jroot, datondef.MainTableDef, diff.MainTable);

            //existing single-main-row diffs might not include the primary key in the main row, so add it here
            if (!datondef.MultipleMainRows)
            {
                var mainDiffRow = diff.MainTable.First();
                if (!mainDiffRow.Columns.ContainsKey(datondef.MainTableDef.PrimaryKeyColName))
                {
                    var pkColdef = datondef.MainTableDef.FindCol(datondef.MainTableDef.PrimaryKeyColName);
                    var pk       = Utils.ChangeType(((PersistonKey)datonKey).PrimaryKey, pkColdef.CSType);
                    mainDiffRow.Columns[datondef.MainTableDef.PrimaryKeyColName] = pk;
                }
            }

            return(diff);
        }
Example #4
0
        private async Task HandleHttpMain(MainRequest req, IUser user, MainResponse resp)
        {
            //initialize
            if (req.Initialze != null)
            {
                resp.DataDictionary = Retrovert.DataDictionaryToWire(DataDictionary, user, LanguageMessages);
            }

            //load datons
            if (req.GetDatons != null)
            {
                var getResponses = new List <GetDatonResponse>();
                foreach (var drequest in req.GetDatons)
                {
                    var loadResult = await GetDaton(DatonKey.Parse(drequest.Key), user, forceCheckLatest : drequest.ForceLoad);

                    var getResponse = new GetDatonResponse
                    {
                        Errors = loadResult.Errors
                    };
                    if (loadResult.Daton != null)                                                                                      //null means it was not found by key, usually
                    {
                        bool doReturnToCaller = loadResult.Daton.Version == null || drequest.KnownVersion != loadResult.Daton.Version; //omit if client already has the current version
                        if (doReturnToCaller)
                        {
                            getResponse.CondensedDaton = new CondensedDatonResponse
                            {
                                CondensedDatonJson = Retrovert.ToWire(DataDictionary, loadResult.Daton, false)
                            };
                        }
                        if (drequest.DoSubscribe && loadResult.Daton is Persiston)
                        {
                            ClientPlex.ManageSubscribe(req.SessionKey, loadResult.Daton.Key, loadResult.Daton.Version, true);
                        }
                    }
                    else
                    {
                        getResponse.Key = drequest.Key; //only needed if daton is not returned to client
                    }
                    getResponses.Add(getResponse);
                }
                resp.GetDatons = getResponses.ToArray();
            }

            //save datons
            if (req.SaveDatons != null)
            {
                var diffs = new List <PersistonDiff>();
                foreach (var saveRequest in req.SaveDatons)
                {
                    var diff = Retrovert.FromDiff(DataDictionary, saveRequest);
                    diffs.Add(diff);
                }
                (bool success, var results) = await SaveDatons(req.SessionKey, user, diffs.ToArray());

                var saveResponses = new List <SavePersistonResponse>();
                foreach (var result in results)
                {
                    saveResponses.Add(new SavePersistonResponse
                    {
                        IsDeleted = result.IsDeleted,
                        IsSuccess = result.IsSuccess,
                        OldKey    = result.OldKey.ToString(),
                        NewKey    = result.NewKey?.ToString(),
                        Errors    = result.Errors
                    });
                }
                resp.SavedPersistons       = saveResponses.ToArray();
                resp.SavePersistonsSuccess = success;
            }

            //change datons state
            if (req.ManageDatons != null)
            {
                var manageResponses = new List <ManageDatonResponse>(req.ManageDatons.Length);
                foreach (var mrequest in req.ManageDatons)
                {
                    //what does the caller wants to change?
                    var  datonKey       = DatonKey.Parse(mrequest.Key);
                    bool wantsLock      = mrequest.SubscribeState == 2;
                    bool wantsSubscribe = mrequest.SubscribeState >= 1;

                    //handle change in subscription
                    //(Performance note: unsubscribe should happen before unlock so that the unlock-propogation can short circuit reloading. Ultimately
                    //if only one client is dealing with a daton and that client releases the lock and subscription, this server can forget about it
                    //immediately.)
                    bool isSubscribed = false;
                    if (datonKey is PersistonKey)
                    {
                        ClientPlex.ManageSubscribe(req.SessionKey, datonKey, mrequest.Version, wantsSubscribe);
                        isSubscribed = wantsSubscribe;
                    }

                    //handle change in lock
                    string lockErrorCode = "";
                    bool   hasLock       = false;
                    if (wantsLock)
                    {
                        if (string.IsNullOrEmpty(mrequest.Version))
                        {
                            throw new Exception("Version required to lock daton");
                        }
                        (hasLock, lockErrorCode) = LockManager.RequestLock(datonKey, mrequest.Version, req.SessionKey);
                    }
                    else
                    {
                        LockManager.ReleaseLock(datonKey, req.SessionKey);
                    }

                    manageResponses.Add(new ManageDatonResponse
                    {
                        ErrorCode      = lockErrorCode,
                        Key            = mrequest.Key,
                        SubscribeState = hasLock ? 2 : (isSubscribed ? 1 : 0)
                    });
                }
                resp.ManageDatons = manageResponses.ToArray();
            }

            //quit - free up locks and memory
            if (req.DoQuit)
            {
                ClientPlex.DeleteSession(req.SessionKey);
                LockManager.ReleaseLocksForSession(req.SessionKey);
            }
        }