1<?php 2/** 3 * @author Thomas Müller <thomas.mueller@tmit.eu> 4 * 5 * @copyright Copyright (c) 2018, ownCloud GmbH 6 * @license AGPL-3.0 7 * 8 * This code is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License, version 3, 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Affero General Public License for more details. 16 * 17 * You should have received a copy of the GNU Affero General Public License, version 3, 18 * along with this program. If not, see <http://www.gnu.org/licenses/> 19 * 20 */ 21 22namespace OCA\DAV\DAV; 23 24use OCA\DAV\JobStatus\Entity\JobStatus; 25use OCA\DAV\JobStatus\Entity\JobStatusMapper; 26use OCP\ILogger; 27use OCP\IURLGenerator; 28use OCP\IUserSession; 29use OCP\Shutdown\IShutdownManager; 30use Sabre\DAV\Exception; 31use Sabre\DAV\Server; 32use Sabre\DAV\ServerPlugin; 33use Sabre\DAV\UUIDUtil; 34use Sabre\HTTP\RequestInterface; 35use Sabre\HTTP\Response; 36use Sabre\HTTP\ResponseInterface; 37 38/** 39 * Class LazyOpsPlugin 40 * 41 * @package OCA\DAV\DAV 42 */ 43class LazyOpsPlugin extends ServerPlugin { 44 45 /** @var Server */ 46 private $server; 47 /** @var string */ 48 private $jobId; 49 /** @var JobStatus */ 50 private $entity; 51 /** @var IUserSession */ 52 private $userSession; 53 /** @var IURLGenerator */ 54 private $urlGenerator; 55 /** @var IShutdownManager */ 56 private $shutdownManager; 57 /** @var ILogger */ 58 private $logger; 59 /** @var JobStatusMapper */ 60 private $mapper; 61 62 public function __construct( 63 IUserSession $userSession, 64 IURLGenerator $urlGenerator, 65 IShutdownManager $shutdownManager, 66 JobStatusMapper $jobStatusMapper, 67 ILogger $logger 68 ) { 69 $this->userSession = $userSession; 70 $this->urlGenerator = $urlGenerator; 71 $this->shutdownManager = $shutdownManager; 72 $this->logger = $logger; 73 $this->mapper = $jobStatusMapper; 74 } 75 76 /** 77 * @param Server $server 78 */ 79 public function initialize(Server $server) { 80 $this->server = $server; 81 $server->on('method:MOVE', [$this, 'httpMove'], 90); 82 } 83 84 /** 85 * @param RequestInterface $request 86 * @param ResponseInterface $response 87 * @return bool 88 * @throws Exception\NotAuthenticated 89 */ 90 public function httpMove(RequestInterface $request, ResponseInterface $response) { 91 if (!$request->getHeader('OC-LazyOps')) { 92 return true; 93 } 94 95 $this->jobId = UUIDUtil::getUUID(); 96 $this->setJobStatus([ 97 'status' => 'init' 98 ]); 99 $userId = $this->getUserId(); 100 $location = $this->urlGenerator 101 ->linkTo('', 'remote.php') . "/dav/job-status/{$userId}/{$this->jobId}"; 102 103 $response->setStatus(202); 104 $response->setHeader('Connection', 'close'); 105 $response->setHeader('OC-JobStatus-Location', $location); 106 107 $this->shutdownManager->register(function () use ($request, $response) { 108 return $this->afterResponse($request, $response); 109 }, IShutdownManager::HIGH); 110 111 return false; 112 } 113 114 public function afterResponse(RequestInterface $request, ResponseInterface $response) { 115 if (!$request->getHeader('OC-LazyOps')) { 116 return true; 117 } 118 119 \flush(); 120 $request->removeHeader('OC-LazyOps'); 121 $responseDummy = new Response(); 122 try { 123 $this->setJobStatus([ 124 'status' => 'started' 125 ]); 126 $this->server->emit('method:MOVE', [$request, $responseDummy]); 127 128 $this->setJobStatus([ 129 'status' => 'finished', 130 'fileId' => $response->getHeader('OC-FileId'), 131 'ETag' => $response->getHeader('ETag') 132 ]); 133 } catch (\Exception $ex) { 134 $this->logger->logException($ex); 135 136 $this->setJobStatus([ 137 'status' => 'error', 138 'errorCode' => $ex instanceof Exception ? $ex->getHTTPCode() : 500, 139 'errorMessage' => $ex->getMessage() 140 ]); 141 } 142 return false; 143 } 144 145 private function setJobStatus(array $status) { 146 if ($this->entity === null) { 147 $userId = $this->getUserId(); 148 149 $this->entity = new JobStatus(); 150 $this->entity->setStatusInfo(\json_encode($status)); 151 $this->entity->setUserId($userId); 152 $this->entity->setUuid($this->jobId); 153 $this->mapper->insert($this->entity); 154 } else { 155 $this->entity->setStatusInfo(\json_encode($status)); 156 $this->mapper->update($this->entity); 157 } 158 } 159 160 /** 161 * @return string 162 * @throws Exception\NotAuthenticated 163 */ 164 private function getUserId() { 165 $user = $this->userSession->getUser(); 166 if ($user === null) { 167 throw new Exception\NotAuthenticated(); 168 } 169 return $user->getUID(); 170 } 171} 172