Example #1
0
        void HandleVerifySubscription(StanzaIQ Request)
        {
            XElement SubscribeElement = Request.Payload.Elements().First();

            try
            {
                string localsid = SubscribeElement.Attribute("subscriptionid").Value;
                string sid      = GetSafeSubscriptionID(Request.From, localsid);
                bool   Verified = Subscribers.ContainsKey(sid);

                StanzaIQ Response = new StanzaIQ(StanzaIQ.StanzaIQType.Result);
                Response.ID = Request.ID;
                Response.To = Request.From;

                XElement VerifiedElement = new XElement(LWTSD.Namespace + "verified-subscription");
                VerifiedElement.SetAttributeValue("subscriptionid", localsid);
                VerifiedElement.SetAttributeValue("isactive", XmlConvert.ToString(Verified));
                Uplink.SendStanza(Response);
            }
            catch (System.Exception ex)
            {
                StanzaIQ ErrorResponse = new StanzaIQ(StanzaIQ.StanzaIQType.Error);
                ErrorResponse.ID = Request.ID;
                ErrorResponse.To = Request.From;
                XElement ErroReasonElement = new XElement(LWTSD.Namespace + "errorreason");
                ErroReasonElement.SetAttributeValue("reason", ErrorReason.InvalidData);
                ErroReasonElement.Value = ex.ToString();
                ErrorResponse.Payload.Add(ErroReasonElement);
                Uplink.SendStanza(ErrorResponse);
            }
        }
Example #2
0
        public async Task <SimplifiedSchema> GetSchema(int Page = 0, string AccessToken = null, List <ResourcePath> Resources = null)
        {
            const int MaxResources = 500;

            TaskCompletionSource <StanzaIQ> Signal = new TaskCompletionSource <StanzaIQ>();

            StanzaIQ Request = new StanzaIQ(StanzaIQ.StanzaIQType.Get);

            Request.To = DataSourceAddress;
            XElement Payload = new XElement(LWTSD.Namespace + "read-schema");

            Payload.SetAttributeValue("format", SchemaFormat.Simplified.GetSerializedValue());
            Payload.SetAttributeValue("startindex", Page * MaxResources);
            Payload.SetAttributeValue("maxresources", MaxResources);

            if (AccessToken != null)
            {
                XElement AToken = new XElement(LWTSD.Namespace + "accesstoken");
                AToken.SetAttributeValue("name", "urn:clayster:cdo:sessionid");
                AToken.Value = AccessToken;
                Payload.Add(AToken);
            }

            if (Resources != null)
            {
                foreach (var res in Resources)
                {
                    XElement Resource = new XElement(LWTSD.Namespace + "resource");
                    Resource.SetAttributeValue("path", res);
                    Payload.Add(Resource);
                }
            }

            Request.Payload.Add(Payload);
            IQRequests[Request.ID] = Signal;

            Uplink.SendStanza(Request);

            await Signal.Task;

            // Parse signal data

            if (Signal.Task.Result == null)
            {
                throw new Exception("Failed to get schema");
            }

            XElement ReturnedData = Signal.Task.Result.Payload.Element(LWTSD.Namespace + "simplified-schema");

            if (ReturnedData == null)
            {
                throw new Exception("Failed to get schema");
            }

            SimplifiedSchema RVal = new SimplifiedSchema(ReturnedData);

            return(RVal);
        }
