| 
<?phpdeclare(strict_types=1);
 namespace ParagonIE\Chronicle;
 
 use GuzzleHttp\Exception\GuzzleException;
 use ParagonIE\Chronicle\Exception\InstanceNotFoundException;
 use ParagonIE\Chronicle\Process\{
 Attest,
 CrossSign,
 Replicate
 };
 use ParagonIE\Sapient\Exception\InvalidMessageException;
 
 /**
 * Class Scheduled
 *
 * @package ParagonIE\Chronicle
 */
 class Scheduled
 {
 /** @var array<string, string> */
 protected $settings;
 
 /**
 * Scheduled constructor.
 * @param array<string, string> $settings
 */
 public function __construct(array $settings = [])
 {
 if (empty($settings)) {
 $this->settings = Chronicle::getSettings();
 }
 $this->settings = $settings;
 }
 
 /**
 * Invoked by a CLI script, this runs all of the scheduled tasks.
 *
 * @return self
 *
 * @throws Exception\ChainAppendException
 * @throws Exception\FilesystemException
 * @throws Exception\InvalidInstanceException
 * @throws Exception\ReplicationSourceNotFound
 * @throws Exception\SecurityViolation
 * @throws Exception\TargetNotFound
 * @throws GuzzleException
 * @throws InvalidMessageException
 * @throws \SodiumException
 */
 public function run(): self
 {
 /** @var array<string, string> $instances */
 $instances = $this->settings['instances'];
 if (!empty($instances)) {
 // Do all of the instances:
 foreach ($instances as $instance => $prefix) {
 try {
 Chronicle::setTablePrefix($prefix);
 $this->runAll();
 } catch (InstanceNotFoundException $ex) {
 // Skip this one. It might not be created yed.
 }
 }
 return $this;
 }
 return $this->runAll();
 }
 
 /**
 * @return Scheduled
 * @throws Exception\ChainAppendException
 * @throws Exception\FilesystemException
 * @throws Exception\InvalidInstanceException
 * @throws Exception\ReplicationSourceNotFound
 * @throws Exception\SecurityViolation
 * @throws Exception\TargetNotFound
 * @throws GuzzleException
 * @throws InvalidMessageException
 * @throws \SodiumException
 */
 public function runAll(): self
 {
 return $this
 ->doCrossSigns()
 ->doReplication()
 ->doAttestation()
 ;
 }
 
 /**
 * Cross-sign to other Chronicles (where it is needed)
 *
 * @return self
 * @throws Exception\FilesystemException
 * @throws Exception\TargetNotFound
 * @throws GuzzleException
 * @throws InvalidMessageException
 */
 public function doCrossSigns(): self
 {
 /** @var array<string, int> $row */
 foreach (Chronicle::getDatabase()->run('SELECT id FROM chronicle_xsign_targets') as $row) {
 $xsign = CrossSign::byId((int) $row['id']);
 if ($xsign->needsToCrossSign()) {
 $xsign->performCrossSign();
 }
 }
 return $this;
 }
 
 /**
 * Replicate any new records from the Chronicles we're mirroring
 *
 * @return self
 *
 * @throws Exception\InvalidInstanceException
 * @throws Exception\ReplicationSourceNotFound
 * @throws Exception\SecurityViolation
 * @throws GuzzleException
 * @throws InvalidMessageException
 * @throws \SodiumException
 */
 public function doReplication(): self
 {
 $query = 'SELECT id FROM ' . Chronicle::getTableName('replication_sources');
 /** @var array<string, int> $row */
 foreach (Chronicle::getDatabase()->run($query) as $row) {
 Replicate::byId((int) $row['id'])->replicate();
 }
 return $this;
 }
 
 /**
 * Run the Attestation process (if it's scheduled).
 *
 * @return self
 *
 * @throws Exception\ChainAppendException
 * @throws Exception\FilesystemException
 * @throws \SodiumException
 */
 public function doAttestation(): self
 {
 $attest = new Attest($this->settings);
 if ($attest->isScheduled()) {
 $attest->run();
 }
 return $this;
 }
 }
 
 |