AutorÃa | Ultima modificación | Ver Log |
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use core\task\adhoc_task;
use core\task\manager;
use Matrix\Exception;
use mod_bigbluebuttonbn\instance;
use mod_bigbluebuttonbn\local\proxy\recording_proxy;
use mod_bigbluebuttonbn\logger;
use mod_bigbluebuttonbn\recording;
use moodle_exception;
/**
* Class containing the scheduled task for converting recordings for the BigBlueButton version 2.5 in Moodle 4.0.
*
* @package mod_bigbluebuttonbn
* @copyright 2021 Jesus Federico, Blindside Networks Inc <jesus at blindsidenetworks dot com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class upgrade_recordings_task extends adhoc_task {
/**
* Run the migration task.
*/
public function execute() {
$info = $this->get_custom_data();
$meetingid = $info->meetingid;
$isimported = $info->isimported ?? 0;
$this->process_bigbluebuttonbn_logs($meetingid, $isimported);
}
/**
* Process all bigbluebuttonbn logs looking for entries which should be converted to meetings.
*
* @param string $meetingid
* @param bool $isimported
* @return bool Whether any more logs are waiting to be processed
* @throws \dml_exception
* @throws moodle_exception
*/
protected function process_bigbluebuttonbn_logs(string $meetingid, bool $isimported): bool {
global $DB;
$classname = static::class;
mtrace("Executing {$classname} for meeting {$meetingid}...");
// Fetch the logs queued for upgrade.
mtrace("Fetching logs for conversion");
// Each log is ordered by timecreated.
[$select, $params] = $this->get_sql_query_for_logs($meetingid, $isimported);
$logsrs = $DB->get_recordset_select('bigbluebuttonbn_logs',
$select,
$params,
'timecreated DESC',
'id, meetingid, timecreated, log');
if (!$logsrs->valid()) {
mtrace("No logs were found for conversion.");
// No more logs. Stop queueing.
return false;
}
// Retrieve recordings from the servers for this meeting.
$recordings = recording_proxy::fetch_recording_by_meeting_id([$meetingid]);
// Sort recordings by meetingId, then startTime.
uasort($recordings, function($a, $b) {
return $b['startTime'] - $a['startTime'];
});
// Create an instance of bigbluebuttonbn_recording per valid recording.
mtrace("Creating new recording records...");
$recordingcount = 0;
foreach ($recordings as $recordingid => $recording) {
$importeddata = $isimported ? '' : json_encode($recording);
try {
$instance = instance::get_from_meetingid($recording['meetingID']);
} catch (Exception $e) {
mtrace("Unable to parse meetingID " . $e->getMessage());
continue;
}
if ($instance) {
$newrecording = [
'courseid' => $instance->get_course_id(),
'bigbluebuttonbnid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id(), // The groupid should be taken from the meetingID.
'recordingid' => $recordingid,
'status' => recording::RECORDING_STATUS_PROCESSED,
];
} else {
mtrace("Unable to find an activity for {$recording['meetingID']}. This recording is headless.");
// This instance does not exist any more.
// Use the data in the log instead of the instance.
$meetingdata = instance::parse_meetingid($recording['meetingID']);
$newrecording = [
'courseid' => $meetingdata['courseid'],
'bigbluebuttonbnid' => $meetingdata['instanceid'],
'groupid' => 0,
'recordingid' => $recordingid,
'status' => recording::RECORDING_STATUS_PROCESSED,
];
if (array_key_exists('groupid', $meetingdata)) {
$newrecording['groupid'] = $meetingdata['groupid'];
}
}
if ($DB->record_exists('bigbluebuttonbn_recordings', $newrecording)) {
mtrace("A recording already exists for {$recording['recordID']}. Skipping.");
// A recording matching these characteristics alreay exists.
continue;
}
// Recording has not been imported, check if we still have more logs.
// We try to guess which logs matches which recordings are they are classed in the same order.
// But this is just an attempt.
$log = null;
if ($logsrs->valid()) {
$log = $logsrs->current();
$logsrs->next();
}
$timecreated = empty($log) ? time() : $log->timecreated;
$newrecording['imported'] = $isimported;
$newrecording['headless'] = 0;
$newrecording['importeddata'] = $importeddata;
$newrecording['timecreated'] = $newrecording['timemodified'] = $timecreated;
// If we could not match with a log, we still create the recording.
$DB->insert_record('bigbluebuttonbn_recordings', $newrecording);
$recordingcount++;
}
mtrace("Migrated {$recordingcount} recordings.");
// Now deactivate logs by marking all of them as migrated.
// Reason for this is that we don't want to run another migration here and we don't know
// which logs matches which recordings.
$DB->set_field_select('bigbluebuttonbn_logs', 'log',
$isimported ? logger::EVENT_IMPORT_MIGRATED : logger::EVENT_CREATE_MIGRATED,
$select,
$params
);
$logsrs->close();
return true;
}
/**
* Get the query (records_select) for the logs to convert.
*
* Each log is ordered by timecreated.
*
* @param string $meetingid
* @param bool $isimported
* @return array
*/
protected function get_sql_query_for_logs(string $meetingid, bool $isimported): array {
global $DB;
if ($isimported) {
return [
'log = :logmatch AND meetingid = :meetingid',
['logmatch' => logger::EVENT_IMPORT, 'meetingid' => $meetingid],
];
}
return [
'log = :logmatch AND meetingid = :meetingid AND ' . $DB->sql_like('meta', ':match'),
[
'logmatch' => logger::EVENT_CREATE,
'match' => '%true%',
'meetingid' => $meetingid
],
];
}
/**
* Schedule all upgrading tasks.
*
* @param bool $importedrecordings
* @return void
* @throws \dml_exception
*/
public static function schedule_upgrade_per_meeting($importedrecordings = false) {
global $DB;
$meetingids = $DB->get_fieldset_sql(
'SELECT DISTINCT meetingid FROM {bigbluebuttonbn_logs} WHERE log = :createorimport',
['createorimport' => $importedrecordings ? logger::EVENT_IMPORT : logger::EVENT_CREATE]
);
foreach ($meetingids as $mid) {
$createdrecordingtask = new static();
$createdrecordingtask->set_custom_data((object) ['meetingid' => $mid, 'isimported' => $importedrecordings]);
manager::queue_adhoc_task($createdrecordingtask);
}
}
}