Example #3
0
        public async Task <Tuple <string, DataPage> > SubscribeToData(SimplifiedSchema KnownSchema,
                                                                      List <ResourcePath> Resources,
                                                                      Action <Tuple <string, DataPage> > NewDataAction,
                                                                      Action <string> SubscriptionCancelled,
                                                                      string AccessToken = null)
        {
            string SubscriptionID = Guid.NewGuid().ToString();

            XElement Payload = new XElement(LWTSD.Namespace + "subscribe");

            Payload.SetAttributeValue("subscriptionid", SubscriptionID);

            foreach (ResourcePath res in Resources)
            {
                XElement Trigger = new XElement(LWTSD.Namespace + "trigger");
                Trigger.SetAttributeValue("onresource", res);
                Payload.Add(Trigger);
            }
            StanzaIQ Request = new StanzaIQ(StanzaIQ.StanzaIQType.Set);

            Request.To = DataSourceAddress;

            Subscription NewSubscription = new Subscription();

            NewSubscription.ID      = SubscriptionID;
            NewSubscription.NewData = NewDataAction;

            TaskCompletionSource <StanzaIQ> Signal = new TaskCompletionSource <StanzaIQ>();

            Request.Payload.Add(Payload);
            IQRequests[Request.ID] = Signal;

            Uplink.SendStanza(Request);

            await Signal.Task;

            if (Signal.Task.Result == null)
            {
                throw new Exception("Failed to subscribe: no data");
            }
            if (Signal.Task.Result.IQType != StanzaIQ.StanzaIQType.Result)
            {
                throw new Exception("Subscription failed");
            }


            DataPage Page = await ReadData(KnownSchema, Resources, AccessToken);

            NewSubscription.KnownSchema           = Page.Schema;
            NewSubscription.Resources             = Resources;
            NewSubscription.AccessToken           = AccessToken;
            NewSubscription.SubscriptionCancelled = SubscriptionCancelled;

            Subscriptions[NewSubscription.ID] = NewSubscription;

            return(new Tuple <string, DataPage>(SubscriptionID, Page));
        }
Example #4
0
        void Uplink_OnStanzaIQ(StanzaIQ Data)
        {
            TaskCompletionSource <StanzaIQ> Signal;

            if (!IQRequests.TryRemove(Data.ID, out Signal))
            {
                return;
            }
            Signal.SetResult(Data);
        }
Example #5
0
        void HandleWriteData(StanzaIQ Request)
        {
            XElement WriteDataElement = Request.Payload.Elements().First();

            try
            {
                List <ResourceAccess> LimitedAccess = GetAccessRights(Request.From, LWTSD.GetAccessToken(WriteDataElement));

                int NrWrittenValues = 0;
                foreach (XElement WriteElement in WriteDataElement.Elements(LWTSD.Namespace + "write"))
                {
                    ResourcePath Path = WriteElement.Attribute("resource-path").Value;

                    if (!ResourceAccess.AllowsWrite(LimitedAccess, Path))
                    {
                        throw new AccessViolation();
                    }

                    if (!Resources.ContainsKey(Path))
                    {
                        throw new InvalidOperationException("Path does not exist: " + Path); // todo: explicit type to make it possible to set correct error code
                    }
                    Resource Res = Resources[Path];
                    if (!Res.SupportsWrite)
                    {
                        throw new InvalidOperationException("Resource is not writeable: " + Path); // todo: explicit type to make it possible to set correct error code
                    }
                    Res.LoadFromWrite(WriteElement);
                    NrWrittenValues++;
                }

                if (NrWrittenValues == 0)
                {
                    throw new Exception("No values found");
                }

                StanzaIQ Response = new StanzaIQ(StanzaIQ.StanzaIQType.Result);
                Response.ID = Request.ID;
                Response.To = Request.From;
                Uplink.SendStanza(Response);
            }
            catch (System.Exception ex)
            {
                StanzaIQ ErrorResponse = new StanzaIQ(StanzaIQ.StanzaIQType.Error);
                ErrorResponse.ID = Request.ID;
                ErrorResponse.To = Request.From;
                XElement ErroReasonElement = new XElement(LWTSD.Namespace + "errorreason");
                ErroReasonElement.SetAttributeValue("reason", ErrorReason.InvalidData);
                ErroReasonElement.Value = ex.ToString();
                ErrorResponse.Payload.Add(ErroReasonElement);
                Uplink.SendStanza(ErrorResponse);
            }
        }
