1+ <?php
2+ namespace LaunchDarkly ;
3+
4+ /**
5+ * @internal
6+ */
7+ class EventProcessor {
8+
9+ private $ _apiKey ;
10+ private $ _queue ;
11+ private $ _capacity ;
12+ private $ _timeout ;
13+ private $ _socket_failed ;
14+ private $ _host ;
15+ private $ _port ;
16+ private $ _ssl ;
17+
18+ public function __construct ($ apiKey , $ options = []) {
19+ $ this ->_apiKey = $ apiKey ;
20+ if (!isset ($ options ['base_uri ' ])) {
21+ $ this ->_host = 'app.launchdarkly.com ' ;
22+ $ this ->_port = 443 ;
23+ $ this ->_ssl = true ;
24+ }
25+ else {
26+ $ url = parse_url ($ options ['base_uri ' ]);
27+ $ this ->_host = $ url ['host ' ];
28+ $ this ->_ssl = $ url ['scheme ' ] === 'https ' ;
29+ if (isset ($ url ['port ' ])) {
30+ $ this ->_port = $ url ['port ' ];
31+ }
32+ else {
33+ $ this ->_port = $ this ->_ssl ? 443 : 80 ;
34+ }
35+ }
36+
37+ $ this ->_capacity = $ options ['capacity ' ];
38+ $ this ->_timeout = $ options ['timeout ' ];
39+
40+ $ this ->_queue = array ();
41+ }
42+
43+ public function __destruct () {
44+ $ this ->flush ();
45+ }
46+
47+ public function sendEvent ($ event ) {
48+ return $ this ->enqueue ($ event );
49+ }
50+
51+ public function enqueue ($ event ) {
52+ if (count ($ this ->_queue ) > $ this ->_capacity ) {
53+ return false ;
54+ }
55+
56+ array_push ($ this ->_queue , $ event );
57+
58+ return true ;
59+ }
60+
61+ protected function flush () {
62+ $ socket = $ this ->createSocket ();
63+
64+ if (!$ socket ) {
65+ error_log ("LaunchDarkly unable to open socket " );
66+ return ;
67+ }
68+ $ payload = json_encode ($ this ->_queue );
69+
70+ $ body = $ this ->createBody ($ payload );
71+
72+ return $ this ->makeRequest ($ socket , $ body );
73+ }
74+
75+ private function createSocket () {
76+ if ($ this ->_socket_failed ) {
77+ return false ;
78+ }
79+
80+ $ protocol = $ this ->_ssl ? "ssl " : "tcp " ;
81+
82+ try {
83+
84+ $ socket = @pfsockopen ($ protocol . ":// " . $ this ->_host , $ this ->_port , $ errno , $ errstr , $ this ->_timeout );
85+
86+ if ($ errno != 0 ) {
87+ $ this ->_socket_failed = true ;
88+ return false ;
89+ }
90+
91+ return $ socket ;
92+ } catch (Exception $ e ) {
93+ error_log ("LaunchDarkly caught $ e " );
94+ $ this ->socket_failed = true ;
95+ return false ;
96+ }
97+ }
98+
99+ private function createBody ($ content ) {
100+ $ req = "" ;
101+ $ req .= "POST /api/events/bulk HTTP/1.1 \r\n" ;
102+ $ req .= "Host: " . $ this ->_host . "\r\n" ;
103+ $ req .= "Content-Type: application/json \r\n" ;
104+ $ req .= "Authorization: api_key " . $ this ->_apiKey . "\r\n" ;
105+ $ req .= "User-Agent: PHPClient/ " . LDClient::VERSION . "\r\n" ;
106+ $ req .= "Accept: application/json \r\n" ;
107+ $ req .= "Content-length: " . strlen ($ content ) . "\r\n" ;
108+ $ req .= "\r\n" ;
109+ $ req .= $ content ;
110+ return $ req ;
111+ }
112+
113+ private function makeRequest ($ socket , $ req , $ retry = true ) {
114+ $ bytes_written = 0 ;
115+ $ bytes_total = strlen ($ req );
116+ $ closed = false ;
117+
118+ while (!$ closed && $ bytes_written < $ bytes_total ) {
119+ try {
120+ $ written = @fwrite ($ socket , substr ($ req , $ bytes_written ));
121+ } catch (Exception $ e ) {
122+ error_log ("LaunchDarkly caught $ e " );
123+ $ closed = true ;
124+ }
125+ if (!isset ($ written ) || !$ written ) {
126+ $ closed = true ;
127+ } else {
128+ $ bytes_written += $ written ;
129+ }
130+ }
131+
132+ if ($ closed ) {
133+ fclose ($ socket );
134+ if ($ retry ) {
135+ error_log ("LaunchDarkly retrying send " );
136+ $ socket = $ this ->createSocket ();
137+ if ($ socket ) return $ this ->makeRequest ($ socket , $ req , false );
138+ }
139+ return false ;
140+ }
141+
142+ return true ;
143+ }
144+
145+
146+ }
0 commit comments