@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
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 213 lines 4.9 kB view raw
1<?php 2 3final class PhabricatorProtocolLog 4 extends Phobject { 5 6 private $logfile; 7 private $mode; 8 private $buffer = array(); 9 10 public function __construct($logfile) { 11 $this->logfile = $logfile; 12 } 13 14 public function didStartSession($session_name) { 15 $this->setMode('!'); 16 $this->buffer[] = $session_name; 17 $this->flush(); 18 } 19 20 public function didEndSession() { 21 $this->setMode('_'); 22 $this->buffer[] = pht('<End of Session>'); 23 $this->flush(); 24 } 25 26 public function didWriteBytes($bytes) { 27 if (!strlen($bytes)) { 28 return; 29 } 30 31 $this->setMode('>'); 32 $this->buffer[] = $bytes; 33 } 34 35 public function didReadBytes($bytes) { 36 if (!strlen($bytes)) { 37 return; 38 } 39 40 $this->setMode('<'); 41 $this->buffer[] = $bytes; 42 } 43 44 public function didReadFrame($frame) { 45 $this->writeFrame('<*', $frame); 46 } 47 48 public function didWriteFrame($frame) { 49 $this->writeFrame('>*', $frame); 50 } 51 52 private function writeFrame($header, $frame) { 53 $this->flush(); 54 55 $frame = explode("\n", $frame); 56 foreach ($frame as $key => $line) { 57 $frame[$key] = $header.' '.$this->escapeBytes($line); 58 } 59 $frame = implode("\n", $frame)."\n\n"; 60 61 $this->writeMessage($frame); 62 } 63 64 private function setMode($mode) { 65 if ($this->mode === $mode) { 66 return $this; 67 } 68 69 if ($this->mode !== null) { 70 $this->flush(); 71 } 72 73 $this->mode = $mode; 74 75 return $this; 76 } 77 78 private function flush() { 79 $mode = $this->mode; 80 $bytes = $this->buffer; 81 82 $this->mode = null; 83 $this->buffer = array(); 84 85 $bytes = implode('', $bytes); 86 87 if (strlen($bytes)) { 88 $this->writeBytes($mode, $bytes); 89 } 90 } 91 92 private function writeBytes($mode, $bytes) { 93 $header = $mode; 94 $len = strlen($bytes); 95 96 $out = array(); 97 switch ($mode) { 98 case '<': 99 $out[] = pht('%s Write [%s bytes]', $header, new PhutilNumber($len)); 100 break; 101 case '>': 102 $out[] = pht('%s Read [%s bytes]', $header, new PhutilNumber($len)); 103 break; 104 default: 105 $out[] = pht( 106 '%s %s', 107 $header, 108 $this->escapeBytes($bytes)); 109 break; 110 } 111 112 switch ($mode) { 113 case '<': 114 case '>': 115 $out[] = $this->renderBytes($header, $bytes); 116 break; 117 } 118 119 $out = implode("\n", $out)."\n\n"; 120 121 $this->writeMessage($out); 122 } 123 124 private function renderBytes($header, $bytes) { 125 $bytes_per_line = 48; 126 $bytes_per_chunk = 4; 127 128 // Compute the width of the "bytes" display section, which looks like 129 // this: 130 // 131 // > 00112233 44556677 abcdefgh 132 // ^^^^^^^^^^^^^^^^^ 133 // 134 // We need to figure this out so we can align the plain text in the far 135 // right column appropriately. 136 137 // The character width of the "bytes" part of a full display line. If 138 // we're rendering 48 bytes per line, we'll need 96 characters, since 139 // each byte is printed as a 2-character hexadecimal code. 140 $display_bytes = ($bytes_per_line * 2); 141 142 // The character width of the number of spaces in between the "bytes" 143 // chunks. If we're rendering 12 chunks per line, we'll put 11 spaces 144 // in between them to separate them. 145 $display_spaces = (($bytes_per_line / $bytes_per_chunk) - 1); 146 147 $pad_bytes = $display_bytes + $display_spaces; 148 149 // When the protocol is plaintext, try to break it on newlines so it's 150 // easier to read. 151 $pos = 0; 152 $lines = array(); 153 while (true) { 154 $next_break = strpos($bytes, "\n", $pos); 155 if ($next_break === false) { 156 $len = strlen($bytes) - $pos; 157 } else { 158 $len = ($next_break - $pos) + 1; 159 } 160 $len = min($bytes_per_line, $len); 161 162 $next_bytes = substr($bytes, $pos, $len); 163 164 $chunk_parts = array(); 165 foreach (str_split($next_bytes, $bytes_per_chunk) as $chunk) { 166 $chunk_display = ''; 167 for ($ii = 0; $ii < strlen($chunk); $ii++) { 168 $chunk_display .= sprintf('%02x', ord($chunk[$ii])); 169 } 170 $chunk_parts[] = $chunk_display; 171 } 172 $chunk_parts = implode(' ', $chunk_parts); 173 174 $chunk_parts = str_pad($chunk_parts, $pad_bytes, ' '); 175 176 177 $lines[] = $header.' '.$chunk_parts.' '.$this->escapeBytes($next_bytes); 178 179 $pos += $len; 180 181 if ($pos >= strlen($bytes)) { 182 break; 183 } 184 } 185 186 $lines = implode("\n", $lines); 187 188 return $lines; 189 } 190 191 private function escapeBytes($bytes) { 192 $result = ''; 193 for ($ii = 0; $ii < strlen($bytes); $ii++) { 194 $c = $bytes[$ii]; 195 $o = ord($c); 196 197 if ($o >= 0x20 && $o <= 0x7F) { 198 $result .= $c; 199 } else { 200 $result .= '.'; 201 } 202 } 203 return $result; 204 } 205 206 private function writeMessage($message) { 207 $f = fopen($this->logfile, 'a'); 208 fwrite($f, $message); 209 fflush($f); 210 fclose($f); 211 } 212 213}