This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 171
/
EventQueues.cs
109 lines (95 loc) · 3.71 KB
/
EventQueues.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Microsoft.VisualStudio.LanguageServer.Protocol;
namespace Microsoft.Quantum.QsLanguageServer
{
public class CoalesceingQueue
{
private int nrSubscriptions = 0;
private readonly ConcurrentDictionary<int, (IDisposable, IDisposable)> subscriptions;
public CoalesceingQueue() =>
this.subscriptions = new ConcurrentDictionary<int, (IDisposable, IDisposable)>();
public bool Unsubscribe(int id)
{
if (!this.subscriptions.TryRemove(id, out var subscriptions))
{
return false;
}
subscriptions.Item1.Dispose();
subscriptions.Item2.Dispose();
return true;
}
public int Subscribe<T>(IObservable<T> observable, Action<IEnumerable<T>> bufferHandler)
{
var fileIdle = new Subject<Unit>();
fileIdle.OnNext(Unit.Default);
var timer = new System.Timers.Timer(2000);
timer.Elapsed += (_, __) => fileIdle.OnNext(Unit.Default);
timer.AutoReset = false;
timer.Enabled = false;
var eventSubscription = observable.Subscribe(fileEvent =>
{
timer.Stop();
timer.Start();
});
var bufferedSubscription = observable.Buffer(fileIdle).Subscribe(e => bufferHandler(e));
var id = ++this.nrSubscriptions;
var subscriptions = (eventSubscription, bufferedSubscription);
if (!this.subscriptions.TryAdd(id, subscriptions))
{
id = -1;
}
return id;
}
internal static IEnumerable<FileEvent> Coalesce(IEnumerable<FileEvent> events)
{
var stacks = new Dictionary<Uri, Stack<FileEvent>>(); // we use one queue for each event source in order to coalesce
foreach (var e in events)
{
if (!stacks.TryGetValue(e.Uri, out var stack))
{
stack = new Stack<FileEvent>();
stack.Push(e);
stacks.Add(e.Uri, stack);
continue;
}
var last = stack.Pop();
var changedEvent = new FileEvent { FileChangeType = FileChangeType.Changed, Uri = e.Uri };
if (last.FileChangeType == e.FileChangeType)
{
stack.Push(last);
}
else if (last.FileChangeType == FileChangeType.Created && e.FileChangeType == FileChangeType.Deleted)
{
stacks.Remove(e.Uri);
}
else if (last.FileChangeType == FileChangeType.Deleted && e.FileChangeType == FileChangeType.Created)
{
stack.Push(changedEvent);
}
else if (last.FileChangeType == FileChangeType.Created && e.FileChangeType == FileChangeType.Changed)
{
stack.Push(last);
}
else if (last.FileChangeType == FileChangeType.Changed && e.FileChangeType == FileChangeType.Deleted)
{
stack.Push(e);
}
else
{
stack.Push(last);
stack.Push(e);
}
}
return stacks.Values.SelectMany(stack => stack.Reverse()).ToImmutableArray();
}
}
}