• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Jericho / ZoomNet / 792

26 Oct 2024 12:38PM UTC coverage: 20.493% (+0.1%) from 20.392%
792

push

appveyor

Jericho
Merge branch 'release/0.82.0'

649 of 3167 relevant lines covered (20.49%)

11.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.18
/Source/ZoomNet/ZoomClient.cs
1
using Microsoft.Extensions.Logging;
2
using Microsoft.Extensions.Logging.Abstractions;
3
using Pathoschild.Http.Client;
4
using Pathoschild.Http.Client.Extensibility;
5
using System;
6
using System.Net;
7
using System.Net.Http;
8
using System.Reflection;
9
using ZoomNet.Json;
10
using ZoomNet.Resources;
11
using ZoomNet.Utilities;
12

13
namespace ZoomNet
14
{
15
        /// <summary>
16
        /// REST client for interacting with Zoom's API.
17
        /// </summary>
18
        /// <remarks>
19
        /// Don't be fooled by the fact that this class implements the IDisposable interface: it is not meant to be short-lived and instantiated with every request.
20
        /// It is meant to be long-lived and re-used throughout the life of an application.
21
        /// The reason is: we use Microsoft's HttpClient to dispatch requests which itself is meant to be long-lived and re-used.
22
        /// Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads and will result in SocketException errors.
23
        ///
24
        /// See <a href="https://github.com/Jericho/ZoomNet/issues/35">this discussion</a> for more information about managing the lifetime of your client instance.
25
        /// </remarks>
26
        public class ZoomClient : IZoomClient, IDisposable
27
        {
28
                #region FIELDS
29

30
                private const string ZOOM_V2_BASE_URI = "https://api.zoom.us/v2";
31

32
                private static string _version;
33

34
                private readonly bool _mustDisposeHttpClient;
35
                private readonly ZoomClientOptions _options;
36
                private readonly ILogger _logger;
37

38
                private HttpClient _httpClient;
39
                private Pathoschild.Http.Client.IClient _fluentClient;
40

41
                #endregion
42

43
                #region PROPERTIES
44

45
                /// <summary>
46
                /// Gets the Version.
47
                /// </summary>
48
                /// <value>
49
                /// The version.
50
                /// </value>
51
                public static string Version
52
                {
53
                        get
54
                        {
55
                                if (string.IsNullOrEmpty(_version))
4✔
56
                                {
57
                                        _version = typeof(ZoomClient).GetTypeInfo().Assembly.GetName().Version.ToString(3);
1✔
58
#if DEBUG
59
                                        _version = "DEBUG";
60
#endif
61
                                }
62

63
                                return _version;
4✔
64
                        }
65
                }
66

67
                /// <inheritdoc/>
68
                public IAccounts Accounts { get; private set; }
69

70
                /// <inheritdoc/>
71
                public IChat Chat { get; private set; }
72

73
                /// <inheritdoc/>
74
                public ICloudRecordings CloudRecordings { get; private set; }
75

76
                /// <inheritdoc/>
77
                public IContacts Contacts { get; private set; }
78

79
                /// <inheritdoc/>
80
                [Obsolete("The Data Compliance API is deprecated")]
81
                public IDataCompliance DataCompliance { get; private set; }
82

83
                /// <inheritdoc/>
84
                public IMeetings Meetings { get; private set; }
85

86
                /// <inheritdoc/>
87
                public IPastMeetings PastMeetings { get; private set; }
88

89
                /// <inheritdoc/>
90
                public IPastWebinars PastWebinars { get; private set; }
91

92
                /// <inheritdoc/>
93
                public IRoles Roles { get; private set; }
94

95
                /// <inheritdoc/>
96
                public IUsers Users { get; private set; }
97

98
                /// <inheritdoc/>
99
                public IWebinars Webinars { get; private set; }
100

101
                /// <inheritdoc/>
102
                public IDashboards Dashboards { get; private set; }
103

104
                /// <inheritdoc/>
105
                public IReports Reports { get; private set; }
106

107
                /// <inheritdoc/>
108
                public ICallLogs CallLogs { get; private set; }
109

110
                /// <inheritdoc/>
111
                public IChatbot Chatbot { get; private set; }
112

113
                /// <inheritdoc/>
114
                public IPhone Phone { get; private set; }
115

116
                /// <inheritdoc/>
117
                public ISms Sms { get; private set; }
118

119
                /// <inheritdoc/>
120
                public IGroups Groups { get; private set; }
121

122
                #endregion
123

124
                #region CTOR
125

126
                /// <summary>
127
                /// Initializes a new instance of the <see cref="ZoomClient"/> class.
128
                /// </summary>
129
                /// <param name="connectionInfo">Connection information.</param>
130
                /// <param name="options">Options for the Zoom client.</param>
131
                /// <param name="logger">Logger.</param>
132
                public ZoomClient(IConnectionInfo connectionInfo, ZoomClientOptions options = null, ILogger logger = null)
133
                        : this(connectionInfo, new HttpClient(), true, options, logger)
1✔
134
                {
135
                }
×
136

137
                /// <summary>
138
                /// Initializes a new instance of the <see cref="ZoomClient"/> class with a specific proxy.
139
                /// </summary>
140
                /// <param name="connectionInfo">Connection information.</param>
141
                /// <param name="proxy">Allows you to specify a proxy.</param>
142
                /// <param name="options">Options for the Zoom client.</param>
143
                /// <param name="logger">Logger.</param>
144
                public ZoomClient(IConnectionInfo connectionInfo, IWebProxy proxy, ZoomClientOptions options = null, ILogger logger = null)
145
                        : this(connectionInfo, new HttpClient(new HttpClientHandler { Proxy = proxy, UseProxy = proxy != null }), true, options, logger)
1✔
146
                {
147
                }
1✔
148

149
                /// <summary>
150
                /// Initializes a new instance of the <see cref="ZoomClient"/> class with a specific handler.
151
                /// </summary>
152
                /// <param name="connectionInfo">Connection information.</param>
153
                /// <param name="handler">TThe HTTP handler stack to use for sending requests.</param>
154
                /// <param name="options">Options for the Zoom client.</param>
155
                /// <param name="logger">Logger.</param>
156
                public ZoomClient(IConnectionInfo connectionInfo, HttpMessageHandler handler, ZoomClientOptions options = null, ILogger logger = null)
157
                        : this(connectionInfo, new HttpClient(handler), true, options, logger)
×
158
                {
159
                }
×
160

161
                /// <summary>
162
                /// Initializes a new instance of the <see cref="ZoomClient"/> class with a specific http client.
163
                /// </summary>
164
                /// <param name="connectionInfo">Connection information.</param>
165
                /// <param name="httpClient">Allows you to inject your own HttpClient. This is useful, for example, to setup the HtppClient with a proxy.</param>
166
                /// <param name="options">Options for the Zoom client.</param>
167
                /// <param name="logger">Logger.</param>
168
                public ZoomClient(IConnectionInfo connectionInfo, HttpClient httpClient, ZoomClientOptions options = null, ILogger logger = null)
169
                        : this(connectionInfo, httpClient, false, options, logger)
1✔
170
                {
171
                }
1✔
172

173
                private ZoomClient(IConnectionInfo connectionInfo, HttpClient httpClient, bool disposeClient, ZoomClientOptions options, ILogger logger = null)
174
                {
175
                        if (connectionInfo == null) throw new ArgumentNullException(nameof(connectionInfo));
3✔
176

177
                        _mustDisposeHttpClient = disposeClient;
3✔
178
                        _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
3✔
179
                        _options = options ?? new();
3✔
180
                        _logger = logger ?? NullLogger.Instance;
3✔
181
                        _fluentClient = new FluentClient(new Uri(ZOOM_V2_BASE_URI), httpClient)
3✔
182
                                .SetUserAgent($"ZoomNet/{Version} (+https://github.com/Jericho/ZoomNet)");
3✔
183

184
                        _fluentClient.Filters.Remove<DefaultErrorFilter>();
3✔
185

186
                        // Remove all the built-in formatters and replace them with our custom JSON formatter
187
                        _fluentClient.Formatters.Clear();
3✔
188
                        _fluentClient.Formatters.Add(new JsonFormatter());
3✔
189

190
                        // Order is important: the token handler (either JWT or OAuth) must be first, followed by DiagnosticHandler and then by ErrorHandler.
191
                        if (connectionInfo is JwtConnectionInfo jwtConnectionInfo)
3✔
192
                        {
193
                                var tokenHandler = new JwtTokenHandler(jwtConnectionInfo);
2✔
194
                                _fluentClient.Filters.Add(tokenHandler);
1✔
195
                                _fluentClient.SetRequestCoordinator(new ZoomRetryCoordinator(new Http429RetryStrategy(), tokenHandler));
1✔
196
                        }
197
                        else if (connectionInfo is OAuthConnectionInfo oAuthConnectionInfo)
1✔
198
                        {
199
                                var tokenHandler = new OAuthTokenHandler(oAuthConnectionInfo, httpClient);
1✔
200
                                _fluentClient.Filters.Add(tokenHandler);
1✔
201
                                _fluentClient.SetRequestCoordinator(new ZoomRetryCoordinator(new Http429RetryStrategy(), tokenHandler));
1✔
202
                        }
203
                        else
204
                        {
205
                                throw new ZoomException($"{connectionInfo.GetType()} is an unknown connection type", null, null, null, null);
×
206
                        }
207

208
                        // The list of filters must be kept in sync with the filters in Utils.GetFluentClient in the unit testing project.
209
                        _fluentClient.Filters.Add(new DiagnosticHandler(_options.LogLevelSuccessfulCalls, _options.LogLevelFailedCalls, _logger));
2✔
210
                        _fluentClient.Filters.Add(new ZoomErrorHandler());
2✔
211

212
                        Accounts = new Accounts(_fluentClient);
2✔
213
                        Chat = new Chat(_fluentClient);
2✔
214
                        CloudRecordings = new CloudRecordings(_fluentClient);
2✔
215
                        Contacts = new Contacts(_fluentClient);
2✔
216
                        DataCompliance = new DataCompliance(_fluentClient);
2✔
217
                        Meetings = new Meetings(_fluentClient);
2✔
218
                        PastMeetings = new PastMeetings(_fluentClient);
2✔
219
                        PastWebinars = new PastWebinars(_fluentClient);
2✔
220
                        Roles = new Roles(_fluentClient);
2✔
221
                        Users = new Users(_fluentClient);
2✔
222
                        Webinars = new Webinars(_fluentClient);
2✔
223
                        Dashboards = new Dashboards(_fluentClient);
2✔
224
                        Reports = new Reports(_fluentClient);
2✔
225
                        CallLogs = new CallLogs(_fluentClient);
2✔
226
                        Chatbot = new Chatbot(_fluentClient);
2✔
227
                        Phone = new Phone(_fluentClient);
2✔
228
                        Sms = new Sms(_fluentClient);
2✔
229
                        Groups = new Groups(_fluentClient);
2✔
230
                }
2✔
231

232
                /// <summary>
233
                /// Finalizes an instance of the <see cref="ZoomClient"/> class.
234
                /// </summary>
235
                ~ZoomClient()
236
                {
237
                        // The object went out of scope and finalized is called.
238
                        // Call 'Dispose' to release unmanaged resources
239
                        // Managed resources will be released when GC runs the next time.
240
                        Dispose(false);
×
241
                }
×
242

243
                #endregion
244

245
                #region PUBLIC METHODS
246

247
                /// <inheritdoc/>
248
                public void Dispose()
249
                {
250
                        // Call 'Dispose' to release resources
251
                        Dispose(true);
1✔
252

253
                        // Tell the GC that we have done the cleanup and there is nothing left for the Finalizer to do
254
                        GC.SuppressFinalize(this);
1✔
255
                }
1✔
256

257
                /// <summary>
258
                /// Releases unmanaged and - optionally - managed resources.
259
                /// </summary>
260
                /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
261
                protected virtual void Dispose(bool disposing)
262
                {
263
                        if (disposing)
1✔
264
                        {
265
                                ReleaseManagedResources();
1✔
266
                        }
267
                        else
268
                        {
269
                                // The object went out of scope and the Finalizer has been called.
270
                                // The GC will take care of releasing managed resources, therefore there is nothing to do here.
271
                        }
272

273
                        ReleaseUnmanagedResources();
1✔
274
                }
1✔
275

276
                #endregion
277

278
                #region PRIVATE METHODS
279

280
                private void ReleaseManagedResources()
281
                {
282
                        if (_fluentClient != null)
1✔
283
                        {
284
                                _fluentClient.Dispose();
1✔
285
                                _fluentClient = null;
1✔
286
                        }
287

288
                        if (_httpClient != null && _mustDisposeHttpClient)
1✔
289
                        {
290
                                _httpClient.Dispose();
1✔
291
                                _httpClient = null;
1✔
292
                        }
293
                }
1✔
294

295
                private void ReleaseUnmanagedResources()
296
                {
297
                        // We do not hold references to unmanaged resources
298
                }
1✔
299

300
                #endregion
301
        }
302
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc