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); } }
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); }
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)); }
void Uplink_OnStanzaIQ(StanzaIQ Data) { TaskCompletionSource <StanzaIQ> Signal; if (!IQRequests.TryRemove(Data.ID, out Signal)) { return; } Signal.SetResult(Data); }
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); } }
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); }
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"); }
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); } }
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); } }
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); }
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); }
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); } }
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); } }