Example #6
0
        public async Task <bool> WriteData(DataPage Page, string AccessToken = null)
        {
            XElement Payload = new XElement(LWTSD.Namespace + "write-data");

            if (AccessToken != null)
            {
                XElement AToken = new XElement(LWTSD.Namespace + "accesstoken");
                AToken.SetAttributeValue("name", "urn:clayster:cdo:sessionid");
                AToken.Value = AccessToken;
                Payload.Add(AToken);
            }

            foreach (var res in Page.Data)
            {
                XElement write = new XElement(LWTSD.Namespace + "write");
                write.SetAttributeValue("resource-path", res.Path);
                write.SetAttributeValue("relativetimeout", "10");
                write.Value = res.GetWriteValue();
                Payload.Add(write);
            }

            StanzaIQ Request = new StanzaIQ(StanzaIQ.StanzaIQType.Set);

            Request.To = DataSourceAddress;
            TaskCompletionSource <StanzaIQ> Signal = new TaskCompletionSource <StanzaIQ>();

            Request.Payload.Add(Payload);
            IQRequests[Request.ID] = Signal;

            Uplink.SendStanza(Request);

            await Signal.Task;

            if (Signal.Task.Result == null)
            {
                throw new Exception("Failed to write data: result is null");
            }
            if (Signal.Task.Result.IQType == StanzaIQ.StanzaIQType.Result)
            {
                return(true);
            }

            return(false);
        }
Example #7
0
        void Uplink_OnStanzaIQ(StanzaIQ Data)
        {
            if (!Data.Payload.HasElements)
            {
                return;
            }

            XElement LWTSDElement = Data.Payload.Elements().First();

            if (LWTSDElement.Name.Namespace != LWTSD.Namespace)
            {
                return;
            }

            Console.WriteLine("Data source processing " +
                              LWTSDElement.Name.LocalName +
                              " from " + Data.From.ToString());
            switch (LWTSDElement.Name.LocalName)
            {
            case "read-schema":
                HandleReadSchema(Data);
                break;

            case "write-data":
                HandleWriteData(Data);
                InvalidateData(Data.From);
                break;

            case "read-data":
                HandleReadData(Data);
                break;

            case "subscribe":
                HandleSubscribe(Data);
                break;

            case "verify-subscription":
                HandleVerifySubscription(Data);
                break;
            }
            Console.WriteLine("Data source processing done");
        }
Example #8
0
        async Task <bool> SynchTime()
        {
            StanzaIQ   TimeRequest = new StanzaIQ(StanzaIQ.StanzaIQType.Get);
            XNamespace XEP202      = "urn:xmpp:time";
            XElement   Time        = new XElement(XEP202 + "time");

            TimeRequest.To = Orchestrator;
            TimeRequest.Payload.Add(Time);
            var Signal = new TaskCompletionSource <StanzaIQ>();

            IQRequests[TimeRequest.ID] = Signal;

            DateTime SentAt = DateTime.UtcNow;

            Uplink.SendStanza(TimeRequest);
            if (Signal.Task != await Task.WhenAny(Signal.Task, Task.Delay(10 * 1000)))
            {
                return(false);                // Timeout
            }

            if (Signal.Task.Result == null)
            {
                return(false);
            }

            try
            {
                string   UTCValue  = Signal.Task.Result.Payload.Element(XEP202 + "time").Element(XEP202 + "utc").Value;
                DateTime TimeValue = System.Xml.XmlConvert.ToDateTime(UTCValue, System.Xml.XmlDateTimeSerializationMode.Utc);
                TimeDifferenceSeconds = (TimeValue - SentAt).TotalSeconds;
                //Console.WriteLine("Time synchronized: {0} - {1} = {2} s", TimeValue, SentAt, TimeDifferenceSeconds);
                LastSynchronizedTime = DateTime.UtcNow;
                return(true);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine("Exception in SynchTime: " + ex.ToString());
                return(false);
            }
        }
