public void Dispatch <T>(DispatcherEvent key, T arg) { List <object> events = null; if (m_Dispatcher.TryGetValue(key, out events)) { object e = null; // for (int i = events.Count - 1; i >= 0; i--) for (int i = 0; i < events.Count; i++) { if (events.Count > i) // for events.Clear() { e = events[i]; if (e is System.Action <T> ) { ((System.Action <T>)e)(arg); } else if (e is System.Action <object> ) { ((System.Action <object>)e)(arg); } } } } }
public void RemoveListener(DispatcherEvent key, System.Action <object> action) { List <object> events = null; if (m_Dispatcher.TryGetValue(key, out events)) { events.Remove(action); } }
public void RemoveListenerByKey(DispatcherEvent key) { List <object> events = null; if (m_Dispatcher.TryGetValue(key, out events)) { events.Clear(); } }
public void AddListener <T>(DispatcherEvent key, System.Action <T> action) { List <object> events = null; if (!m_Dispatcher.TryGetValue(key, out events)) { events = new List <object>();//new List<TriggerEvent>(); m_Dispatcher.Add(key, events); } events.Add(action); }
public void Dispatch <T>(DispatcherEvent key, T arg) { List <object> events = null; if (m_Dispatcher.TryGetValue(key, out events)) { object e = null; for (int i = events.Count - 1; i >= 0; i--) { e = events[i]; if (e is System.Action <T> ) { ((System.Action <T>)e)(arg); } } } }
public void Dispatcher(DispatcherEvent key, object arg) { List <object> events = null; if (m_Dispatcher.TryGetValue(key, out events)) { object e = null; for (int i = events.Count - 1; i >= 0; i--) //倒着执行防止删除后少执行一次bug { e = events[i]; if (e is System.Action <object> ) { ((System.Action <object>)e)(arg); } } } }
internal Yield PublishEvent(DreamContext context, DreamMessage request, Result <DreamMessage> response) { DispatcherEvent ev; try { ev = new DispatcherEvent(request); _log.DebugFormat("{0} received event '{1}'", this.Self.Uri, ev.Id); if (ev.Channel.Scheme == "pubsub") { response.Return(DreamMessage.Forbidden("events published into this service cannot be of scheme 'pubsub'")); yield break; } _dispatcher.Dispatch(ev); response.Return(DreamMessage.Ok(ev.GetEventEnvelope())); } catch (Exception e) { response.Return(DreamMessage.BadRequest(e.Message)); } yield break; }
public void AddListener(DispatcherEvent key, System.Action <object> action) { AddListener <object>(key, action); }
protected override Yield GetListenersByChannelResourceMatch(DispatcherEvent ev, Result <Dictionary <XUri, List <PubSubSubscription> > > result) { if (!ev.Channel.Segments[1].EqualsInvariantIgnoreCase("pages")) { // not a page DispatcherEvent or a page delete DispatcherEvent, use default matcher Result <Dictionary <XUri, List <PubSubSubscription> > > baseResult; yield return(baseResult = Coroutine.Invoke(base.GetListenersByChannelResourceMatch, ev, new Result <Dictionary <XUri, List <PubSubSubscription> > >())); result.Return(baseResult); yield break; } var matches = new List <PubSubSubscription>(); if (ev.Channel.Segments.Length <= 2 || !ev.Channel.Segments[2].EqualsInvariantIgnoreCase("delete")) { // dispatch to all PubSubSubscriptions that listen for this DispatcherEvent and its contents XDoc evDoc = ev.AsDocument(); uint? pageid = evDoc["pageid"].AsUInt; string wikiId = evDoc["@wikiid"].AsText; bool first = true; _log.DebugFormat("trying dispatch based on channel & page PubSubSubscriptions for page '{0}' from wiki '{1}'", pageid, wikiId); // fetch parent page id's for this page so that we can resolve infinite depth PubSubSubscriptions Result <DreamMessage> pageHierarchyResult; yield return(pageHierarchyResult = _deki.At("pages", pageid.ToString()).WithHeader("X-Deki-Site", "id=" + wikiId).GetAsync()); DreamMessage pageHierarchy = pageHierarchyResult.Value; if (pageHierarchy.IsSuccessful) { XDoc pageDoc = pageHierarchy.ToDocument(); while (pageid.HasValue) { List <Tuplet <PubSubSubscription, bool> > subs; _subscriptionsByPage.TryGetValue(pageid.Value, out subs); if (subs != null) { // only the first pageId (the one from the event) triggers on non-infinite depth subs foreach (var sub in subs) { if ((sub.Item2 || first) && !matches.Contains(sub.Item1)) { matches.Add(sub.Item1); } } } // get parent id and then set pageDoc to the parent's subdoc, so we can descend the ancesstor tree further pageid = pageDoc["page.parent/@id"].AsUInt; pageDoc = pageDoc["page.parent"]; first = false; } } else { _log.WarnFormat("unable to retrieve page doc for page '{0}': {1}", pageid, pageHierarchy.Status); } } ICollection <PubSubSubscription> listeningSubs; lock (_channelMap) { // get all the PubSubSubscriptions that are wild card matches (which is basically those that didn't // have any resources in their PubSubSubscription) and add them to the above matches foreach (var sub in _resourceMap.GetMatches(new XUri("http://dummy/dummy"))) { if (!matches.Contains(sub)) { matches.Add(sub); } } listeningSubs = _channelMap.GetMatches(ev.Channel, matches); } var listeners = new Dictionary <XUri, List <PubSubSubscription> >(); foreach (var sub in listeningSubs) { List <PubSubSubscription> subs; if (!listeners.TryGetValue(sub.Destination, out subs)) { subs = new List <PubSubSubscription>(); listeners.Add(sub.Destination, subs); subs.Add(sub); } else if (!subs.Contains(sub)) { subs.Add(sub); } } result.Return(listeners); yield break; }
public static void DispatchInt(this GlobalDispatcher self, DispatcherEvent key, int arg) { self.Dispatch <int>(key, arg); }
public static void RemoveListenerInt(this GlobalDispatcher self, DispatcherEvent key, System.Action <int> action) { self.RemoveListener <int>(key, action); }
public static void DispatchBool(this GlobalDispatcher self, DispatcherEvent key, bool arg) { self.Dispatch <bool>(key, arg); }
public void InstanceKey_authtoken_gets_verified_against_deki() { var mockDeki = new XUri("http://mock/deki"); var dispatcherUri = new XUri("http://mock/dispatcher"); var authorizedRecipient = new XUri("http://mock/authorized"); var dispatcher = new DekiDispatcher( new DispatcherConfig { ServiceUri = dispatcherUri, ServiceAccessCookie = new DreamCookie("service-key", "foo", dispatcherUri), ServiceConfig = new XDoc("config").Elem("uri.deki", mockDeki).Elem("authtoken", "abc") }, _mockRepository.Object ); var sub = new XDoc("subscription-set") .Elem("uri.owner", authorizedRecipient) .Start("subscription") .Attr("id", "1") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("authtoken", "def").Elem("uri", authorizedRecipient).End() .End(); _log.DebugFormat("registering sub set"); dispatcher.RegisterSet("abc", sub, "def"); Assert.IsTrue(Wait.For( () => dispatcher.CombinedSet.Subscriptions .Where(s => s.Channels.Where(c => c.ToString() == "event://default/deki/pages/*").Any() && !s.Resources.Any() ).Any(), 10.Seconds())); MockPlug.Setup(mockDeki) .Verb("GET") .At("site", "settings") .With("apikey", "abc") .WithHeader("X-Deki-Site", "id=default") .Returns(new XDoc("config").Start("security").Elem("api-key", "def").End()) .ExpectCalls(Times.Once()); MockPlug.Setup(authorizedRecipient) .Verb("POST") .WithMessage(r => { if (!r.HasDocument) { return(false); } var doc = r.ToDocument(); _log.Debug(doc.ToPrettyString()); return(doc["channel"].AsText == "event://default/deki/pages/update" && doc["pageid"].AsText == "10"); }) .ExpectCalls(Times.Once()); var evDoc = new XDoc("deki-event") .Attr("wikiid", "default") .Elem("channel", "event://default/deki/pages/update") .Elem("uri", "deki://default/pages/10") .Elem("pageid", "10"); var ev = new DispatcherEvent(evDoc, new XUri("event://default/deki/pages/update"), new XUri("deki://default/pages/10"), new XUri("http://default/deki/pages/10")); _log.DebugFormat("ready to dispatch event"); dispatcher.Dispatch(ev); MockPlug.VerifyAll(TimeSpan.FromSeconds(10)); }
public void Dispatch(DispatcherEvent key, object arg) { Dispatch <object>(key, arg); }
public static void RemoveListenerVector3(this GlobalDispatcher self, DispatcherEvent key, System.Action <Vector3> action) { self.RemoveListener <Vector3>(key, action); }
public override void Run(DebugAdapterRunner runner) { // Send the request string request = CreateDispatcherRequest(runner); // VSCode doesn't send /n at the end. If this is writeline, then concord hangs runner.DebugAdapter.StandardInput.Write(request); // Process + validate responses List <object> responseList = new List <object>(); int currentExpectedResponseIndex = 0; // Loop until we have received as many expected responses as expected while (currentExpectedResponseIndex < this.ExpectedResponses.Count) { string receivedMessage = null; Exception getMessageExeception = null; try { receivedMessage = this.GetMessage( runner.DebugAdapter.StandardOutput.BaseStream, runner.ResponseTimeout, runner.DebugAdapter, runner); } catch (Exception e) { getMessageExeception = e; } if (getMessageExeception != null) { if (!runner.DebugAdapter.HasExited) { // If it hasn't exited yet, wait a little bit longer to make sure it isn't just about to exit try { runner.DebugAdapter.WaitForExit(500); } catch { } } string messageStart; if (runner.DebugAdapter.HasExited) { if (runner.HasAsserted()) { messageStart = string.Format(CultureInfo.CurrentCulture, "The debugger process has asserted and exited with code '{0}' without sending all expected responses. See test log for assert details.", runner.DebugAdapter.ExitCode); } else { messageStart = string.Format(CultureInfo.CurrentCulture, "The debugger process has exited with code '{0}' without sending all expected responses.", runner.DebugAdapter.ExitCode); } } else if (getMessageExeception is TimeoutException) { if (runner.HasAsserted()) { messageStart = "The debugger process has asserted. See test log for assert details."; } else { messageStart = "Expected response not found before timeout."; } } else { messageStart = "Exception while reading message from debug adpter. " + getMessageExeception.Message; } string expectedResponseText = JsonConvert.SerializeObject(this.ExpectedResponses[currentExpectedResponseIndex].Response); string actualResponseText = string.Empty; for (int i = 0; i < responseList.Count; i++) { actualResponseText += string.Format(CultureInfo.CurrentCulture, "{0}. {1}\n", (i + 1), JsonConvert.SerializeObject(responseList[i])); } string errorMessage = string.Format(CultureInfo.CurrentCulture, "{0}\nExpected = {1}\nActual Responses =\n{2}", messageStart, expectedResponseText, actualResponseText); throw new DARException(errorMessage); } try { DispatcherMessage dispatcherMessage = JsonConvert.DeserializeObject <DispatcherMessage>(receivedMessage); if (dispatcherMessage.type == "event") { DispatcherEvent dispatcherEvent = JsonConvert.DeserializeObject <DispatcherEvent>(receivedMessage); responseList.Add(dispatcherEvent); if (dispatcherEvent.eventType == "stopped") { runner.CurrentThreadId = dispatcherEvent.body.threadId; } var expected = this.ExpectedResponses[currentExpectedResponseIndex]; if (Utils.CompareObjects(expected.Response, dispatcherEvent, expected.IgnoreOrder)) { expected.Match = dispatcherEvent; currentExpectedResponseIndex++; } } else if (dispatcherMessage.type == "response") { DispatcherResponse dispatcherResponse = JsonConvert.DeserializeObject <DispatcherResponse>(receivedMessage); responseList.Add(dispatcherResponse); var expected = this.ExpectedResponses[currentExpectedResponseIndex]; if (Utils.CompareObjects(expected.Response, dispatcherResponse, expected.IgnoreOrder)) { expected.Match = dispatcherResponse; currentExpectedResponseIndex++; } } else if (dispatcherMessage.type == "request") { runner.HandleCallbackRequest(receivedMessage); } else { throw new DARException(String.Format(CultureInfo.CurrentCulture, "Unknown Dispatcher Message type: '{0}'", dispatcherMessage.type)); } } catch (JsonReaderException) { runner.AppendLineToDebugAdapterOutput("Response could not be parsed as json. This was the response:"); runner.AppendLineToDebugAdapterOutput(receivedMessage); throw; } } }
public static void AddListenerFloat(this GlobalDispatcher self, DispatcherEvent key, System.Action <float> action) { self.AddListener <float>(key, action); }
public void Subscribers_to_a_single_page_do_not_get_escalated_by_a_subscriber_with_infinite_depth_on_same_page() { var mockDekiUri = new XUri("http://mock/deki"); var mockDeki = MockPlug.Register(mockDekiUri); mockDeki.Expect().Verb("GET").Uri(mockDekiUri.At("pages", "10")).Response(DreamMessage.Ok(new XDoc("page") .Attr("id", "10") .Start("page.parent") .Attr("id", "9") .Start("page.parent") .Attr("id", "8") .Start("page.parent") .Attr("id", "7") .EndAll())); var dispatcherUri = new XUri("http://mock/dispatcher"); var dispatcher = new DekiDispatcher( new DispatcherConfig { ServiceUri = dispatcherUri, ServiceAccessCookie = new DreamCookie("service-key", "foo", dispatcherUri), ServiceConfig = new XDoc("config").Elem("uri.deki", mockDekiUri).Elem("authtoken", "abc") }, _mockRepository.Object ); var combinedSetUpdated = 0; dispatcher.CombinedSetUpdated += (o, e) => { combinedSetUpdated++; }; // subscribe to page 7 and all children var mockHierarchyRecipientUri = new XUri("http://mock/recipient/hierarchy"); var mockHierarchyRecipient = MockPlug.Register(mockHierarchyRecipientUri); mockHierarchyRecipient.Expect().Verb("POST"); dispatcher.RegisterSet( "location1", new XDoc("subscription-set") .Elem("uri.owner", mockHierarchyRecipientUri) .Start("subscription") .Attr("id", "3") .Elem("uri.resource", "deki://default/pages/7#depth=infinity") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("authtoken", "abc").Elem("uri", mockHierarchyRecipientUri).End() .End(), "def" ); // subscribe to only page 7 var mockPageonlyRecipientUri = new XUri("http://mock/recipient/pageonly"); var mockPageonlyRecipientCalled = 0; MockPlug.Register(mockPageonlyRecipientUri, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { _log.DebugFormat("mockPageonlyRecipient called at: {0}", u); mockPageonlyRecipientCalled++; r2.Return(DreamMessage.Ok()); }); dispatcher.RegisterSet( "location2", new XDoc("subscription-set") .Elem("uri.owner", mockPageonlyRecipientUri) .Start("subscription") .Attr("id", "3") .Elem("uri.resource", "deki://default/pages/7") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("authtoken", "abc").Elem("uri", mockPageonlyRecipientUri).End() .End(), "def" ); // wait for subscriptions to be set up _log.DebugFormat("wait for subscriptions to be updated"); Assert.IsTrue( Wait.For(() => combinedSetUpdated == 2, TimeSpan.FromSeconds(10)), string.Format("timeout waiting for subscriptions, expected 2, got {0} dispatches", combinedSetUpdated)); // fire page change for page 10 (sub-child of page 7) XDoc evDoc = new XDoc("deki-event") .Attr("wikiid", "default") .Elem("channel", "event://default/deki/pages/update") .Elem("uri", "deki://default/pages/10") .Elem("pageid", "10"); var ev = new DispatcherEvent(evDoc, new XUri("event://default/deki/pages/update"), new XUri("deki://default/pages/10"), new XUri("http://default/deki/pages/10")); _log.DebugFormat("ready to dispatch event"); dispatcher.Dispatch(ev); // wait for deki to have been called _log.DebugFormat("wait for deki call"); Assert.IsTrue(mockDeki.WaitAndVerify(TimeSpan.FromSeconds(10)), mockDeki.VerificationFailure); // wait for recipients to be notified _log.DebugFormat("wait for hierarchy notification"); Assert.IsTrue(mockHierarchyRecipient.WaitAndVerify(TimeSpan.FromSeconds(10)), mockHierarchyRecipient.VerificationFailure); // only 'hierarchy' subscriber should have been notified _log.DebugFormat("make sure page only doesn't get called"); Assert.IsFalse(Wait.For(() => mockPageonlyRecipientCalled > 0, TimeSpan.FromSeconds(5))); }
public void Page_delete_events_skip_page_auth() { XUri mockDeki = new XUri("http://mock/deki"); int dekiCalled = 0; MockPlug.Register(mockDeki, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { _log.DebugFormat("mockDeki called at: {0}", u); dekiCalled++; r2.Return(DreamMessage.BadRequest("shouldn't have called deki")); }); XUri authorizedRecipient = new XUri("http://mock/authorized2"); AutoResetEvent authorizedResetEvent = new AutoResetEvent(false); XDoc authorizedReceived = null; MockPlug.Register(authorizedRecipient, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { _log.DebugFormat("authorizedRecipient called at: {0}", u); authorizedReceived = r.ToDocument(); authorizedResetEvent.Set(); r2.Return(DreamMessage.Ok()); }); XUri mockRecipient = new XUri("http://mock/r1"); int mockRecipientCalled = 0; MockPlug.Register(mockRecipient, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { _log.DebugFormat("mockRecipient called at: {0}", u); mockRecipientCalled++; r2.Return(DreamMessage.Ok()); }); XUri dispatcherUri = new XUri("http://mock/dispatcher"); DekiDispatcher dispatcher = new DekiDispatcher( new DispatcherConfig { ServiceUri = dispatcherUri, ServiceAccessCookie = new DreamCookie("service-key", "foo", dispatcherUri), ServiceConfig = new XDoc("config").Elem("uri.deki", mockDeki).Elem("authtoken", "abc") }, _mockRepository.Object ); XDoc sub1 = new XDoc("subscription-set") .Elem("uri.owner", authorizedRecipient) .Start("subscription") .Attr("id", "1") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("authtoken", "abc").Elem("uri", authorizedRecipient).End() .End(); Thread.Sleep(100); _log.DebugFormat("registering sub set 1"); dispatcher.RegisterSet("abc", sub1, "def"); XDoc sub2 = new XDoc("subscription-set") .Elem("uri.owner", mockRecipient.At("1")) .Start("subscription") .Attr("id", "1") .Elem("uri.resource", "deki://default/pages/10") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("userid", "1").Elem("uri", "http://mock/r1/match").End() .End(); Thread.Sleep(100); _log.DebugFormat("registering sub set 2"); dispatcher.RegisterSet("abc", sub2, "def"); XDoc evDoc = new XDoc("deki-event") .Attr("wikiid", "default") .Elem("channel", "event://default/deki/pages/delete") .Elem("uri", "deki://default/pages/10") .Elem("pageid", "10"); var ev = new DispatcherEvent(evDoc, new XUri("event://default/deki/pages/delete"), new XUri("deki://default/pages/10"), new XUri("http://default/deki/pages/10")); _log.DebugFormat("ready to dispatch event"); // Meh. Testing multithreaded code is wonky. This 1000ms sleep is required, otherwise the event below never fires Thread.Sleep(1000); dispatcher.Dispatch(ev); // since we're waiting for more than one dekiPageAuthEvent, we give it a chance to finish after the first triggers Assert.IsTrue(authorizedResetEvent.WaitOne(5000, false)); Assert.AreEqual(0, dekiCalled); Assert.AreEqual(0, mockRecipientCalled); Assert.AreEqual(evDoc, authorizedReceived); }
public void Page_events_uses_deki_to_check_parent_wildcard_resource_matches() { var dekiPageAuthEvent = new ManualResetEvent(false); var authorizedRecipientCalledEv = new ManualResetEvent(false); var mockMatchCalledEv = new ManualResetEvent(false); var mockWildcardCalledEv = new ManualResetEvent(false); XUri mockDeki = new XUri("http://mock/deki"); int dekiPageAuthCalled = 0; int dekiPageCalled = 0; MockPlug.Register(mockDeki, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { XDoc rDoc = null; _log.DebugFormat("mockDeki called at: {0}", u); if (u.Segments.Length == 3) { _log.DebugFormat("getting page xml"); if (u.LastSegment == "10") { dekiPageCalled++; } rDoc = new XDoc("page") .Attr("id", "10") .Start("page.parent") .Attr("id", "9") .Start("page.parent") .Attr("id", "8") .Start("page.parent") .Attr("id", "7") .EndAll(); } else { _log.DebugFormat("getting users for page: {0}", u.LastSegment); dekiPageAuthCalled++; rDoc = new XDoc("users"); foreach (XDoc user in r.ToDocument()["user/@id"]) { rDoc.Start("user").Attr("id", user.AsText).End(); } if (dekiPageAuthCalled == 2) { dekiPageAuthEvent.Set(); } } r2.Return(DreamMessage.Ok(rDoc)); }); XUri authorizedRecipient = new XUri("http://mock/authorized2"); int authorizedRecipientCalled = 0; XDoc authorizedReceived = null; MockPlug.Register(authorizedRecipient, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { _log.DebugFormat("authorizedRecipient called at: {0}", u); authorizedRecipientCalled++; authorizedReceived = r.ToDocument(); authorizedRecipientCalledEv.Set(); r2.Return(DreamMessage.Ok()); }); XUri mockRecipient = new XUri("http://mock/r1"); int mockRecipientCalled = 0; int mockMatchCalled = 0; int mockWildcardCalled = 0; MockPlug.Register(mockRecipient, delegate(Plug p, string v, XUri u, DreamMessage r, Result <DreamMessage> r2) { _log.DebugFormat("mockRecipient called at: {0}", u); mockRecipientCalled++; if (u == mockRecipient.At("match")) { mockMatchCalled++; mockMatchCalledEv.Set(); } else if (u == mockRecipient.At("wildcard")) { mockWildcardCalled++; mockWildcardCalledEv.Set(); } r2.Return(DreamMessage.Ok()); }); XUri dispatcherUri = new XUri("http://mock/dispatcher"); DekiDispatcher dispatcher = new DekiDispatcher( new DispatcherConfig() { ServiceUri = dispatcherUri, ServiceAccessCookie = new DreamCookie("service-key", "foo", dispatcherUri), ServiceConfig = new XDoc("config").Elem("uri.deki", mockDeki).Elem("authtoken", "abc") }, _mockRepository.Object ); XDoc sub1 = new XDoc("subscription-set") .Elem("uri.owner", authorizedRecipient) .Start("subscription") .Attr("id", "1") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("authtoken", "abc").Elem("uri", authorizedRecipient).End() .End(); _log.DebugFormat("registering sub set 1"); dispatcher.RegisterSet("location1", sub1, "def"); Assert.IsTrue(Wait.For(() => dispatcher.CombinedSet.Subscriptions .Where(s => s.Channels.Where(c => c.ToString() == "event://default/deki/pages/*").Any() && !s.Resources.Any() ).Any(), 10.Seconds())); XDoc sub2 = new XDoc("subscription-set") .Elem("uri.owner", mockRecipient.At("1")) .Start("subscription") .Attr("id", "1") .Elem("uri.resource", "deki://default/pages/10") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("userid", "1").Elem("uri", "http://mock/r1/match").End() .End(); _log.DebugFormat("registering sub set 2"); dispatcher.RegisterSet("location2", sub2, "def"); Assert.IsTrue(Wait.For(() => dispatcher.CombinedSet.Subscriptions .Where(s => s.Channels.Where(c => c.ToString() == "event://default/deki/pages/*").Any() && s.Resources.Where(r => r.ToString() == "deki://default/pages/10").Any() ).Any(), 10.Seconds())); XDoc sub3 = new XDoc("subscription-set") .Elem("uri.owner", mockRecipient.At("2")) .Start("subscription") .Attr("id", "2") .Elem("uri.resource", "deki://default/pages/11") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("userid", "1").Elem("uri", "http://mock/r1/miss").End() .End(); _log.DebugFormat("registering sub set 3"); dispatcher.RegisterSet("location3", sub3, "def"); Assert.IsTrue(Wait.For(() => dispatcher.CombinedSet.Subscriptions .Where(s => s.Channels.Where(c => c.ToString() == "event://default/deki/pages/*").Any() && s.Resources.Where(r => r.ToString() == "deki://default/pages/11").Any() ).Any(), 10.Seconds())); XDoc sub4 = new XDoc("subscription-set") .Elem("uri.owner", mockRecipient.At("3")) .Start("subscription") .Attr("id", "3") .Elem("uri.resource", "deki://default/pages/8#depth=infinity") .Elem("channel", "event://default/deki/pages/*") .Start("recipient").Attr("userid", "1").Elem("uri", "http://mock/r1/wildcard").End() .End(); _log.DebugFormat("registering sub set 4"); dispatcher.RegisterSet("location4", sub4, "def"); Assert.IsTrue(Wait.For(() => dispatcher.CombinedSet.Subscriptions .Where(s => s.Channels.Where(c => c.ToString() == "event://default/deki/pages/*").Any() && s.Resources.Where(r => r.ToString() == "deki://default/pages/8#depth%3Dinfinity").Any() ).Any(), 10.Seconds())); XDoc evDoc = new XDoc("deki-event") .Attr("wikiid", "default") .Elem("channel", "event://default/deki/pages/update") .Elem("uri", "deki://default/pages/10") .Elem("pageid", "10"); var ev = new DispatcherEvent(evDoc, new XUri("event://default/deki/pages/update"), new XUri("deki://default/pages/10"), new XUri("http://default/deki/pages/10")); _log.DebugFormat("ready to dispatch event"); dispatcher.Dispatch(ev); Assert.IsTrue(dekiPageAuthEvent.WaitOne(5000, true)); Assert.IsTrue(authorizedRecipientCalledEv.WaitOne(5000, true)); Assert.IsTrue(mockMatchCalledEv.WaitOne(5000, true)); Assert.IsTrue(mockWildcardCalledEv.WaitOne(5000, true)); Assert.AreEqual(1, dekiPageCalled); Assert.AreEqual(2, dekiPageAuthCalled); Assert.AreEqual(1, authorizedRecipientCalled); Assert.AreEqual(2, mockRecipientCalled); Assert.AreEqual(1, mockMatchCalled); Assert.AreEqual(1, mockWildcardCalled); Assert.AreEqual(evDoc, authorizedReceived); }
//--- Constructors --- /// <summary> /// Create a new dispatch item /// </summary> /// <param name="uri">Uri the event will be dispatched to.</param> /// <param name="event">Event to dispatch.</param> /// <param name="location">Location string identifying the <see cref="PubSubSubscriptionSet"/> the event is being dispatched for.</param> public DispatchItem(XUri uri, DispatcherEvent @event, string location) { Uri = uri; Event = @event; Location = location; }
public static void DispatchVector3(this GlobalDispatcher self, DispatcherEvent key, Vector3 arg) { self.Dispatch <Vector3>(key, arg); }
public static void AddListenerVector2(this GlobalDispatcher self, DispatcherEvent key, System.Action <Vector2> action) { self.AddListener <Vector2>(key, action); }
public static void RemoveListenerBool(this GlobalDispatcher self, DispatcherEvent key, System.Action <bool> action) { self.RemoveListener <bool>(key, action); }
public static void DispatchFloat(this GlobalDispatcher self, DispatcherEvent key, float arg) { self.Dispatch <float>(key, arg); }
protected override Yield FilterRecipients(DispatcherEvent ev, PubSubSubscription subscription, Result <DispatcherEvent> result) { var recipients2 = new List <DispatcherRecipient>(); uint? pageid = null; string wikiId = null; if (ev.HasDocument) { var changeDoc = ev.AsDocument(); pageid = changeDoc["pageid"].AsUInt; wikiId = changeDoc["@wikiid"].AsText; } var userIds = new Dictionary <int, DispatcherRecipient>(); foreach (var recipient in subscription.Recipients) { var authtoken = recipient.Doc["@authtoken"].AsText; if (string.IsNullOrEmpty(authtoken)) { // if the recipient has no authtoken, but has a userid, collect the Id so we can authorize it against the page int?userId = recipient.Doc["@userid"].AsInt; if (userId.HasValue) { userIds.Add(userId.Value, recipient); } } else if (authtoken == _authtoken) { // master authtoken means the recipient doesn't need page level authorization (such as lucene) recipients2.Add(recipient); } else if (!string.IsNullOrEmpty(wikiId)) { var key = authtoken + ":" + wikiId; if (!_validatedKeys.Contains(key)) { // no valid key found, need to check with API to validate XDoc settings = null; yield return(_deki.At("site", "settings") .With("apikey", _authtoken) .WithHeader("X-Deki-Site", "id=" + wikiId) .Get(new Result <DreamMessage>()) .Set(x => settings = x.IsSuccessful ? x.ToDocument() : null)); if (settings == null || !authtoken.EqualsInvariant(settings["security/api-key"].AsText)) { continue; } _validatedKeys.Add(key); } // instance authtoken means the recipient doesn't need page level authorization (such as lucene) recipients2.Add(recipient); } } if (userIds.Count > 0 && (ev.Channel.Segments.Length <= 2 || !ev.Channel.Segments[2].EqualsInvariantIgnoreCase("delete"))) { // check all userId's against the page to prune set to authorized users var users = new XDoc("users"); foreach (int userid in userIds.Keys) { users.Start("user").Attr("id", userid).End(); } if (pageid.HasValue) { Result <DreamMessage> userAuthResult; yield return(userAuthResult = _deki.At("pages", pageid.Value.ToString(), "allowed") .With("permissions", "read,subscribe") .With("filterdisabled", true) .WithHeader("X-Deki-Site", "id=" + wikiId) .PostAsync(users)); DreamMessage userAuth = userAuthResult.Value; if (userAuth.IsSuccessful) { int authorized = 0; foreach (XDoc userid in userAuth.ToDocument()["user/@id"]) { DispatcherRecipient recipient; if (!userIds.TryGetValue(userid.AsInt.GetValueOrDefault(), out recipient)) { continue; } authorized++; recipients2.Add(recipient); } if (authorized != userIds.Count) { _log.DebugFormat("requested auth on {0} users, received auth on {1} for page {2}", userIds.Count, authorized, pageid.Value); } } else { _log.WarnFormat("unable to retrieve user auth for page '{0}': {1}", pageid, userAuth.Status); } } } result.Return(recipients2.Count == 0 ? null : ev.WithRecipient(true, recipients2.ToArray())); yield break; }