Class: BigbluebuttonRecording

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
ActiveModel::ForbiddenAttributesProtection
Defined in:
app/models/bigbluebutton_recording.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.overall_average_lengthObject

Returns the overall (i.e. for all recordings) average length of recordings in seconds Uses the length of the default playback format



70
71
72
73
74
# File 'app/models/bigbluebutton_recording.rb', line 70

def self.overall_average_length
  avg = BigbluebuttonPlaybackFormat.joins(:playback_type)
        .where("bigbluebutton_playback_types.default = ?", true).average(:length)
  avg.nil? ? 0 : (avg.truncate(2) * 60)
end

.overall_average_sizeObject

Returns the overall (i.e. for all recordings) average size of recordings in bytes Uses the length of the default playback format



78
79
80
81
# File 'app/models/bigbluebutton_recording.rb', line 78

def self.overall_average_size
  avg = BigbluebuttonRecording.average(:size)
  avg.nil? ? 0 : avg
end

.recording_changed?(recording, data) ⇒ Boolean

Compares a recording from the db with data from a getRecordings call. If anything changed in the recording, returns true. We select only the attributes that are saved and turn it all into sorted arrays to compare. If new attributes are stored in recordings, they should be added here.

This was created to speed up the full sync of recordings. In the worst case the comparison is wrong and we’re updating them all (same as not using this method at all, which is ok).

Returns:

  • (Boolean)


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'app/models/bigbluebutton_recording.rb', line 91

def self.recording_changed?(recording, data)
  begin
    # the attributes that are considered in the comparison
    keys = [:end_time, :meetingid,  :metadata, :playback, :published, :recordid, :size, :start_time] # rawSize is not stored at the moment
    keys_formats = [:length, :type, :url] # :size, :processingTime are not stored at the moment

    # the data from getRecordings
    data_clone = data.deep_dup
    data_clone[:size] = data_clone[:size].to_s if data_clone.key?(:size)
    data_clone[:metadata] = data_clone[:metadata].sort if data_clone.key?(:metadata)
    if data_clone.key?(:playback) && data_clone[:playback].key?(:format)
      data_clone[:playback][:format] = [data_clone[:playback][:format]] unless data_clone[:playback][:format].is_a?(Array)
      data_clone[:playback] = data_clone[:playback][:format].map{ |f|
        f.slice(*keys_formats).sort
      }.sort
    else
      data_clone[:playback] = []
    end
    data_clone[:end_time] = data_clone[:end_time].to_i if data_clone.key?(:end_time)
    data_clone[:start_time] = data_clone[:start_time].to_i if data_clone.key?(:start_time)
    data_clone = data_clone.slice(*keys)
    data_sorted = data_clone.sort

    # the data from the recording in the db
    attrs = recording.attributes.symbolize_keys.slice(*keys)
    attrs[:size] = attrs[:size].to_s if attrs.key?(:size)
    attrs[:metadata] = recording..pluck(:name, :content).map{ |i| [i[0].to_sym, i[1]] }.sort
    attrs[:playback] = recording.playback_formats.map{ |f|
      r = f.attributes.symbolize_keys.slice(*keys_formats)
      r[:type] = f.format_type
      r.sort
    }.sort
    attrs = attrs.sort

    # compare
    data_sorted.to_s != attrs.to_s
  rescue StandardError => e
    logger.error "Error comparing recordings: #{e.inspect}"
    true # always update recordings if on error
  end
end

.sync(server, recordings, full_sync = false) ⇒ Object

Syncs the recordings in the db with the array of recordings in ‘recordings’, as received from BigBlueButtonApi#get_recordings. Will add new recordings that are not in the db yet and update the ones that already are (matching by ‘recordid’). Will NOT delete recordings from the db if they are not in the array but instead mark them as unavailable. ‘server’ is the BigbluebuttonServer object from which the recordings were fetched.

TODO: catch exceptions on creating/updating recordings



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'app/models/bigbluebutton_recording.rb', line 142

def self.sync(server, recordings, full_sync=false)
  recordings.each do |rec|
    rec_obj = BigbluebuttonRecording.find_by_recordid(rec[:recordID])
    rec_data = adapt_recording_hash(rec)
    changed = !rec_obj.present? ||
              self.recording_changed?(rec_obj, rec_data)

    if changed
      BigbluebuttonRecording.transaction do
        if rec_obj
          logger.info "Sync recordings: updating recording #{rec_obj.inspect}"
          logger.debug "Sync recordings: recording data #{rec_data.inspect}"
          self.update_recording(server, rec_obj, rec_data)
        else
          logger.info "Sync recordings: creating recording"
          logger.debug "Sync recordings: recording data #{rec_data.inspect}"
          self.create_recording(server, rec_data)
        end
      end
    end
  end
  cleanup_playback_types

  # set as unavailable the recordings that are not in 'recordings', but
  # only in a full synchronization process, which means that the recordings
  # in `recordings` are *all* available in `server`, not a subset.
  if full_sync
    recordIDs = recordings.map{ |rec| rec[:recordID] }
    if recordIDs.length <= 0 # empty response
      BigbluebuttonRecording.
        where(available: true, server: server).
        update_all(available: false)
    else
      BigbluebuttonRecording.
        where(available: true, server: server).
        where.not(recordid: recordIDs).
        update_all(available: false)
    end
  end
end

Instance Method Details

#default_playback_formatObject



54
55
56
57
# File 'app/models/bigbluebutton_recording.rb', line 54

def default_playback_format
  playback_formats.joins(:playback_type)
    .where("bigbluebutton_playback_types.default = ?", true).first
end

#delete_from_server!Object

Remove this recording from the server



60
61
62
63
64
65
66
# File 'app/models/bigbluebutton_recording.rb', line 60

def delete_from_server!
  if self.server.present?
    self.server.send_delete_recordings(self.recordid)
  else
    false
  end
end

#get_token(user, ip) ⇒ Object



34
35
36
37
38
39
40
# File 'app/models/bigbluebutton_recording.rb', line 34

def get_token(user, ip)
  server = BigbluebuttonServer.default
  user.present? ? authName = user.username : authName = "anonymous"
  api_token = server.api.send_api_request(:getRecordingToken, { authUser: authName, authAddr: ip, meetingID: self.recordid })
  str_token = api_token[:token]
  str_token
end

#to_paramObject



30
31
32
# File 'app/models/bigbluebutton_recording.rb', line 30

def to_param
  self.recordid
end

#token_url(user, ip, playback) ⇒ Object

Passing it on the url



44
45
46
47
48
49
50
51
52
# File 'app/models/bigbluebutton_recording.rb', line 44

def token_url(user, ip, playback)
  auth_token = get_token(user, ip)
  if auth_token.present?
    uri = playback.url
    uri += URI.parse(uri).query.blank? ? "?" : "&"
    uri += "token=#{auth_token}"
    uri
  end
end