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.
- checksums.yaml +7 -0
- data/.env.example +39 -0
- data/.gitignore +52 -0
- data/.gitlab-ci.yml +108 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +487 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +860 -0
- data/RELEASE.md +726 -0
- data/Rakefile +21 -0
- data/conversant.gemspec +49 -0
- data/examples/inheritance_integration.rb +348 -0
- data/examples/rails_initializer.rb +69 -0
- data/lib/conversant/configuration.rb +132 -0
- data/lib/conversant/v3/base.rb +47 -0
- data/lib/conversant/v3/http_client.rb +456 -0
- data/lib/conversant/v3/mixins/authentication.rb +221 -0
- data/lib/conversant/v3/services/authorization.rb +194 -0
- data/lib/conversant/v3/services/cdn/analytics.rb +483 -0
- data/lib/conversant/v3/services/cdn/audit.rb +71 -0
- data/lib/conversant/v3/services/cdn/business.rb +122 -0
- data/lib/conversant/v3/services/cdn/certificate.rb +180 -0
- data/lib/conversant/v3/services/cdn/dashboard.rb +109 -0
- data/lib/conversant/v3/services/cdn/domain.rb +223 -0
- data/lib/conversant/v3/services/cdn/monitoring.rb +65 -0
- data/lib/conversant/v3/services/cdn/partner/analytics.rb +233 -0
- data/lib/conversant/v3/services/cdn/partner.rb +60 -0
- data/lib/conversant/v3/services/cdn.rb +221 -0
- data/lib/conversant/v3/services/lms/dashboard.rb +99 -0
- data/lib/conversant/v3/services/lms/domain.rb +108 -0
- data/lib/conversant/v3/services/lms/job.rb +211 -0
- data/lib/conversant/v3/services/lms/partner/analytics.rb +266 -0
- data/lib/conversant/v3/services/lms/partner/business.rb +151 -0
- data/lib/conversant/v3/services/lms/partner/report.rb +170 -0
- data/lib/conversant/v3/services/lms/partner.rb +58 -0
- data/lib/conversant/v3/services/lms/preset.rb +57 -0
- data/lib/conversant/v3/services/lms.rb +173 -0
- data/lib/conversant/v3/services/oss/partner/analytics.rb +105 -0
- data/lib/conversant/v3/services/oss/partner.rb +48 -0
- data/lib/conversant/v3/services/oss.rb +128 -0
- data/lib/conversant/v3/services/portal/dashboard.rb +114 -0
- data/lib/conversant/v3/services/portal.rb +219 -0
- data/lib/conversant/v3/services/vms/analytics.rb +114 -0
- data/lib/conversant/v3/services/vms/business.rb +190 -0
- data/lib/conversant/v3/services/vms/partner/analytics.rb +133 -0
- data/lib/conversant/v3/services/vms/partner/business.rb +90 -0
- data/lib/conversant/v3/services/vms/partner.rb +57 -0
- data/lib/conversant/v3/services/vms/transcoding.rb +184 -0
- data/lib/conversant/v3/services/vms.rb +166 -0
- data/lib/conversant/v3.rb +36 -0
- data/lib/conversant/version.rb +5 -0
- data/lib/conversant.rb +108 -0
- data/publish.sh +107 -0
- data/sig/conversant/v3/services/authorization.rbs +34 -0
- data/sig/conversant/v3/services/cdn.rbs +123 -0
- data/sig/conversant/v3/services/lms.rbs +80 -0
- data/sig/conversant/v3/services/portal.rbs +22 -0
- data/sig/conversant/v3/services/vms.rbs +64 -0
- data/sig/conversant/v3.rbs +85 -0
- data/sig/conversant.rbs +37 -0
- metadata +267 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'authorization'
|
|
4
|
+
|
|
5
|
+
module Conversant
|
|
6
|
+
module V3
|
|
7
|
+
module Services
|
|
8
|
+
# Portal service for Conversant/SwiftFederation administration
|
|
9
|
+
#
|
|
10
|
+
# Provides access to portal functionality including appliance management
|
|
11
|
+
# and infrastructure monitoring.
|
|
12
|
+
#
|
|
13
|
+
# @example Basic usage
|
|
14
|
+
# portal = Conversant::V3.portal(12345)
|
|
15
|
+
#
|
|
16
|
+
# # Get appliances for current month
|
|
17
|
+
# appliances = portal.appliances
|
|
18
|
+
#
|
|
19
|
+
# # Get appliances for specific date range
|
|
20
|
+
# appliances = portal.appliances('2025-01-01T00:00:00Z', '2025-01-31T23:59:59Z')
|
|
21
|
+
#
|
|
22
|
+
# @since 1.0.0
|
|
23
|
+
class Portal < ::Conversant::V3::Base
|
|
24
|
+
include Authorization
|
|
25
|
+
|
|
26
|
+
# Redis key prefix for caching appliance data
|
|
27
|
+
MASTER_APPLIANCE_REDIS_KEY = 'CONVERSANT.V3.PORTAL.APPLIANCE.ITEMS'
|
|
28
|
+
|
|
29
|
+
# Retrieves appliance data for a specified date range
|
|
30
|
+
#
|
|
31
|
+
# Returns information about appliances (CDN nodes) including their IP addresses,
|
|
32
|
+
# hostnames, locations (POP), traffic volume, and federation volume. Results are
|
|
33
|
+
# cached in Redis for 10 minutes to improve performance.
|
|
34
|
+
#
|
|
35
|
+
# @param gte [String, nil] Start date/time in ISO 8601 format (defaults to beginning of current month)
|
|
36
|
+
# @param lte [String, nil] End date/time in ISO 8601 format (defaults to end of current month)
|
|
37
|
+
#
|
|
38
|
+
# @return [Array<Hash>] Array of appliance hashes with keys:
|
|
39
|
+
# - :ip [String] IP address of the appliance
|
|
40
|
+
# - :hostname [String] Hostname of the appliance
|
|
41
|
+
# - :deleted [Boolean] Whether the appliance has been deleted
|
|
42
|
+
# - :pop [String] Point of Presence (datacenter location)
|
|
43
|
+
# - :volume [Integer] Traffic volume in bytes
|
|
44
|
+
# - :federation [Integer] Federation traffic volume in bytes
|
|
45
|
+
#
|
|
46
|
+
# @example Get appliances for current month
|
|
47
|
+
# appliances = portal.appliances
|
|
48
|
+
# appliances.each do |appliance|
|
|
49
|
+
# puts "#{appliance[:hostname]} (#{appliance[:ip]}) - #{appliance[:pop]}"
|
|
50
|
+
# puts " Volume: #{appliance[:volume]} bytes"
|
|
51
|
+
# puts " Federation: #{appliance[:federation]} bytes"
|
|
52
|
+
# end
|
|
53
|
+
#
|
|
54
|
+
# @example Get appliances for specific date range
|
|
55
|
+
# start_date = '2025-01-01T00:00:00Z'
|
|
56
|
+
# end_date = '2025-01-31T23:59:59Z'
|
|
57
|
+
# appliances = portal.appliances(start_date, end_date)
|
|
58
|
+
#
|
|
59
|
+
# @since 1.0.0
|
|
60
|
+
def appliances(gte = nil, lte = nil)
|
|
61
|
+
today = Date.today.to_datetime
|
|
62
|
+
|
|
63
|
+
gte ||= today.beginning_of_month.strftime('%Y-%m-%dT00:00:00Z')
|
|
64
|
+
lte ||= today.end_of_month.strftime('%Y-%m-%dT23:59:59Z')
|
|
65
|
+
|
|
66
|
+
key = "#{MASTER_APPLIANCE_REDIS_KEY}.#{gte.to_datetime&.strftime('%Y%m')}"
|
|
67
|
+
|
|
68
|
+
items = redis.get(key)
|
|
69
|
+
|
|
70
|
+
if items.nil?
|
|
71
|
+
logger.debug "#{identifier}.METHOD:appliances.FETCHING_DATA"
|
|
72
|
+
|
|
73
|
+
payload = {
|
|
74
|
+
startTime: gte,
|
|
75
|
+
endTime: lte
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
response = JSON.parse(call('POST', '/load_appliance_data', payload))
|
|
79
|
+
|
|
80
|
+
items = response&.[]('applianceList')&.map do |item|
|
|
81
|
+
{
|
|
82
|
+
ip: item['ip'],
|
|
83
|
+
hostname: item['hostname'],
|
|
84
|
+
deleted: item['deleted'],
|
|
85
|
+
pop: item['pop'],
|
|
86
|
+
volume: item['volume'],
|
|
87
|
+
federation: item['federationVolume'],
|
|
88
|
+
}
|
|
89
|
+
end.to_json
|
|
90
|
+
|
|
91
|
+
redis.set(key, items, ex: 600)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
JSON.parse(items)
|
|
95
|
+
rescue StandardError => e
|
|
96
|
+
logger.error "#{identifier}.METHOD:appliances.ERROR:#{e.message}"
|
|
97
|
+
[]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Get dashboard service instance
|
|
101
|
+
#
|
|
102
|
+
# @return [Dashboard] dashboard service for customer metadata and reporting
|
|
103
|
+
# @since 1.0.8
|
|
104
|
+
def dashboard
|
|
105
|
+
@dashboard ||= Dashboard.new(self)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
protected
|
|
109
|
+
|
|
110
|
+
# Makes an authenticated API call to the Portal service
|
|
111
|
+
#
|
|
112
|
+
# Validates SESSION cookie presence before making the request and handles
|
|
113
|
+
# HTTP errors appropriately.
|
|
114
|
+
#
|
|
115
|
+
# @param method [String] HTTP method ('GET', 'POST', etc.)
|
|
116
|
+
# @param uri [String] API endpoint URI (relative to portal_endpoint)
|
|
117
|
+
# @param payload [Hash, nil] Request payload for POST/PUT requests
|
|
118
|
+
#
|
|
119
|
+
# @return [String] Response body
|
|
120
|
+
#
|
|
121
|
+
# @raise [AuthenticationError] if SESSION cookie is missing
|
|
122
|
+
# @raise [ApiError] if HTTP response code is 400 or higher
|
|
123
|
+
def call(method, uri, payload = nil)
|
|
124
|
+
url = "#{portal_endpoint}#{uri}"
|
|
125
|
+
|
|
126
|
+
headers = authorized_headers
|
|
127
|
+
|
|
128
|
+
# Check for SESSION in Cookie header
|
|
129
|
+
if headers['Cookie'].nil? || !headers['Cookie'].include?('SESSION=')
|
|
130
|
+
logger.error "#{identifier}.METHOD:call.NO_SESSION"
|
|
131
|
+
raise AuthenticationError, 'Missing SESSION for Portal'
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
code, response = request(method, url, payload, headers)
|
|
135
|
+
|
|
136
|
+
if code >= 400
|
|
137
|
+
logger.error "#{identifier}.METHOD:call.HTTP_ERROR:#{code}"
|
|
138
|
+
raise ApiError, "Portal API error: #{code}"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
response.body
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
# Fetches a new SESSION cookie for Portal API access
|
|
147
|
+
#
|
|
148
|
+
# Authenticates with root portal sessions (SESSION + SSO_GW_SESSION2) and
|
|
149
|
+
# exchanges them for a customer-specific SESSION cookie. The new session
|
|
150
|
+
# is cached in Redis with the configured TTL.
|
|
151
|
+
#
|
|
152
|
+
# @return [String, nil] The SESSION cookie value, or nil if authentication fails
|
|
153
|
+
def fetch_new_session
|
|
154
|
+
sessions = authenticate
|
|
155
|
+
return nil unless sessions && sessions[:session] && sessions[:sso_gw_session2]
|
|
156
|
+
|
|
157
|
+
logger.debug "#{identifier}.METHOD:authorize.REQUESTING_SESSION"
|
|
158
|
+
|
|
159
|
+
response = RestClient.get(
|
|
160
|
+
"#{portal_endpoint}/?cId=#{customer_id}",
|
|
161
|
+
{
|
|
162
|
+
authority: URI.parse(portal_endpoint).hostname,
|
|
163
|
+
referer: portal_endpoint,
|
|
164
|
+
user_agent: configuration.default_ua,
|
|
165
|
+
cookies: {
|
|
166
|
+
'SESSION': sessions[:session],
|
|
167
|
+
'SSO_GW_SESSION2': sessions[:sso_gw_session2]
|
|
168
|
+
},
|
|
169
|
+
timeout: 30,
|
|
170
|
+
open_timeout: 30
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if response.cookies['SESSION']
|
|
175
|
+
session_cookie = response.cookies['SESSION']
|
|
176
|
+
redis.set(session_cache_key, session_cookie, ex: configuration.cache_ttl)
|
|
177
|
+
logger.debug "#{identifier}.METHOD:authorize.SESSION_OBTAINED"
|
|
178
|
+
session_cookie
|
|
179
|
+
else
|
|
180
|
+
logger.error "#{identifier}.METHOD:authorize.NO_SESSION_IN_RESPONSE"
|
|
181
|
+
nil
|
|
182
|
+
end
|
|
183
|
+
rescue RestClient::Unauthorized, RestClient::Forbidden => e
|
|
184
|
+
logger.error "#{identifier}.METHOD:authorize.AUTH_ERROR:#{e.message}"
|
|
185
|
+
nil
|
|
186
|
+
rescue StandardError => e
|
|
187
|
+
logger.error "#{identifier}.METHOD:authorize.ERROR:#{e.message}"
|
|
188
|
+
nil
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
protected
|
|
192
|
+
|
|
193
|
+
# Returns the Portal service endpoint URL
|
|
194
|
+
#
|
|
195
|
+
# @return [String] The portal endpoint URL
|
|
196
|
+
def service_endpoint
|
|
197
|
+
portal_endpoint
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Returns the session cookie name used by Portal service
|
|
201
|
+
#
|
|
202
|
+
# @return [String] The cookie name ('SESSION')
|
|
203
|
+
def session_cookie_name
|
|
204
|
+
'SESSION'
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Indicates whether Portal service requires a session cookie
|
|
208
|
+
#
|
|
209
|
+
# @return [Boolean] true (Portal requires SESSION cookie)
|
|
210
|
+
def requires_session?
|
|
211
|
+
true
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Load nested service classes after Portal is defined
|
|
219
|
+
require_relative 'portal/dashboard'
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class VMS
|
|
7
|
+
# Analytics service for VMS metrics
|
|
8
|
+
#
|
|
9
|
+
# Provides analytics data for video transcoding operations
|
|
10
|
+
# including duration and volume metrics for reporting and
|
|
11
|
+
# capacity planning.
|
|
12
|
+
#
|
|
13
|
+
# @example Get transcoding analytics
|
|
14
|
+
# vms = Conversant::V3.vms(12345)
|
|
15
|
+
#
|
|
16
|
+
# # Get transcoding duration metrics
|
|
17
|
+
# duration = vms.analytics.transcoding({
|
|
18
|
+
# startTime: "2025-01-01",
|
|
19
|
+
# endTime: "2025-01-31"
|
|
20
|
+
# })
|
|
21
|
+
#
|
|
22
|
+
# # Get volume metrics
|
|
23
|
+
# volume = vms.analytics.volume({
|
|
24
|
+
# startTime: "2025-01-01",
|
|
25
|
+
# endTime: "2025-01-31"
|
|
26
|
+
# })
|
|
27
|
+
#
|
|
28
|
+
# @since 1.0.0
|
|
29
|
+
class Analytics
|
|
30
|
+
# @return [VMS] the parent VMS service instance
|
|
31
|
+
attr_reader :parent
|
|
32
|
+
|
|
33
|
+
# Initialize analytics service
|
|
34
|
+
#
|
|
35
|
+
# @param parent [VMS] the parent VMS service instance
|
|
36
|
+
def initialize(parent)
|
|
37
|
+
@parent = parent
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Get transcoding duration analytics
|
|
41
|
+
#
|
|
42
|
+
# Retrieves duration metrics for video transcoding operations
|
|
43
|
+
# over a specified time range. Useful for capacity planning
|
|
44
|
+
# and billing calculations.
|
|
45
|
+
#
|
|
46
|
+
# @param payload [Hash] query parameters including time range
|
|
47
|
+
# @option payload [String] :startTime start date/time
|
|
48
|
+
# @option payload [String] :endTime end date/time
|
|
49
|
+
#
|
|
50
|
+
# @return [Array] transcoding duration metrics, or empty array on error
|
|
51
|
+
#
|
|
52
|
+
# @example Get monthly transcoding duration
|
|
53
|
+
# duration = vms.analytics.transcoding({
|
|
54
|
+
# startTime: "2025-01-01",
|
|
55
|
+
# endTime: "2025-01-31"
|
|
56
|
+
# })
|
|
57
|
+
# puts "Total duration: #{duration.sum} minutes"
|
|
58
|
+
#
|
|
59
|
+
# @since 1.0.0
|
|
60
|
+
def transcoding(payload)
|
|
61
|
+
merged_payload = payload.merge(type: nil)
|
|
62
|
+
response = @parent.send(:call, 'GET', "/reporting/vms/transcoding/duration?#{merged_payload.to_query}")
|
|
63
|
+
return [] if response.nil?
|
|
64
|
+
|
|
65
|
+
JSON.parse(response)
|
|
66
|
+
rescue StandardError => e
|
|
67
|
+
logger.error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
68
|
+
[]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Get volume analytics for transcoding
|
|
72
|
+
#
|
|
73
|
+
# Retrieves volume metrics (in bytes/GB) for transcoded video data
|
|
74
|
+
# over a specified time range. Useful for storage capacity planning
|
|
75
|
+
# and bandwidth analysis.
|
|
76
|
+
#
|
|
77
|
+
# @param payload [Hash] query parameters including time range
|
|
78
|
+
# @option payload [String] :startTime start date/time
|
|
79
|
+
# @option payload [String] :endTime end date/time
|
|
80
|
+
#
|
|
81
|
+
# @return [Array] volume metrics for transcoding operations, or empty array on error
|
|
82
|
+
#
|
|
83
|
+
# @example Get monthly transcoding volume
|
|
84
|
+
# volume = vms.analytics.volume({
|
|
85
|
+
# startTime: "2025-01-01",
|
|
86
|
+
# endTime: "2025-01-31"
|
|
87
|
+
# })
|
|
88
|
+
# puts "Total volume: #{volume.sum} GB"
|
|
89
|
+
#
|
|
90
|
+
# @since 1.0.0
|
|
91
|
+
def volume(payload)
|
|
92
|
+
merged_payload = payload.merge(type: nil)
|
|
93
|
+
response = @parent.send(:call, 'GET', "/reporting/vms/transcoding/volume?#{merged_payload.to_query}")
|
|
94
|
+
return [] if response.nil?
|
|
95
|
+
|
|
96
|
+
JSON.parse(response)
|
|
97
|
+
rescue StandardError => e
|
|
98
|
+
logger.error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
99
|
+
[]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# Get logger instance from parent
|
|
105
|
+
#
|
|
106
|
+
# @return [Logger] logger instance
|
|
107
|
+
def logger
|
|
108
|
+
@parent.send(:logger)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class VMS
|
|
7
|
+
# Business metrics service for VMS
|
|
8
|
+
#
|
|
9
|
+
# Provides business-level metrics for billing and reporting
|
|
10
|
+
# including duration, volume, and transcoding statistics broken
|
|
11
|
+
# down by resolution (SD, HD, UHD) and operation type.
|
|
12
|
+
#
|
|
13
|
+
# @example Get business metrics
|
|
14
|
+
# vms = Conversant::V3.vms(12345)
|
|
15
|
+
#
|
|
16
|
+
# # Get duration metrics for billing
|
|
17
|
+
# duration = vms.business.duration({
|
|
18
|
+
# startTime: Time.now.beginning_of_month
|
|
19
|
+
# })
|
|
20
|
+
#
|
|
21
|
+
# # Get comprehensive transcoding breakdown
|
|
22
|
+
# breakdown = vms.business.transcoding({
|
|
23
|
+
# startTime: Time.now.beginning_of_month
|
|
24
|
+
# })
|
|
25
|
+
# puts "SD: #{breakdown[:vms_transcoding_sd]}"
|
|
26
|
+
# puts "HD: #{breakdown[:vms_transcoding_hd]}"
|
|
27
|
+
# puts "UHD: #{breakdown[:vms_transcoding_uhd]}"
|
|
28
|
+
#
|
|
29
|
+
# @since 1.0.0
|
|
30
|
+
class Business
|
|
31
|
+
# @return [VMS] the parent VMS service instance
|
|
32
|
+
attr_reader :parent
|
|
33
|
+
|
|
34
|
+
# Initialize business metrics service
|
|
35
|
+
#
|
|
36
|
+
# @param parent [VMS] the parent VMS service instance
|
|
37
|
+
def initialize(parent)
|
|
38
|
+
@parent = parent
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Get video duration metrics for billing
|
|
42
|
+
#
|
|
43
|
+
# Retrieves video transcoding duration metrics aggregated by month
|
|
44
|
+
# for billing and usage reporting purposes.
|
|
45
|
+
#
|
|
46
|
+
# @param payload [Hash] query parameters including month/year
|
|
47
|
+
# @option payload [Time, String] :startTime start time (used to extract month)
|
|
48
|
+
#
|
|
49
|
+
# @return [Array] duration metrics for billing purposes, or empty array on error
|
|
50
|
+
#
|
|
51
|
+
# @example Get current month duration
|
|
52
|
+
# duration = vms.business.duration({
|
|
53
|
+
# startTime: Time.now.beginning_of_month
|
|
54
|
+
# })
|
|
55
|
+
#
|
|
56
|
+
# @since 1.0.0
|
|
57
|
+
def duration(payload)
|
|
58
|
+
month = extract_month(payload)
|
|
59
|
+
search_payload = {
|
|
60
|
+
month: month,
|
|
61
|
+
selectType: 'vtd',
|
|
62
|
+
customerType: @parent.type || 2,
|
|
63
|
+
_: (Time.now.to_f * 1000).to_i.to_s
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
response = @parent.send(:call, 'GET', "/v5/reporting/vms/business/usage/search?#{search_payload.to_query}")
|
|
67
|
+
return [] if response.nil?
|
|
68
|
+
|
|
69
|
+
JSON.parse(response)
|
|
70
|
+
rescue StandardError => e
|
|
71
|
+
logger.error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
72
|
+
[]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get video volume metrics for billing
|
|
76
|
+
#
|
|
77
|
+
# Retrieves video transcoding volume metrics aggregated by month
|
|
78
|
+
# for storage billing and capacity planning.
|
|
79
|
+
#
|
|
80
|
+
# @param payload [Hash] query parameters including month/year
|
|
81
|
+
# @option payload [Time, String] :startTime start time (used to extract month)
|
|
82
|
+
#
|
|
83
|
+
# @return [Array] volume metrics for billing purposes, or empty array on error
|
|
84
|
+
#
|
|
85
|
+
# @example Get current month volume
|
|
86
|
+
# volume = vms.business.volume({
|
|
87
|
+
# startTime: Time.now.beginning_of_month
|
|
88
|
+
# })
|
|
89
|
+
#
|
|
90
|
+
# @since 1.0.0
|
|
91
|
+
def volume(payload)
|
|
92
|
+
month = extract_month(payload)
|
|
93
|
+
search_payload = {
|
|
94
|
+
month: month,
|
|
95
|
+
selectType: 'vtv',
|
|
96
|
+
customerType: @parent.type || 2,
|
|
97
|
+
_: (Time.now.to_f * 1000).to_i.to_s
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
response = @parent.send(:call, 'GET', "/v5/reporting/vms/business/usage/search?#{search_payload.to_query}")
|
|
101
|
+
return [] if response.nil?
|
|
102
|
+
|
|
103
|
+
JSON.parse(response)
|
|
104
|
+
rescue StandardError => e
|
|
105
|
+
logger.error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
106
|
+
[]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Get comprehensive transcoding metrics breakdown
|
|
110
|
+
#
|
|
111
|
+
# Retrieves detailed transcoding metrics broken down by resolution
|
|
112
|
+
# (SD, HD, UHD) and operation type (transcoding vs transmuxing).
|
|
113
|
+
# Useful for detailed billing and capacity analysis.
|
|
114
|
+
#
|
|
115
|
+
# @param payload [Hash] query parameters including month/year
|
|
116
|
+
# @option payload [Time, String] :startTime start time (used to extract month)
|
|
117
|
+
#
|
|
118
|
+
# @return [Hash] transcoding metrics breakdown with keys:
|
|
119
|
+
# - :vms_transcoding [Float] total transcoding duration
|
|
120
|
+
# - :vms_transmuxing [Float] transmuxing duration
|
|
121
|
+
# - :vms_transcoding_sd [Float] SD transcoding duration
|
|
122
|
+
# - :vms_transcoding_hd [Float] HD transcoding duration
|
|
123
|
+
# - :vms_transcoding_uhd [Float] UHD transcoding duration
|
|
124
|
+
#
|
|
125
|
+
# @example Get transcoding breakdown
|
|
126
|
+
# breakdown = vms.business.transcoding({
|
|
127
|
+
# startTime: Time.now.beginning_of_month
|
|
128
|
+
# })
|
|
129
|
+
# puts "Total transcoding: #{breakdown[:vms_transcoding]} minutes"
|
|
130
|
+
# puts "SD: #{breakdown[:vms_transcoding_sd]} minutes"
|
|
131
|
+
# puts "HD: #{breakdown[:vms_transcoding_hd]} minutes"
|
|
132
|
+
# puts "UHD: #{breakdown[:vms_transcoding_uhd]} minutes"
|
|
133
|
+
# puts "Transmuxing: #{breakdown[:vms_transmuxing]} minutes"
|
|
134
|
+
#
|
|
135
|
+
# @since 1.0.0
|
|
136
|
+
def transcoding(payload)
|
|
137
|
+
report_vms = {
|
|
138
|
+
vms_transcoding: 0,
|
|
139
|
+
vms_transmuxing: 0,
|
|
140
|
+
vms_transcoding_sd: 0,
|
|
141
|
+
vms_transcoding_hd: 0,
|
|
142
|
+
vms_transcoding_uhd: 0
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
vms_trans = duration(payload)&.first
|
|
146
|
+
return report_vms unless vms_trans
|
|
147
|
+
|
|
148
|
+
name = vms_trans.keys&.first
|
|
149
|
+
if vms_trans[name].present? && !vms_trans[name].empty?
|
|
150
|
+
vms_trans[name]&.each do |item|
|
|
151
|
+
report_vms[:vms_transmuxing] += item['transmux']&.to_f || 0
|
|
152
|
+
report_vms[:vms_transcoding_sd] += (item['h264SdTranscoding']&.to_f || 0) + (item['h265SdTranscoding']&.to_f || 0)
|
|
153
|
+
report_vms[:vms_transcoding_hd] += (item['h264HdTranscoding']&.to_f || 0) + (item['h265HdTranscoding']&.to_f || 0)
|
|
154
|
+
report_vms[:vms_transcoding_uhd] += (item['h264UhdTranscoding']&.to_f || 0) + (item['h265UhdTranscoding']&.to_f || 0)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
report_vms[:vms_transcoding] =
|
|
159
|
+
report_vms[:vms_transcoding_sd] +
|
|
160
|
+
report_vms[:vms_transcoding_hd] +
|
|
161
|
+
report_vms[:vms_transcoding_uhd]
|
|
162
|
+
|
|
163
|
+
report_vms
|
|
164
|
+
rescue StandardError => e
|
|
165
|
+
logger.error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
166
|
+
report_vms
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
private
|
|
170
|
+
|
|
171
|
+
# Extract month in YYYYMM format from payload
|
|
172
|
+
#
|
|
173
|
+
# @param payload [Hash] payload containing startTime
|
|
174
|
+
# @return [String] month in YYYYMM format
|
|
175
|
+
def extract_month(payload)
|
|
176
|
+
start_time = payload[:startTime] || Time.now.beginning_of_month
|
|
177
|
+
start_time.to_datetime.strftime('%Y%m')
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Get logger instance from parent
|
|
181
|
+
#
|
|
182
|
+
# @return [Logger] logger instance
|
|
183
|
+
def logger
|
|
184
|
+
@parent.send(:logger)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Conversant
|
|
4
|
+
module V3
|
|
5
|
+
module Services
|
|
6
|
+
class VMS
|
|
7
|
+
class Partner
|
|
8
|
+
# VMS analytics service for partner-level reporting
|
|
9
|
+
#
|
|
10
|
+
# Provides partner-level analytics and reporting for Video Management System services
|
|
11
|
+
# including VOD duration and transcoding metrics across multiple customer accounts.
|
|
12
|
+
#
|
|
13
|
+
# @since 1.0.12
|
|
14
|
+
class Analytics
|
|
15
|
+
# @return [Conversant::V3::Services::VMS] the parent VMS service instance
|
|
16
|
+
attr_reader :parent
|
|
17
|
+
|
|
18
|
+
# Initialize partner VMS analytics service
|
|
19
|
+
#
|
|
20
|
+
# @param parent [Conversant::V3::Services::VMS] the parent VMS service instance
|
|
21
|
+
def initialize(parent)
|
|
22
|
+
@parent = parent
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get business service instance
|
|
26
|
+
#
|
|
27
|
+
# Provides access to business-focused analytics that aggregate transcoding
|
|
28
|
+
# data for VOD billing and capacity planning.
|
|
29
|
+
#
|
|
30
|
+
# @return [Business] business service for VMS aggregated analytics
|
|
31
|
+
# @since 1.0.16
|
|
32
|
+
#
|
|
33
|
+
# @example Access business methods
|
|
34
|
+
# vms = Conversant::V3.vms(12345)
|
|
35
|
+
# business = vms.partner.analytics.business
|
|
36
|
+
# metrics = business.transcoding(startTime: Time.now.beginning_of_month)
|
|
37
|
+
def business
|
|
38
|
+
@business ||= Business.new(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Get duration of VOD (Video on Demand) for business usage reporting
|
|
42
|
+
#
|
|
43
|
+
# Retrieves VOD transcoding duration metrics aggregated by month and customer type
|
|
44
|
+
# for partner-level business reporting and billing purposes.
|
|
45
|
+
#
|
|
46
|
+
# @param args [Hash] query parameters
|
|
47
|
+
# @option args [Time, String] :startTime start time for the report (defaults to beginning of current month)
|
|
48
|
+
# @option args [String, Integer] :type customer type filter (defaults to 2)
|
|
49
|
+
#
|
|
50
|
+
# @return [Array] VOD duration data, or empty array on error
|
|
51
|
+
#
|
|
52
|
+
# @example Get VOD duration for current month
|
|
53
|
+
# duration = vms.partner.analytics.duration_of_vod
|
|
54
|
+
# puts "Total VOD duration: #{duration.first['total_duration']} minutes"
|
|
55
|
+
#
|
|
56
|
+
# @since 1.0.8
|
|
57
|
+
def duration_of_vod(**args)
|
|
58
|
+
month, type, timestamp = queries(**args)
|
|
59
|
+
|
|
60
|
+
payload = {
|
|
61
|
+
month: month,
|
|
62
|
+
selectType: 'vtd',
|
|
63
|
+
customerType: type,
|
|
64
|
+
_: timestamp
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
response = @parent.send(:call, 'GET', "/v5/reporting/vms/business/usage/search?#{payload.to_query}")
|
|
68
|
+
return [] if response.nil?
|
|
69
|
+
|
|
70
|
+
JSON.parse(response)&.map(&:with_indifferent_access) || []
|
|
71
|
+
rescue StandardError => e
|
|
72
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
73
|
+
[]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Get VMS transcoding duration metrics
|
|
77
|
+
#
|
|
78
|
+
# Retrieves transcoding duration metrics for video processing operations,
|
|
79
|
+
# useful for capacity planning and billing calculations.
|
|
80
|
+
#
|
|
81
|
+
# @param params [Hash] query parameters
|
|
82
|
+
# @option params [String] :year year in YYYY format
|
|
83
|
+
#
|
|
84
|
+
# @return [Array] transcoding duration data, or empty array on error
|
|
85
|
+
#
|
|
86
|
+
# @example Get transcoding duration for a year
|
|
87
|
+
# duration = vms.partner.analytics.duration(year: "2025")
|
|
88
|
+
# puts "Total transcoding: #{duration['total']} hours"
|
|
89
|
+
#
|
|
90
|
+
# @since 1.0.8
|
|
91
|
+
def duration(params = {})
|
|
92
|
+
query_string = params.map { |k, v| "#{k}=#{v}" }.join('&')
|
|
93
|
+
uri = '/reporting/vms/transcoding/duration'
|
|
94
|
+
uri += "?#{query_string}" unless query_string.empty?
|
|
95
|
+
response = @parent.send(:call, 'GET', uri)
|
|
96
|
+
return [] if response.nil?
|
|
97
|
+
|
|
98
|
+
JSON.parse(response)&.map(&:with_indifferent_access) || []
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
@parent.send(:logger).error "#{@parent.send(:identifier)}.METHOD:#{__method__}.EXCEPTION:#{e.message}"
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
def logger
|
|
107
|
+
@parent.send(:logger)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Helper method to build query parameters
|
|
111
|
+
#
|
|
112
|
+
# Generates month, customer type, and timestamp parameters for VMS business usage queries.
|
|
113
|
+
# Defaults to current month if startTime is not provided.
|
|
114
|
+
#
|
|
115
|
+
# @param args [Hash] Input parameters
|
|
116
|
+
# @option args [Time, String] :startTime Start time for the report (defaults to beginning of current month)
|
|
117
|
+
# @option args [String, Integer] :type Customer type filter (defaults to parent's type or 2)
|
|
118
|
+
#
|
|
119
|
+
# @return [Array<String, Integer, Integer>] Array containing [month (YYYYMM), customer_type, timestamp (ms)]
|
|
120
|
+
def queries(**args)
|
|
121
|
+
month = (args[:startTime] || Time.now&.beginning_of_month)&.to_datetime&.strftime('%Y%m')
|
|
122
|
+
customer_type = args[:type]
|
|
123
|
+
customer_type = @parent.type || 2 unless customer_type.present?
|
|
124
|
+
timestamp = Time.now.getutc.to_i * 1000
|
|
125
|
+
|
|
126
|
+
[month, customer_type, timestamp]
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|