Example #9
0
        void HandleReadSchema(StanzaIQ Request)
        {
            XElement ReadSchemaElement = Request.Payload.Elements().First();

            try
            {
                List <ResourceAccess> LimitedAccess = GetAccessRights(Request.From, LWTSD.GetAccessToken(ReadSchemaElement));

                SchemaFormat RequestedFormat =
                    SchemaFormatMethods.LoadFromString(ReadSchemaElement.Attribute("format").Value);
                if (RequestedFormat != SchemaFormat.Simplified)
                {
                    throw new NotSupportedException("Extended schema not supported");
                }

                int startindex = XmlConvert.ToInt32(ReadSchemaElement.Attribute("startindex").Value);
                int maxitems   = XmlConvert.ToInt32(ReadSchemaElement.Attribute("maxresources").Value);

                StanzaIQ Response = new StanzaIQ(StanzaIQ.StanzaIQType.Result);
                Response.ID = Request.ID;
                Response.To = Request.From;

                lock (Schema)
                {
                    Response.Payload.Add(Schema.GetSerializedElement(startindex, maxitems, LimitedAccess));
                }
                Uplink.SendStanza(Response);
            }
            catch (System.Exception ex)
            {
                StanzaIQ ErrorResponse = new StanzaIQ(StanzaIQ.StanzaIQType.Error);
                ErrorResponse.ID = Request.ID;
                ErrorResponse.To = Request.From;
                XElement ErroReasonElement = new XElement(LWTSD.Namespace + "errorreason");
                ErroReasonElement.SetAttributeValue("reason", ErrorReason.InvalidData);
                ErroReasonElement.Value = ex.ToString();
                ErrorResponse.Payload.Add(ErroReasonElement);
                Uplink.SendStanza(ErrorResponse);
            }
        }
Example #10
0
        void Uplink_OnStanzaIQ(StanzaIQ Data)
        {
            if (Data.From.GetBareJID() != DataSourceAddress.GetBareJID())
            {
                return;
            }

            Console.WriteLine("Controller received iq stanza");

            if (!IQRequests.ContainsKey(Data.ID))
            {
                return;
            }
            TaskCompletionSource <StanzaIQ> Signal;

            if (!IQRequests.TryRemove(Data.ID, out Signal))
            {
                return;
            }

            Signal.SetResult(Data);
        }
Example #11
0
        async Task <DataPage> InnerReadData(SimplifiedSchema KnownSchema,
                                            List <ResourcePath> Resources,
                                            int Page = 0,
                                            List <string> ResubscriptionIDs = null,
                                            string AccessToken = null)
        {
            if (KnownSchema == null)
            {
                KnownSchema = await GetSchema(0, AccessToken, Resources);
            }

            TaskCompletionSource <StanzaIQ> Signal = new TaskCompletionSource <StanzaIQ>();

            StanzaIQ Request = new StanzaIQ(StanzaIQ.StanzaIQType.Get);

            Request.To = DataSourceAddress;
            XElement Payload = new XElement(LWTSD.Namespace + "read-data");

            Payload.SetAttributeValue("maxpoints", DataPage.PointsPerPage.ToString());
            Payload.SetAttributeValue("startindex", (Page * DataPage.PointsPerPage).ToString());
            Payload.SetAttributeValue("relativetimeout", "10");

            if (AccessToken != null)
            {
                XElement AToken = new XElement(LWTSD.Namespace + "accesstoken");
                AToken.SetAttributeValue("name", "urn:clayster:cdo:sessionid");
                AToken.Value = AccessToken;
                Payload.Add(AToken);
            }

            if (ResubscriptionIDs != null)
            {
                foreach (string sid in ResubscriptionIDs)
                {
                    XElement el = new XElement(LWTSD.Namespace + "re-subscribe");
                    el.SetAttributeValue("subscriptionid", sid);
                    Payload.Add(el);
                }
            }

            foreach (ResourcePath Path in Resources)
            {
                XElement el = new XElement(LWTSD.Namespace + "read");
                el.SetAttributeValue("resource-path", Path);
                el.SetAttributeValue("maxpoints", "1");
                Payload.Add(el);
            }

            Request.Payload.Add(Payload);
            IQRequests[Request.ID] = Signal;

            Uplink.SendStanza(Request);

            await Signal.Task;

            // Parse signal data

            if (Signal.Task.Result == null)
            {
                throw new Exception("Failed to get data: no return value");
            }

            XElement ReturnedData = Signal.Task.Result.Payload.Element(LWTSD.Namespace + "data");

            if (ReturnedData == null)
            {
                throw new Exception("Failed to get data: invalid data: " + Signal.Task.Result.Payload.ToString());
            }


            // This is wrong for more than one or two iterations, Need to re-read the data. Recurse?
            DataPage RVal = new DataPage(ReturnedData, KnownSchema, Page);

            return(RVal);
        }
