@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 171 lines 4.4 kB view raw
1<?php 2 3/** 4 * Amazon S3 file storage engine. This engine scales well but is relatively 5 * high-latency since data has to be pulled off S3. 6 * 7 * @task internal Internals 8 */ 9final class PhabricatorS3FileStorageEngine 10 extends PhabricatorFileStorageEngine { 11 12 13/* -( Engine Metadata )---------------------------------------------------- */ 14 15 16 /** 17 * This engine identifies as `amazon-s3`. 18 */ 19 public function getEngineIdentifier() { 20 return 'amazon-s3'; 21 } 22 23 public function getEnginePriority() { 24 return 100; 25 } 26 27 public function canWriteFiles() { 28 $bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket'); 29 $access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key'); 30 $secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key'); 31 $endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint'); 32 $region = PhabricatorEnv::getEnvConfig('amazon-s3.region'); 33 34 return phutil_nonempty_string($bucket) && 35 phutil_nonempty_string($access_key) && 36 phutil_nonempty_string($secret_key) && 37 phutil_nonempty_string($endpoint) && 38 phutil_nonempty_string($region); 39 } 40 41 42/* -( Managing File Data )------------------------------------------------- */ 43 44 45 /** 46 * Writes file data into Amazon S3. 47 */ 48 public function writeFile($data, array $params) { 49 $s3 = $this->newS3API(); 50 51 // Generate a random name for this file. We add some directories to it 52 // (e.g. 'abcdef123456' becomes 'ab/cd/ef123456') to make large numbers of 53 // files more browsable with web/debugging tools like the S3 administration 54 // tool. 55 $seed = Filesystem::readRandomCharacters(20); 56 $parts = array(); 57 $parts[] = 'phabricator'; 58 59 $instance_name = PhabricatorEnv::getEnvConfig('cluster.instance'); 60 if (phutil_nonempty_string($instance_name)) { 61 $parts[] = $instance_name; 62 } 63 64 $parts[] = substr($seed, 0, 2); 65 $parts[] = substr($seed, 2, 2); 66 $parts[] = substr($seed, 4); 67 68 $name = implode('/', $parts); 69 70 AphrontWriteGuard::willWrite(); 71 $profiler = PhutilServiceProfiler::getInstance(); 72 $call_id = $profiler->beginServiceCall( 73 array( 74 'type' => 's3', 75 'method' => 'putObject', 76 )); 77 78 $s3 79 ->setParametersForPutObject($name, $data) 80 ->resolve(); 81 82 $profiler->endServiceCall($call_id, array()); 83 84 return $name; 85 } 86 87 88 /** 89 * Load a stored blob from Amazon S3. 90 */ 91 public function readFile($handle) { 92 $s3 = $this->newS3API(); 93 94 $profiler = PhutilServiceProfiler::getInstance(); 95 $call_id = $profiler->beginServiceCall( 96 array( 97 'type' => 's3', 98 'method' => 'getObject', 99 )); 100 101 $result = $s3 102 ->setParametersForGetObject($handle) 103 ->resolve(); 104 105 $profiler->endServiceCall($call_id, array()); 106 107 return $result; 108 } 109 110 111 /** 112 * Delete a blob from Amazon S3. 113 */ 114 public function deleteFile($handle) { 115 $s3 = $this->newS3API(); 116 117 AphrontWriteGuard::willWrite(); 118 $profiler = PhutilServiceProfiler::getInstance(); 119 $call_id = $profiler->beginServiceCall( 120 array( 121 'type' => 's3', 122 'method' => 'deleteObject', 123 )); 124 125 $s3 126 ->setParametersForDeleteObject($handle) 127 ->resolve(); 128 129 $profiler->endServiceCall($call_id, array()); 130 } 131 132 133/* -( Internals )---------------------------------------------------------- */ 134 135 136 /** 137 * Retrieve the S3 bucket name. 138 * 139 * @task internal 140 */ 141 private function getBucketName() { 142 $bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket'); 143 if (!$bucket) { 144 throw new PhabricatorFileStorageConfigurationException( 145 pht( 146 "No '%s' specified!", 147 'storage.s3.bucket')); 148 } 149 return $bucket; 150 } 151 152 /** 153 * Create a new S3 API object. 154 * 155 * @task internal 156 */ 157 private function newS3API() { 158 $access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key'); 159 $secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key'); 160 $region = PhabricatorEnv::getEnvConfig('amazon-s3.region'); 161 $endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint'); 162 163 return id(new PhutilAWSS3Future()) 164 ->setAccessKey($access_key) 165 ->setSecretKey(new PhutilOpaqueEnvelope($secret_key)) 166 ->setRegion($region) 167 ->setEndpoint($endpoint) 168 ->setBucket($this->getBucketName()); 169 } 170 171}