conversant 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +39 -0
  3. data/.gitignore +52 -0
  4. data/.gitlab-ci.yml +108 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +16 -0
  7. data/.yardopts +7 -0
  8. data/CHANGELOG.md +487 -0
  9. data/Gemfile +12 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +860 -0
  12. data/RELEASE.md +726 -0
  13. data/Rakefile +21 -0
  14. data/conversant.gemspec +49 -0
  15. data/examples/inheritance_integration.rb +348 -0
  16. data/examples/rails_initializer.rb +69 -0
  17. data/lib/conversant/configuration.rb +132 -0
  18. data/lib/conversant/v3/base.rb +47 -0
  19. data/lib/conversant/v3/http_client.rb +456 -0
  20. data/lib/conversant/v3/mixins/authentication.rb +221 -0
  21. data/lib/conversant/v3/services/authorization.rb +194 -0
  22. data/lib/conversant/v3/services/cdn/analytics.rb +483 -0
  23. data/lib/conversant/v3/services/cdn/audit.rb +71 -0
  24. data/lib/conversant/v3/services/cdn/business.rb +122 -0
  25. data/lib/conversant/v3/services/cdn/certificate.rb +180 -0
  26. data/lib/conversant/v3/services/cdn/dashboard.rb +109 -0
  27. data/lib/conversant/v3/services/cdn/domain.rb +223 -0
  28. data/lib/conversant/v3/services/cdn/monitoring.rb +65 -0
  29. data/lib/conversant/v3/services/cdn/partner/analytics.rb +233 -0
  30. data/lib/conversant/v3/services/cdn/partner.rb +60 -0
  31. data/lib/conversant/v3/services/cdn.rb +221 -0
  32. data/lib/conversant/v3/services/lms/dashboard.rb +99 -0
  33. data/lib/conversant/v3/services/lms/domain.rb +108 -0
  34. data/lib/conversant/v3/services/lms/job.rb +211 -0
  35. data/lib/conversant/v3/services/lms/partner/analytics.rb +266 -0
  36. data/lib/conversant/v3/services/lms/partner/business.rb +151 -0
  37. data/lib/conversant/v3/services/lms/partner/report.rb +170 -0
  38. data/lib/conversant/v3/services/lms/partner.rb +58 -0
  39. data/lib/conversant/v3/services/lms/preset.rb +57 -0
  40. data/lib/conversant/v3/services/lms.rb +173 -0
  41. data/lib/conversant/v3/services/oss/partner/analytics.rb +105 -0
  42. data/lib/conversant/v3/services/oss/partner.rb +48 -0
  43. data/lib/conversant/v3/services/oss.rb +128 -0
  44. data/lib/conversant/v3/services/portal/dashboard.rb +114 -0
  45. data/lib/conversant/v3/services/portal.rb +219 -0
  46. data/lib/conversant/v3/services/vms/analytics.rb +114 -0
  47. data/lib/conversant/v3/services/vms/business.rb +190 -0
  48. data/lib/conversant/v3/services/vms/partner/analytics.rb +133 -0
  49. data/lib/conversant/v3/services/vms/partner/business.rb +90 -0
  50. data/lib/conversant/v3/services/vms/partner.rb +57 -0
  51. data/lib/conversant/v3/services/vms/transcoding.rb +184 -0
  52. data/lib/conversant/v3/services/vms.rb +166 -0
  53. data/lib/conversant/v3.rb +36 -0
  54. data/lib/conversant/version.rb +5 -0
  55. data/lib/conversant.rb +108 -0
  56. data/publish.sh +107 -0
  57. data/sig/conversant/v3/services/authorization.rbs +34 -0
  58. data/sig/conversant/v3/services/cdn.rbs +123 -0
  59. data/sig/conversant/v3/services/lms.rbs +80 -0
  60. data/sig/conversant/v3/services/portal.rbs +22 -0
  61. data/sig/conversant/v3/services/vms.rbs +64 -0
  62. data/sig/conversant/v3.rbs +85 -0
  63. data/sig/conversant.rbs +37 -0
  64. metadata +267 -0