Example #12
0
        void HandleSubscribe(StanzaIQ Request)
        {
            XElement SubscribeElement = Request.Payload.Elements().First();

            try
            {
                string AccessToken = LWTSD.GetAccessToken(SubscribeElement);
                List <ResourceAccess> LimitedAccess = GetAccessRights(Request.From, AccessToken);

                Subscriber Subscription = new Subscriber();
                Subscription.SubscriptionID    = SubscribeElement.Attribute("subscriptionid").Value;
                Subscription.SubscriberAddress = Request.From;
                Subscription.AccessToken       = AccessToken;

                foreach (XElement WriteElement in SubscribeElement.Elements(LWTSD.Namespace + "trigger"))
                {
                    ResourcePath Path = WriteElement.Attribute("onresource").Value;

                    if (!ResourceAccess.AllowsRead(LimitedAccess, Path))
                    {
                        throw new AccessViolation();
                    }

                    if (!Resources.ContainsKey(Path))
                    {
                        throw new InvalidOperationException("Path does not exist: " + Path);                         // todo: explicit type to make it possible to set correct error code
                    }
                    Resource Res = Resources[Path];
                    if (!Res.SupportsRead)
                    {
                        throw new InvalidOperationException("Resource is not readable: " + Path);                         // todo: explicit type to make it possible to set correct error code
                    }
                    ResourceSubscription Trigger = new ResourceSubscription()
                    {
                        Path = Path
                    };

                    Subscription.Triggers.Add(Trigger);
                }

                if (Subscription.Triggers.Count == 0)
                {
                    throw new InvalidOperationException("No triggers");
                }

                Subscribers[GetSafeSubscriptionID(Request.From, Subscription.SubscriptionID)] = Subscription;

                StanzaIQ Response = new StanzaIQ(StanzaIQ.StanzaIQType.Result);
                Response.ID = Request.ID;
                Response.To = Request.From;
                Uplink.SendStanza(Response);
            }
            catch (System.Exception ex)
            {
                StanzaIQ ErrorResponse = new StanzaIQ(StanzaIQ.StanzaIQType.Error);
                ErrorResponse.ID = Request.ID;
                ErrorResponse.To = Request.From;
                XElement ErroReasonElement = new XElement(LWTSD.Namespace + "errorreason");
                ErroReasonElement.SetAttributeValue("reason", ErrorReason.InvalidData);
                ErroReasonElement.Value = ex.ToString();
                ErrorResponse.Payload.Add(ErroReasonElement);
                Uplink.SendStanza(ErrorResponse);
            }
        }
