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); } }
public void InvalidateData(JID ExcludeJID) { List <string> SubscriptionsToRemove = new List <string>(); foreach (string key in Subscribers.Keys) { Subscriber s = Subscribers[key]; try { if (ExcludeJID != null) { if (s.SubscriberAddress == ExcludeJID) { continue; } } if (s.LastInvalidated > s.LastResubscribed) { continue; } List <ResourceAccess> LimitedAccess = GetAccessRights(s.SubscriberAddress, s.AccessToken); bool Invalidate = false; foreach (ResourceSubscription trigger in s.Triggers) { if (!ResourceAccess.AllowsRead(LimitedAccess, trigger.Path)) { throw new AccessViolation(); } Resource res = Resources[trigger.Path]; if (res.ModifiedAt > s.LastInvalidated) { Invalidate = true; break; } } if (!Invalidate) { continue; } // Invalidate StanzaMessage InvalidateMessage = new StanzaMessage(); InvalidateMessage.MessageType = StanzaMessage.StanzaMessageType.Normal; InvalidateMessage.To = s.SubscriberAddress; s.LastInvalidated = DateTime.UtcNow; XElement SubscriptionTriggeredElement = new XElement(LWTSD.Namespace + "subscription-triggered"); SubscriptionTriggeredElement.SetAttributeValue("subscriptionid", s.SubscriptionID); InvalidateMessage.Payload.Add(SubscriptionTriggeredElement); Uplink.SendStanza(InvalidateMessage); } catch (AccessViolation Violation) { SubscriptionsToRemove.Add(key); } } foreach (string ToRemove in SubscriptionsToRemove) { Subscriber Temp; Subscribers.TryRemove(ToRemove, out Temp); } }
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); } }