data/README.md ADDED
@@ -0,0 +1,860 @@
1
+ # Conversant Ruby Gem
2
+
3
+ A Ruby client library for interacting with Conversant/SwiftFederation CDN services, providing clean interfaces for Portal, CDN, and LMS APIs with V3 authentication support.
4
+
5
+ ## Features
6
+
7
+ - **Zero Configuration** - Automatically uses existing CONVERSANT environment variables
8
+ - **V3 SSO Authentication** - Handles complex authentication flow with session management
9
+ - **Service-Oriented Architecture** - Separate classes for Portal, CDN, LMS, VMS, and OSS services
10
+ - **Clean Service Structure** - Each service organized with focused sub-services (analytics, domain, dashboard, etc.)
11
+ - **79 API Methods** - Complete coverage across 4 main services (CDN: 46, LMS: 19, VMS: 9, Portal: 5)
12
+ - **Comprehensive CDN Management** - Full suite of CDN operations including domains, certificates, analytics
13
+ - **Inheritance-Friendly** - Easy to extend with your custom business logic
14
+ - **Redis Session Caching** - Automatic session management with configurable TTL
15
+ - **Thread-Safe** - Proper cookie jar management for concurrent requests
16
+ - **Drop-in Replacement** - Works with existing `Utils::Conversant::V3::Private` classes
17
+ - **YARD Documentation** - Complete API documentation with examples
18
+ - **RBS Type Signatures** - Full type coverage for better IDE support
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem 'conversant'
26
+ ```
27
+
28
+ And then execute:
29
+
30
+ ```bash
31
+ $ bundle install
32
+ ```
33
+
34
+ Or install it yourself as:
35
+
36
+ ```bash
37
+ $ gem install conversant
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### Zero Configuration (If ENV Variables Already Set)
43
+
44
+ If you're already using the CONVERSANT system, the gem works immediately:
45
+
46
+ ```ruby
47
+ require 'conversant'
48
+
49
+ # No configuration needed! The gem automatically uses:
50
+ # - ENV['PRIVATE_CDN_ENDPOINT']
51
+ # - ENV['PRIVATE_LMS_ENDPOINT']
52
+ # - ENV['SWIFTSERVE_IDENTIFIER_ID']
53
+ # - ENV['SWIFTSERVE_IDENTIFIER_HASH']
54
+ # - All other CONVERSANT ENV variables
55
+
56
+ # Just start using it:
57
+ portal = Conversant::V3.portal(customer_id)
58
+ cdn = Conversant::V3.cdn(customer_id)
59
+ lms = Conversant::V3.lms(customer_id)
60
+ vms = Conversant::V3.vms(customer_id)
61
+ oss = Conversant::V3.oss(customer_id)
62
+ ```
63
+
64
+ ## Configuration
65
+
66
+ ### Environment Variables
67
+
68
+ The gem automatically uses these CONVERSANT environment variables:
69
+
70
+ | Variable | Description | Default | Required |
71
+ |------------------------------|---------------------------------|----------------------------------|----------|
72
+ | `PORTAL_ROOT_HOSTNAME` | Portal hostname | `console.swiftfederation.com` | No |
73
+ | `PORTAL_SSO_HOSTNAME` | SSO hostname | `sso.swiftfederation.com` | No |
74
+ | `PRIVATE_PORTAL_ENDPOINT` | Portal API endpoint | `https://{PORTAL_ROOT_HOSTNAME}` | No |
75
+ | `PRIVATE_SSO_ENDPOINT` | SSO endpoint | `https://{PORTAL_SSO_HOSTNAME}` | No |
76
+ | `PRIVATE_CDN_ENDPOINT` | CDN API endpoint | - | Yes |
77
+ | `PRIVATE_LMS_ENDPOINT` | LMS API endpoint | - | Yes |
78
+ | `PRIVATE_VMS_ENDPOINT` | VMS API endpoint | - | No |
79
+ | `PRIVATE_OSS_ENDPOINT` | OSS API endpoint | - | No |
80
+ | `CONVERSANT_CDN_API_URL` | CDN API URL for http_code | - | No |
81
+ | `SWIFTSERVE_IDENTIFIER_ID` | Authentication ID | - | Yes |
82
+ | `SWIFTSERVE_IDENTIFIER_HASH` | Authentication hash | - | Yes |
83
+ | `DEFAULT_UA` | User agent string | Mozilla/5.0... | No |
84
+ | `DEFAULT_CONTENT_TYPE` | Content type header | `application/json` | No |
85
+ | `CONVERSANT_DEBUG` | Enable debug logging | `false` | No |
86
+ | `CONVERSANT_CACHE_TTL` | Session cache TTL (seconds) | `1200` | No |
87
+ | `REDIS_URL` | Redis connection URL | - | No* |
88
+ | `RAILS_ENV` | Rails environment (affects SSL) | - | No |
89
+
90
+ *Redis is auto-detected from `$redis` global or `ENV['REDIS_URL']`.
91
+
92
+ ### Auto-Configuration (With Validation)
93
+
94
+ To ensure all required variables are present:
95
+
96
+ ```ruby
97
+ # In config/initializers/conversant.rb (Rails)
98
+ require 'conversant'
99
+
100
+ # Validate that all required ENV variables are set
101
+ Conversant.auto_configure!
102
+ ```
103
+
104
+ ### Manual Configuration
105
+
106
+ Override specific settings if needed:
107
+
108
+ ```ruby
109
+ Conversant.configure do |config|
110
+ # Override only what you need
111
+ config.cache_ttl = 3600 # 1 hour instead of default 20 minutes
112
+ config.logger = Rails.logger
113
+ config.debug_mode = true
114
+ end
115
+ ```
116
+
117
+ ## Usage
118
+
119
+ ### Basic Usage
120
+
121
+ ```ruby
122
+ require 'conversant'
123
+
124
+ # Initialize services
125
+ customer_id = 12345
126
+ cdn = Conversant::V3.cdn(customer_id)
127
+ lms = Conversant::V3.lms(customer_id)
128
+ vms = Conversant::V3.vms(customer_id)
129
+ ```
130
+
131
+ ### CDN Domain Management
132
+
133
+ ```ruby
134
+ # List all domains
135
+ domains = cdn.domain.all
136
+ domains.each do |domain|
137
+ puts "Domain: #{domain.name} (ID: #{domain.id})"
138
+ puts " Type: #{domain.businessScenarioType == 1 ? 'CDN' : 'Storage'}"
139
+ puts " Status: #{domain.status == 1 ? 'Active' : 'Inactive'}"
140
+ puts " Usage: #{domain.current_disk_usage / 1_073_741_824.0} GB"
141
+ end
142
+
143
+ # Find specific domain
144
+ domain = cdn.domain.find_by(name: 'cdn.example.com')
145
+ if domain
146
+ puts "Found domain: #{domain.name} with ID: #{domain.id}"
147
+ end
148
+
149
+ # Create new CDN domain
150
+ domain_id = cdn.domain.create({
151
+ businessScenarioType: 1,
152
+ name: "cdn.example.com",
153
+ origins: [{ url_prefix: "203.0.113.10" }],
154
+ redirect_http_to_https: true,
155
+ http2_enabled: true
156
+ })
157
+ puts "Created domain with ID: #{domain_id}" if domain_id
158
+ ```
159
+
160
+ ### CDN Analytics & Reporting
161
+
162
+ ```ruby
163
+ # Get bandwidth usage for the current month
164
+ require 'date'
165
+ start_time = Date.today.beginning_of_month.strftime("%Y-%m-%dT00:00:00Z")
166
+ end_time = Date.today.end_of_month.strftime("%Y-%m-%dT23:59:59Z")
167
+
168
+ bandwidth = cdn.analytics.bandwidths({
169
+ startTime: start_time,
170
+ endTime: end_time,
171
+ pageSize: 1000
172
+ })
173
+
174
+ total_bandwidth = bandwidth.sum { |b| b['bandwidth'] || 0 }
175
+ puts "Total bandwidth this month: #{total_bandwidth / 1_099_511_627_776.0} TB"
176
+
177
+ # Get 95th percentile for billing
178
+ bandwidth_95th = cdn.business.bandwidth95th(year: 2025)
179
+ annual_95th = bandwidth_95th.map { |m| m['bandwidth_95th'] }.max
180
+ puts "Annual 95th percentile: #{annual_95th / 1_000_000.0} Mbps"
181
+
182
+ # Top URLs analysis
183
+ top_urls = cdn.analytics.top_urls({
184
+ startTime: start_time,
185
+ endTime: end_time,
186
+ limit: 10
187
+ })
188
+
189
+ puts "Top 10 URLs:"
190
+ top_urls.each_with_index do |url, i|
191
+ puts " #{i+1}. #{url['url']} - #{url['hits']} hits"
192
+ end
193
+ ```
194
+
195
+ ### Certificate Management
196
+
197
+ ```ruby
198
+ # List all certificates
199
+ certificates = cdn.certificate.all
200
+ certificates.each do |cert|
201
+ puts "Certificate: #{cert['name']}"
202
+ puts " Status: #{cert['status']}"
203
+ puts " Expires: #{cert['expiry_date']}"
204
+ puts " Domains: #{cert['domains']&.join(', ')}"
205
+ end
206
+
207
+ # Deploy Let's Encrypt certificate
208
+ success = cdn.certificate.deploy_auto_certificate(12345, "example.com", {
209
+ enable: true,
210
+ domains: ["example.com", "www.example.com"],
211
+ validation_method: "http",
212
+ auto_renewal: true
213
+ })
214
+
215
+ if success
216
+ puts "Auto-certificate deployed successfully"
217
+ else
218
+ puts "Failed to deploy auto-certificate"
219
+ end
220
+ ```
221
+
222
+ ### Monitoring & Alerts
223
+
224
+ ```ruby
225
+ # Monitor domain health
226
+ domain_list = cdn.monitoring.delivery_domain_list
227
+ domain_list.each do |domain|
228
+ if domain['status'] != 'healthy'
229
+ puts "Alert: Domain #{domain['name']} status is #{domain['status']}"
230
+ end
231
+ end
232
+
233
+ # Get detailed monitoring for specific domain
234
+ domain_detail = cdn.monitoring.delivery_domain_detail(domain_id)
235
+ if domain_detail
236
+ puts "Domain: #{domain_detail['name']}"
237
+ puts " Response Time: #{domain_detail['response_time']}ms"
238
+ puts " Cache Hit Rate: #{domain_detail['cache_hit_rate']}%"
239
+ puts " Error Rate: #{domain_detail['error_rate']}%"
240
+ end
241
+ ```
242
+
243
+ ### Audit Logging
244
+
245
+ ```ruby
246
+ # Get audit logs for the last 24 hours
247
+ yesterday = (Time.now - 86400).strftime("%Y-%m-%dT%H:%M:%SZ")
248
+ now = Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")
249
+
250
+ audit_logs = cdn.audit.delivery_domain_operations({
251
+ startTime: yesterday,
252
+ endTime: now,
253
+ pageSize: 100
254
+ })
255
+
256
+ audit_logs.each do |log|
257
+ puts "[#{log['timestamp']}] #{log['action']} by #{log['user']}"
258
+ puts " Domain: #{log['domain_name']}"
259
+ puts " Details: #{log['details']}"
260
+ end
261
+ ```
262
+
263
+ ### Inheritance Pattern (Extend with Your Logic)
264
+
265
+ Create your own classes that inherit from the gem's services:
266
+
267
+ ```ruby
268
+ module Utils
269
+ module Conversant
270
+ module V3
271
+ class CDN < ::Conversant::V3::Services::CDN
272
+ # Add your custom methods
273
+ def daily_summary(date = Date.today)
274
+ start_time = date.strftime("%Y-%m-%dT00:00:00Z")
275
+ end_time = date.strftime("%Y-%m-%dT23:59:59Z")
276
+
277
+ {
278
+ bandwidth: analytics.bandwidths({startTime: start_time, endTime: end_time}),
279
+ volumes: analytics.volumes({startTime: start_time, endTime: end_time}),
280
+ spots: monitoring.spots({startTime: start_time, endTime: end_time})
281
+ }
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ # Use your extended class
289
+ cdn = Utils::Conversant::V3::CDN.new(customer_id)
290
+ summary = cdn.daily_summary # Your custom method
291
+ bandwidth = cdn.analytics.bandwidths(payload) # Parent's method
292
+ ```
293
+
294
+ ## Integration with Existing Code
295
+
296
+ ### Option 1: Drop-in Replacement for ConversantHttpClientV3
297
+
298
+ Replace your existing authentication module:
299
+
300
+ ```ruby
301
+ # app/models/concerns/conversant_http_client_v3.rb
302
+ require 'conversant'
303
+
304
+ Conversant.auto_configure! unless Conversant.configured?
305
+
306
+ module ConversantHttpClientV3
307
+ def self.included(base)
308
+ base.class_eval do
309
+ include ::Conversant::V3::Mixins::Authentication
310
+ use_conversant_auth!
311
+ end
312
+ end
313
+
314
+ def authenticate
315
+ conversant_authenticate
316
+ end
317
+
318
+ def signature
319
+ sessions = authenticate
320
+ sessions && sessions[:session]
321
+ end
322
+ end
323
+ ```
324
+
325
+ ### Option 2: Update Only Authorization Headers
326
+
327
+ Keep your existing classes, just update the auth:
328
+
329
+ ```ruby
330
+ class Utils::Conversant::V3::Private::Operation
331
+ def authorized_headers
332
+ # Only change this method - use gem's auth
333
+ ::Conversant::V3.portal(@customer_id).send(:authorized_headers)
334
+ end
335
+
336
+ # All your existing methods remain unchanged
337
+ def appliances(gte = nil, lte = nil)
338
+ # Your existing implementation
339
+ end
340
+ end
341
+ ```
342
+
343
+ ### Option 3: Using the Mixin
344
+
345
+ For classes that can't change inheritance:
346
+
347
+ ```ruby
348
+ class Utils::Conversant::V3::Private::Operation
349
+ include Conversant::V3::Mixins::Authentication
350
+ use_conversant_auth!
351
+
352
+ def initialize(customer_id, type = 2)
353
+ @customer_id = customer_id
354
+ @type = type
355
+ initialize_conversant_auth(customer_id, type)
356
+ end
357
+
358
+ def your_existing_method
359
+ headers = portal_authorized_headers # Use gem's auth
360
+ # Your existing logic...
361
+ end
362
+ end
363
+ ```
364
+
365
+ ## API Reference
366
+
367
+ ### Portal Service
368
+
369
+ ```ruby
370
+ portal = Conversant::V3.portal(customer_id)
371
+
372
+ # Get appliances
373
+ appliances = portal.appliances(start_date, end_date)
374
+ # Returns: Array of appliance hashes with ip, hostname, deleted, pop, volume, federation
375
+ ```
376
+
377
+ ### CDN Service
378
+
379
+ The CDN service provides comprehensive domain, certificate, analytics, and monitoring capabilities.
380
+
381
+ ```ruby
382
+ cdn = Conversant::V3.cdn(customer_id)
383
+
384
+ # Domain Management
385
+ domains = cdn.domain.all # Get all domains
386
+ domain = cdn.domain.find(domain_id) # Find by ID
387
+ domain = cdn.domain.find_by(name: 'example.com') # Find by name
388
+ total_usage = cdn.domain.total_current_disk_usage # Storage usage in bytes
389
+
390
+ # Create new domain
391
+ domain_id = cdn.domain.create({
392
+ businessScenarioType: 1, # 1=CDN, 2=Storage
393
+ name: "cdn.example.com",
394
+ origins: [{ url_prefix: "203.0.113.10" }],
395
+ redirect_http_to_https: true,
396
+ http2_enabled: true,
397
+ streaming_service: false,
398
+ disabled: false
399
+ })
400
+
401
+ # Certificate Management
402
+ certificates = cdn.certificate.all # List all certificates
403
+ cert_info = cdn.certificate.auto_certificate_info(cert_id, domain_name)
404
+
405
+ # Deploy Let's Encrypt certificate
406
+ success = cdn.certificate.deploy_auto_certificate(cert_id, domain_name, {
407
+ enable: true,
408
+ domains: ["example.com", "www.example.com"],
409
+ validation_method: "http",
410
+ auto_renewal: true
411
+ })
412
+
413
+ # Analytics
414
+ bandwidth = cdn.analytics.bandwidths({
415
+ startTime: "2025-01-01T00:00:00Z",
416
+ endTime: "2025-01-31T23:59:59Z",
417
+ pageSize: 1000,
418
+ pageNumber: 0
419
+ })
420
+
421
+ hits = cdn.analytics.hits({
422
+ startTime: start_time,
423
+ endTime: end_time,
424
+ groupBy: "hour"
425
+ })
426
+
427
+ status_codes = cdn.analytics.status_codes({
428
+ startTime: start_time,
429
+ endTime: end_time,
430
+ statusCode: "200,404,500"
431
+ })
432
+
433
+ top_urls = cdn.analytics.top_urls({
434
+ startTime: start_time,
435
+ endTime: end_time,
436
+ limit: 100
437
+ })
438
+
439
+ # Business Metrics (Billing)
440
+ usage = cdn.business.bandwidth({
441
+ startTime: "2025-01-01T00:00:00Z",
442
+ endTime: "2025-01-31T23:59:59Z",
443
+ pageSize: 1000
444
+ })
445
+
446
+ # Get 95th percentile bandwidth
447
+ bandwidth_95th = cdn.business.bandwidth95th(year: 2025)
448
+
449
+ # Monitoring
450
+ domain_list = cdn.monitoring.delivery_domain_list
451
+ domain_detail = cdn.monitoring.delivery_domain_detail(domain_id)
452
+ customer_details = cdn.monitoring.customer_details
453
+
454
+ # Audit Logs
455
+ audit_logs = cdn.audit.delivery_domain_operations({
456
+ startTime: start_time,
457
+ endTime: end_time,
458
+ pageSize: 50
459
+ })
460
+ ```
461
+
462
+ ### LMS Service (Live Media Streaming)
463
+
464
+ ```ruby
465
+ lms = Conversant::V3.lms(customer_id)
466
+
467
+ # Job Management - Query streaming jobs
468
+ jobs = lms.job.where(
469
+ page_number: 1,
470
+ page_size: 50,
471
+ status: 'active'
472
+ )
473
+
474
+ jobs.each do |job|
475
+ puts "Job #{job['id']}: #{job['name']}"
476
+ puts " Status: #{job['status']}"
477
+ puts " Created: #{job['created_at']}"
478
+ end
479
+
480
+ # Domain Management
481
+ domains = lms.domain.all(page_number: 1, page_size: 50)
482
+ domains.each do |domain|
483
+ puts "Domain: #{domain['name']} (ID: #{domain['id']})"
484
+ end
485
+
486
+ # Get specific domain details
487
+ domain = lms.domain.show(domain_id)
488
+
489
+ # Create streaming domain
490
+ domain_id = lms.domain.create({
491
+ name: "stream.example.com",
492
+ type: "live",
493
+ protocol: "rtmp"
494
+ })
495
+
496
+ # Update streaming domain
497
+ lms.domain.update({
498
+ id: domain_id,
499
+ name: "updated-stream.example.com"
500
+ })
501
+
502
+ # Delete streaming domain
503
+ lms.domain.delete(domain_id)
504
+
505
+ # Dashboard Metrics
506
+ live_duration = lms.dashboard.live
507
+ vod_duration = lms.dashboard.vod
508
+ dvr_duration = lms.dashboard.dvr
509
+ recent_jobs = lms.dashboard.recent_jobs
510
+
511
+ # Transcoding Presets
512
+ presets = lms.preset.all
513
+ presets.each do |preset|
514
+ puts "Preset: #{preset['name']} - #{preset['resolution']}"
515
+ end
516
+ ```
517
+
518
+ ### VMS Service (Video Management System)
519
+
520
+ ```ruby
521
+ vms = Conversant::V3.vms(customer_id)
522
+
523
+ # Transcoding Jobs and Presets
524
+ jobs = vms.transcoding.jobs(page_size: 50, job_status: 2)
525
+ jobs.each do |job|
526
+ puts "Job #{job['id']}: #{job['file_name']} - Status: #{job['status']}"
527
+ end
528
+
529
+ # Get available transcoding presets
530
+ presets = vms.transcoding.presets(page_size: 50)
531
+ presets.each do |preset|
532
+ puts "Preset: #{preset['name']} - #{preset['description']}"
533
+ end
534
+
535
+ # Analytics - Transcoding duration and volume
536
+ duration = vms.analytics.transcoding({
537
+ startTime: "2025-01-01",
538
+ endTime: "2025-01-31"
539
+ })
540
+
541
+ volume = vms.analytics.volume({
542
+ startTime: "2025-01-01",
543
+ endTime: "2025-01-31"
544
+ })
545
+
546
+ # Business Metrics - Detailed transcoding breakdown
547
+ transcoding_breakdown = vms.business.transcoding({
548
+ startTime: Time.now.beginning_of_month
549
+ })
550
+ puts "SD: #{transcoding_breakdown[:vms_transcoding_sd]} minutes"
551
+ puts "HD: #{transcoding_breakdown[:vms_transcoding_hd]} minutes"
552
+ puts "UHD: #{transcoding_breakdown[:vms_transcoding_uhd]} minutes"
553
+ puts "Total: #{transcoding_breakdown[:vms_transcoding]} minutes"
554
+
555
+ # Duration and volume for billing
556
+ duration_metrics = vms.business.duration({
557
+ startTime: Time.now.beginning_of_month
558
+ })
559
+
560
+ volume_metrics = vms.business.volume({
561
+ startTime: Time.now.beginning_of_month
562
+ })
563
+ ```
564
+
565
+ ### OSS Service (Object Storage Service)
566
+
567
+ ```ruby
568
+ oss = Conversant::V3.oss(customer_id)
569
+
570
+ # Bucket operations
571
+ buckets = oss.list_buckets
572
+ bucket = oss.get_bucket(bucket_name)
573
+ oss.create_bucket(bucket_name, region: 'us-east-1')
574
+
575
+ # Object operations
576
+ objects = oss.list_objects(bucket_name, prefix: 'videos/')
577
+ object = oss.get_object(bucket_name, object_key)
578
+ oss.put_object(bucket_name, object_key, file_content)
579
+ oss.delete_object(bucket_name, object_key)
580
+
581
+ # Presigned URLs
582
+ url = oss.presigned_url(bucket_name, object_key, expires_in: 3600)
583
+ ```
584
+
585
+ ## Error Handling
586
+
587
+ ```ruby
588
+ begin
589
+ portal = Conversant::V3.portal(customer_id)
590
+ appliances = portal.appliances
591
+ rescue Conversant::AuthenticationError => e
592
+ # Handle authentication failures
593
+ puts "Authentication failed: #{e.message}"
594
+ rescue Conversant::ApiError => e
595
+ # Handle API errors
596
+ puts "API error: #{e.message}"
597
+ rescue Conversant::Error => e
598
+ # Handle general errors
599
+ puts "Error: #{e.message}"
600
+ end
601
+ ```
602
+
603
+ ## Migration Guide
604
+
605
+ ### From Existing Utils::Conversant::V3::Private
606
+
607
+ #### Phase 1: Authentication Only
608
+ 1. Add `gem 'conversant'` to Gemfile
609
+ 2. Replace `ConversantHttpClientV3` module with gem's wrapper
610
+ 3. Keep all business logic unchanged
611
+
612
+ #### Phase 2: Gradual Migration (Optional)
613
+ - Migrate services one by one
614
+ - Start with least critical service
615
+ - Keep custom business logic where needed
616
+
617
+ #### Phase 3: Full Integration (Optional)
618
+ - Use inheritance pattern for all services
619
+ - Add custom methods as needed
620
+
621
+ ### Rollback Plan
622
+
623
+ If you need to rollback:
624
+ 1. Restore original `ConversantHttpClientV3` module
625
+ 2. Remove gem from Gemfile
626
+ 3. No changes needed to business logic
627
+
628
+ ## Authentication Architecture
629
+
630
+ The gem implements a multi-tier authentication system with automatic session management using a consistent Authorization module pattern across all services.
631
+
632
+ ### Authentication Flow
633
+
634
+ 1. **Root Authentication**:
635
+ - Logs into SSO with master credentials (SWIFTSERVE_IDENTIFIER_ID/HASH)
636
+ - Obtains SESSION and SSO_GW_SESSION2 cookies
637
+ - Cached in Redis with TTL management
638
+
639
+ 2. **Service-Specific Sessions**:
640
+ All services follow the same authentication pattern via the Authorization module:
641
+ - **Portal**: Exchanges root sessions for customer-specific SESSION cookie
642
+ - **CDN**: Exchanges root sessions for customer-specific SESSION cookie
643
+ - **LMS**: Exchanges root sessions for Java-based JSESSIONID cookie
644
+ - **VMS**: Exchanges root sessions for Java-based JSESSIONID cookie
645
+ - **OSS**: Uses root sessions with S3-compatible authentication
646
+
647
+ 3. **Authorization Module Pattern**:
648
+ Each service implements the Authorization module which provides:
649
+ - Automatic session fetching and caching
650
+ - Session validation before API calls
651
+ - Consistent error handling
652
+ - Redis-based session storage
653
+
654
+ ### Session Caching
655
+
656
+ All sessions are cached in Redis with automatic refresh using a standardized key format:
657
+
658
+ ```ruby
659
+ # Sessions are cached with these keys:
660
+ "CONVERSANT.V3.PORTAL.SESSION.{customer_id}" # Portal SESSION cookie
661
+ "CONVERSANT.V3.PORTAL.SSO_GW_SESSION2.{customer_id}" # SSO session (shared)
662
+ "CONVERSANT.V3.CDN.SESSION.{customer_id}" # CDN SESSION cookie
663
+ "CONVERSANT.V3.LMS.JSESSIONID.{customer_id}" # LMS JSESSIONID cookie
664
+ "CONVERSANT.V3.VMS.JSESSIONID.{customer_id}" # VMS JSESSIONID cookie
665
+
666
+ # Default TTL: 20 minutes (configurable)
667
+ ```
668
+
669
+ ### Session Validation
670
+
671
+ All services automatically validate session cookies before making API calls:
672
+
673
+ ```ruby
674
+ # Each service checks for its required cookie before making requests:
675
+ # - Portal, CDN: Validates SESSION cookie presence
676
+ # - LMS, VMS: Validates JSESSIONID cookie presence
677
+ # - If missing, automatically fetches new session
678
+ # - If fetch fails, raises AuthenticationError
679
+ ```
680
+
681
+ ### Using Custom Authentication
682
+
683
+ If you need access to raw authentication headers:
684
+
685
+ ```ruby
686
+ # Get authorized headers for direct API calls
687
+ cdn = Conversant::V3.cdn(customer_id)
688
+ headers = cdn.send(:authorized_headers)
689
+
690
+ # Make custom API call
691
+ response = RestClient.get("#{cdn_endpoint}/custom-endpoint", headers)
692
+ ```
693
+
694
+ ## Development
695
+
696
+ See [DEVELOPER_GUIDE.md](DEVELOPER_GUIDE.md) for detailed information on:
697
+ - Building and testing the gem
698
+ - Publishing to RubyGems
699
+ - Version management
700
+ - Documentation generation
701
+ - GitLab CI/CD setup
702
+ - Troubleshooting
703
+
704
+ Quick start:
705
+ ```bash
706
+ bundle install # Install dependencies
707
+ bundle exec rspec # Run tests
708
+ bundle exec yard doc # Generate documentation
709
+ ./publish.sh # Publish to RubyGems
710
+ ```
711
+
712
+ ## Debugging
713
+
714
+ Enable debug mode for verbose logging:
715
+
716
+ ```ruby
717
+ Conversant.configure do |config|
718
+ config.debug_mode = true
719
+ config.logger = Logger.new($stdout)
720
+ end
721
+ ```
722
+
723
+ ## Examples
724
+
725
+ See the `examples/` directory for:
726
+ - `inheritance_integration.rb` - Complete inheritance patterns
727
+ - `rails_initializer.rb` - Rails setup example
728
+
729
+ ## Troubleshooting
730
+
731
+ ### Common Issues
732
+
733
+ #### Authentication Errors
734
+ ```ruby
735
+ # Error: Conversant::AuthenticationError
736
+ # Solution: Check environment variables
737
+ ENV['SWIFTSERVE_IDENTIFIER_ID'] # Must be set
738
+ ENV['SWIFTSERVE_IDENTIFIER_HASH'] # Must be set
739
+ ENV['PRIVATE_CDN_ENDPOINT'] # Must be set
740
+ ENV['PRIVATE_LMS_ENDPOINT'] # Must be set
741
+
742
+ # Clear cache if credentials changed
743
+ redis.del("CONVERSANT.V3.PORTAL.SESSION.#{customer_id}")
744
+ redis.del("CONVERSANT.V3.PORTAL.SSO_GW_SESSION2.#{customer_id}")
745
+ ```
746
+
747
+ #### Redis Connection Issues
748
+ ```ruby
749
+ # Error: Redis::CannotConnectError
750
+ # Solution: Configure Redis properly
751
+ Conversant.configure do |config|
752
+ config.redis = Redis.new(url: ENV['REDIS_URL'])
753
+ end
754
+
755
+ # Or use global $redis
756
+ $redis = Redis.new(url: ENV['REDIS_URL'])
757
+ ```
758
+
759
+ #### Domain Creation Failures
760
+ ```ruby
761
+ # Common issues:
762
+ # 1. Domain name already exists
763
+ # 2. Invalid origin configuration
764
+ # 3. Missing FTP password for storage domains (businessScenarioType: 2)
765
+
766
+ # Check response for details:
767
+ domain_id = cdn.domain.create(payload)
768
+ if domain_id.nil?
769
+ # Check logs for error details
770
+ # Enable debug mode for more info
771
+ Conversant.configure { |c| c.debug_mode = true }
772
+ end
773
+ ```
774
+
775
+ #### Certificate Deployment Issues
776
+ ```ruby
777
+ # Let's Encrypt validation failures:
778
+ # 1. Domain must be publicly accessible
779
+ # 2. HTTP validation requires port 80 open
780
+ # 3. DNS validation requires DNS control
781
+
782
+ # Check certificate status:
783
+ cert_info = cdn.certificate.auto_certificate_info(cert_id, domain)
784
+ puts cert_info['validation_status'] # Should be 'valid'
785
+ puts cert_info['error_message'] # If failed
786
+ ```
787
+
788
+ ### Debug Mode
789
+
790
+ Enable detailed logging for troubleshooting:
791
+
792
+ ```ruby
793
+ Conversant.configure do |config|
794
+ config.debug_mode = true
795
+ config.logger = Logger.new($stdout)
796
+ config.log_level = :debug
797
+ end
798
+
799
+ # This will log:
800
+ # - All API requests and responses
801
+ # - Authentication attempts
802
+ # - Session cache hits/misses
803
+ # - Error details with stack traces
804
+ ```
805
+
806
+ ### Performance Tips
807
+
808
+ 1. **Use Redis connection pooling**:
809
+ ```ruby
810
+ require 'connection_pool'
811
+
812
+ redis_pool = ConnectionPool.new(size: 5) { Redis.new }
813
+ Conversant.configure do |config|
814
+ config.redis = redis_pool
815
+ end
816
+ ```
817
+
818
+ 2. **Batch API calls when possible**:
819
+ ```ruby
820
+ # Instead of multiple calls:
821
+ domains.each { |d| cdn.domain.find(d.id) }
822
+
823
+ # Use single call with filtering:
824
+ all_domains = cdn.domain.all
825
+ my_domains = all_domains.select { |d| domain_ids.include?(d.id) }
826
+ ```
827
+
828
+ 3. **Increase cache TTL for stable data**:
829
+ ```ruby
830
+ Conversant.configure do |config|
831
+ config.cache_ttl = 3600 # 1 hour for stable environments
832
+ end
833
+ ```
834
+
835
+ ## Version Notes
836
+
837
+ ### Latest Release: 1.0.10 (2025-09-30)
838
+
839
+ **Documentation Update**: Enhanced documentation for v1.0.9 critical fixes
840
+
841
+ ### Version 1.0.9 - Critical Bug Fix
842
+
843
+ **Fixed authentication issues with LMS and VMS services:**
844
+
845
+ - ✅ Fixed JSESSIONID authentication for LMS service (resolves "Missing JSESSIONID" error)
846
+ - ✅ Fixed JSESSIONID authentication for VMS service
847
+ - ✅ Improved RestClient cookie handling (switched from manual `'Cookie'` header to `:cookies` option)
848
+ - ✅ Fixed method visibility issues in Authorization module
849
+
850
+ **Upgrade recommended** if you're using LMS or VMS services. CDN and Portal services are unaffected.
851
+
852
+ See [CHANGELOG.md](CHANGELOG.md) for complete version history.
853
+
854
+ ## Contributing
855
+
856
+ Bug reports and pull requests are welcome on GitLab at https://gitlab.vnetwork.dev/gems/conversant.
857
+
858
+ ## License
859
+
860
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).