Example #13
0
        void HandleReadData(StanzaIQ Request)
        {
            XElement ReadDataElement = Request.Payload.Elements().First();

            try
            {
                List <ResourceAccess> LimitedAccess = GetAccessRights(Request.From, LWTSD.GetAccessToken(ReadDataElement));

                int       maxpoints   = XmlConvert.ToInt32(ReadDataElement.Attribute("maxpoints").Value);
                int       startindex  = XmlConvert.ToInt32(ReadDataElement.Attribute("startindex").Value);
                SortOrder OrderByTime = SortOrder.None;
                if (ReadDataElement.Attribute("orderedbytime") != null)
                {
                    OrderByTime = SortOrderMethods.LoadFromString(ReadDataElement.Attribute("orderedbytime").Value);
                }

                StanzaIQ Response = new StanzaIQ(StanzaIQ.StanzaIQType.Result);
                Response.ID = Request.ID;
                Response.To = Request.From;

                XElement DataElement = new XElement(LWTSD.Namespace + "data");

                List <Resource> MatchingResources = new List <Resource>();

                foreach (XElement ReadElement in ReadDataElement.Elements(LWTSD.Namespace + "read"))
                {
                    if (ReadElement.Attribute("maxpoints") != null)
                    {
                        if (XmlConvert.ToInt32(ReadElement.Attribute("maxpoints").Value) < 1)
                        {
                            throw new InvalidOperationException("Maxpoints < 0 in read");
                        }
                    }
                    if (ReadElement.Attribute("startindex") != null)
                    {
                        int localstartindex = XmlConvert.ToInt32(ReadElement.Attribute("startindex").Value);
                        if (localstartindex < 1)
                        {
                            throw new InvalidOperationException("startindex < 0 in read");
                        }
                        if (localstartindex > 1)
                        {
                            continue; // We only have one point / resource
                        }
                    }

                    ResourcePath Path = ReadElement.Attribute("resource-path").Value;

                    if (!ResourceAccess.AllowsRead(LimitedAccess, Path))
                    {
                        throw new AccessViolation();
                    }

                    if (!Resources.ContainsKey(Path))
                    {
                        // Todo: Explicit exception to set proper error code
                        throw new Exception("Path does not exist: " + Path);
                    }

                    Resource Res = Resources[Path];
                    if (!Res.SupportsRead)
                    {
                        throw new InvalidOperationException("Resource does not support read: " + Path);
                    }

                    MatchingResources.Add(Res);
                }

                lock (Schema)
                {
                    int Index          = 0;
                    int ReturnedPoints = 0;

                    foreach (Resource Res in MatchingResources)
                    {
                        if (Index < startindex)
                        {
                            Index++;
                            continue;
                        }
                        if ((Index - startindex) >= maxpoints)
                        {
                            Index++;
                            break;
                        }

                        Index++;
                        ReturnedPoints++;

                        XElement ResourceElement = new XElement(LWTSD.Namespace + "resource");
                        ResourceElement.SetAttributeValue("path", Res.Path);
                        ResourceElement.SetAttributeValue("returnedpoints", "1");
                        ResourceElement.SetAttributeValue("totalpoints", "1");
                        XElement PointElement = Res.GetPoint();
                        ResourceElement.Add(PointElement);

                        DataElement.Add(ResourceElement);
                    }

                    DataElement.SetAttributeValue("schemaversion", Schema.GetVersion());
                    DataElement.SetAttributeValue("returnedpoints", XmlConvert.ToString(ReturnedPoints));
                    DataElement.SetAttributeValue("totalpoints", XmlConvert.ToString(MatchingResources.Count));
                }

                foreach (XElement ReSubscribeElement in ReadDataElement.Elements(LWTSD.Namespace + "re-subscribe"))
                {
                    string localsid = ReSubscribeElement.Attribute("subscriptionid").Value;
                    string sid      = GetSafeSubscriptionID(Request.From, localsid);

                    if (!Subscribers.ContainsKey(sid))
                    {
                        throw new InvalidOperationException("Subscription ID does not exist: " + localsid);
                    }

                    Subscriber Subscription = Subscribers[sid];
                    Subscription.LastResubscribed = DateTime.UtcNow;
                }

                Response.Payload.Add(DataElement);
                Uplink.SendStanza(Response);
            }
            catch (System.Exception ex)
            {
                StanzaIQ ErrorResponse = new StanzaIQ(StanzaIQ.StanzaIQType.Error);
                ErrorResponse.ID = Request.ID;
                ErrorResponse.To = Request.From;
                XElement ErroReasonElement = new XElement(LWTSD.Namespace + "errorreason");
                ErroReasonElement.SetAttributeValue("reason", ErrorReason.InvalidData);
                ErroReasonElement.Value = ex.ToString();
                ErrorResponse.Payload.Add(ErroReasonElement);
                Uplink.SendStanza(ErrorResponse);
            }
        }