1 /*
2  * Copyright (C) 2019, HuntLabs
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 module hunt.database.driver.postgresql.PostgreSQLConnectOptions;
19 
20 import hunt.database.driver.postgresql.SslMode;
21 // import hunt.database.driver.postgresql.impl.PgConnectionUriParser;
22 // import io.vertx.codegen.annotations.DataObject;
23 // import io.vertx.core.buffer.Buffer;
24 // import io.vertx.core.json.JsonObject;
25 // import io.vertx.core.net.*;
26 import hunt.database.base.SqlConnectOptions;
27 
28 import hunt.collection.Collections;
29 import hunt.collection.HashMap;
30 import hunt.collection.Map;
31 import hunt.collection.Set;
32 import hunt.net.OpenSSLEngineOptions;
33 import hunt.net.ProxyOptions;
34 import hunt.net.util.HttpURI;
35 import hunt.Exceptions;
36 
37 import core.time;
38 import std.concurrency : initOnce;
39 import std.string;
40 
41 
42 /**
43  * @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
44  * @author Billy Yuan <billy112487983@gmail.com>
45  */
46 class PgConnectOptions : SqlConnectOptions {
47 
48     /**
49      * Provide a {@link PgConnectOptions} configured from a connection URI.
50      *
51      * @param connectionUri the connection URI to configure from
52      * @return a {@link PgConnectOptions} parsed from the connection URI
53      * @throws IllegalArgumentException when the {@code connectionUri} is in an invalid format
54      */
55     static PgConnectOptions fromUri(string connectionUri) {
56         return new PgConnectOptions(new HttpURI(connectionUri));
57     }
58 
59     /**
60      * Provide a {@link PgConnectOptions} configured with environment variables, if the environment variable
61      * is not set, then a default value will take precedence over this.
62      */
63     // static PgConnectOptions fromEnv() {
64     //     PgConnectOptions pgConnectOptions = new PgConnectOptions();
65 
66     //     if (getenv("PGHOSTADDR") is null) {
67     //         if (getenv("PGHOST") !is null) {
68     //             pgConnectOptions.setHost(getenv("PGHOST"));
69     //         }
70     //     } else {
71     //         pgConnectOptions.setHost(getenv("PGHOSTADDR"));
72     //     }
73 
74     //     if (getenv("PGPORT") !is null) {
75     //         try {
76     //             pgConnectOptions.setPort(parseInt(getenv("PGPORT")));
77     //         } catch (NumberFormatException e) {
78     //             // port will be set to default
79     //         }
80     //     }
81 
82     //     if (getenv("PGDATABASE") !is null) {
83     //         pgConnectOptions.setDatabase(getenv("PGDATABASE"));
84     //     }
85     //     if (getenv("PGUSER") !is null) {
86     //         pgConnectOptions.setUser(getenv("PGUSER"));
87     //     }
88     //     if (getenv("PGPASSWORD") !is null) {
89     //         pgConnectOptions.setPassword(getenv("PGPASSWORD"));
90     //     }
91     //     if (getenv("PGSSLMODE") !is null) {
92     //         pgConnectOptions.setSslMode(SslMode.of(getenv("PGSSLMODE")));
93     //     }
94     //     return pgConnectOptions;
95     // }
96 
97     enum string DEFAULT_HOST = "localhost";
98     static int DEFAULT_PORT = 5432;
99     enum string DEFAULT_DATABASE = "db";
100     enum string DEFAULT_USER = "user";
101     enum string DEFAULT_PASSWORD = "pass";
102     enum int DEFAULT_PIPELINING_LIMIT = 256;
103     enum SslMode DEFAULT_SSLMODE = SslMode.DISABLE;
104     enum string[string] DEFAULT_PROPERTIES = [
105             "application_name" : "hunt-pg-client",
106             "client_encoding" : "utf8",     
107             "DateStyle" : "ISO", 
108             "intervalStyle" : "postgres",   
109             "extra_float_digits" : "2"];
110 
111     private int pipeliningLimit;
112     private SslMode sslMode;
113 
114     this() {
115         super();
116     }
117 
118     this(HttpURI uri) {        
119         super(uri);
120     }
121 
122     this(PgConnectOptions other) {
123         super(other);
124         pipeliningLimit = other.pipeliningLimit;
125         sslMode = other.sslMode;
126     }
127 
128     override
129     PgConnectOptions setHost(string host) {
130         return cast(PgConnectOptions) super.setHost(host);
131     }
132 
133     override
134     PgConnectOptions setPort(int port) {
135         return cast(PgConnectOptions) super.setPort(port);
136     }
137 
138     override
139     PgConnectOptions setUser(string user) {
140         return cast(PgConnectOptions) super.setUser(user);
141     }
142 
143     override
144     PgConnectOptions setPassword(string password) {
145         return cast(PgConnectOptions) super.setPassword(password);
146     }
147 
148     override
149     PgConnectOptions setDatabase(string database) {
150         return cast(PgConnectOptions) super.setDatabase(database);
151     }
152 
153     int getPipeliningLimit() {
154         return pipeliningLimit;
155     }
156 
157     PgConnectOptions setPipeliningLimit(int pipeliningLimit) {
158         if (pipeliningLimit < 1) {
159             throw new IllegalArgumentException();
160         }
161         this.pipeliningLimit = pipeliningLimit;
162         return this;
163     }
164 
165     override PgConnectOptions setCachePreparedStatements(bool cachePreparedStatements) {
166         return cast(PgConnectOptions) super.setCachePreparedStatements(cachePreparedStatements);
167     }
168 
169     override
170     PgConnectOptions setPreparedStatementCacheMaxSize(int preparedStatementCacheMaxSize) {
171         return cast(PgConnectOptions) super.setPreparedStatementCacheMaxSize(preparedStatementCacheMaxSize);
172     }
173 
174     override
175     PgConnectOptions setPreparedStatementCacheSqlLimit(int preparedStatementCacheSqlLimit) {
176         return cast(PgConnectOptions) super.setPreparedStatementCacheSqlLimit(preparedStatementCacheSqlLimit);
177     }
178 
179     override
180     PgConnectOptions setProperties(Map!(string, string) properties) {
181         return cast(PgConnectOptions) super.setProperties(properties);
182     }
183 
184     override
185     PgConnectOptions addProperty(string key, string value) {
186         return cast(PgConnectOptions) super.addProperty(key, value);
187     }
188 
189     /**
190      * @return the value of current sslmode
191      */
192     SslMode getSslMode() {
193         return sslMode;
194     }
195 
196     /**
197      * Set {@link SslMode} for the client, this option can be used to provide different levels of secure protection.
198      *
199      * @param sslmode the value of sslmode
200      * @return a reference to this, so the API can be used fluently
201      */
202     PgConnectOptions setSslMode(SslMode sslmode) {
203         this.sslMode = sslmode;
204         return this;
205     }
206 
207     override
208     PgConnectOptions setSendBufferSize(int sendBufferSize) {
209         return cast(PgConnectOptions) super.setSendBufferSize(sendBufferSize);
210     }
211 
212     override
213     PgConnectOptions setReceiveBufferSize(int receiveBufferSize) {
214         return cast(PgConnectOptions) super.setReceiveBufferSize(receiveBufferSize);
215     }
216 
217     override
218     PgConnectOptions setDecoderBufferSize(int size) {
219         return cast(PgConnectOptions) super.setDecoderBufferSize(size);
220     }
221 
222     override
223     PgConnectOptions setEncoderBufferSize(int size) {
224         return cast(PgConnectOptions) super.setEncoderBufferSize(size);
225     }
226 
227     override
228     PgConnectOptions setReuseAddress(bool reuseAddress) {
229         return cast(PgConnectOptions) super.setReuseAddress(reuseAddress);
230     }
231 
232     override
233     PgConnectOptions setTrafficClass(int trafficClass) {
234         return cast(PgConnectOptions) super.setTrafficClass(trafficClass);
235     }
236 
237     override
238     PgConnectOptions setTcpNoDelay(bool tcpNoDelay) {
239         return cast(PgConnectOptions) super.setTcpNoDelay(tcpNoDelay);
240     }
241 
242     override
243     PgConnectOptions setTcpKeepAlive(bool tcpKeepAlive) {
244         return cast(PgConnectOptions) super.setTcpKeepAlive(tcpKeepAlive);
245     }
246 
247     override
248     PgConnectOptions setSoLinger(int soLinger) {
249         return cast(PgConnectOptions) super.setSoLinger(soLinger);
250     }
251 
252     // override
253     // PgConnectOptions setUsePooledBuffers(bool usePooledBuffers) {
254     //     return cast(PgConnectOptions) super.setUsePooledBuffers(usePooledBuffers);
255     // }
256 
257     override
258     PgConnectOptions setIdleTimeout(Duration idleTimeout) {
259         return cast(PgConnectOptions) super.setIdleTimeout(idleTimeout);
260     }
261 
262     // override
263     // PgConnectOptions setIdleTimeoutUnit(TimeUnit idleTimeoutUnit) {
264     //     return cast(PgConnectOptions) super.setIdleTimeoutUnit(idleTimeoutUnit);
265     // }
266 
267     override
268     PgConnectOptions setSsl(bool ssl) {
269         if (ssl) {
270             setSslMode(SslMode.VERIFY_CA);
271         } else {
272             setSslMode(SslMode.DISABLE);
273         }
274         return this;
275     }
276 
277     // override
278     // PgConnectOptions setKeyCertOptions(KeyCertOptions options) {
279     //     return cast(PgConnectOptions) super.setKeyCertOptions(options);
280     // }
281 
282     // override
283     // PgConnectOptions setKeyStoreOptions(JksOptions options) {
284     //     return cast(PgConnectOptions) super.setKeyStoreOptions(options);
285     // }
286 
287     // override
288     // PgConnectOptions setPfxKeyCertOptions(PfxOptions options) {
289     //     return cast(PgConnectOptions) super.setPfxKeyCertOptions(options);
290     // }
291 
292     // override
293     // PgConnectOptions setPemKeyCertOptions(PemKeyCertOptions options) {
294     //     return cast(PgConnectOptions) super.setPemKeyCertOptions(options);
295     // }
296 
297     // override
298     // PgConnectOptions setTrustOptions(TrustOptions options) {
299     //     return cast(PgConnectOptions) super.setTrustOptions(options);
300     // }
301 
302     // override
303     // PgConnectOptions setTrustStoreOptions(JksOptions options) {
304     //     return cast(PgConnectOptions) super.setTrustStoreOptions(options);
305     // }
306 
307     // override
308     // PgConnectOptions setPemTrustOptions(PemTrustOptions options) {
309     //     return cast(PgConnectOptions) super.setPemTrustOptions(options);
310     // }
311 
312     // override
313     // PgConnectOptions setPfxTrustOptions(PfxOptions options) {
314     //     return cast(PgConnectOptions) super.setPfxTrustOptions(options);
315     // }
316 
317     // override
318     // PgConnectOptions addEnabledCipherSuite(string suite) {
319     //     return cast(PgConnectOptions) super.addEnabledCipherSuite(suite);
320     // }
321 
322     // override
323     // PgConnectOptions addEnabledSecureTransportProtocol(string protocol) {
324     //     return cast(PgConnectOptions) super.addEnabledSecureTransportProtocol(protocol);
325     // }
326 
327     // override
328     // PgConnectOptions addCrlPath(string crlPath) {
329     //     return cast(PgConnectOptions) super.addCrlPath(crlPath);
330     // }
331 
332     // override
333     // PgConnectOptions addCrlValue(Buffer crlValue) {
334     //     return cast(PgConnectOptions) super.addCrlValue(crlValue);
335     // }
336 
337     // override
338     // PgConnectOptions setTrustAll(bool trustAll) {
339     //     return cast(PgConnectOptions) super.setTrustAll(trustAll);
340     // }
341 
342     override
343     PgConnectOptions setConnectTimeout(Duration connectTimeout) {
344         return cast(PgConnectOptions) super.setConnectTimeout(connectTimeout);
345     }
346 
347     override
348     PgConnectOptions setMetricsName(string metricsName) {
349         return cast(PgConnectOptions) super.setMetricsName(metricsName);
350     }
351 
352     override
353     PgConnectOptions setReconnectAttempts(int attempts) {
354         return cast(PgConnectOptions) super.setReconnectAttempts(attempts);
355     }
356 
357     override
358     PgConnectOptions setHostnameVerificationAlgorithm(string hostnameVerificationAlgorithm) {
359         return cast(PgConnectOptions) super.setHostnameVerificationAlgorithm(hostnameVerificationAlgorithm);
360     }
361 
362     override
363     PgConnectOptions setLogActivity(bool logEnabled) {
364         return cast(PgConnectOptions) super.setLogActivity(logEnabled);
365     }
366 
367     override
368     PgConnectOptions setReconnectInterval(Duration interval) {
369         return cast(PgConnectOptions) super.setReconnectInterval(interval);
370     }
371 
372     override
373     PgConnectOptions setProxyOptions(ProxyOptions proxyOptions) {
374         return cast(PgConnectOptions) super.setProxyOptions(proxyOptions);
375     }
376 
377     override
378     PgConnectOptions setLocalAddress(string localAddress) {
379         return cast(PgConnectOptions) super.setLocalAddress(localAddress);
380     }
381 
382     override
383     PgConnectOptions setUseAlpn(bool useAlpn) {
384         return cast(PgConnectOptions) super.setUseAlpn(useAlpn);
385     }
386 
387     // override
388     // PgConnectOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) {
389     //     return cast(PgConnectOptions) super.setSslEngineOptions(sslEngineOptions);
390     // }
391 
392     // override
393     // PgConnectOptions setJdkSslEngineOptions(JdkSSLEngineOptions sslEngineOptions) {
394     //     return cast(PgConnectOptions) super.setJdkSslEngineOptions(sslEngineOptions);
395     // }
396 
397     override
398     PgConnectOptions setOpenSslEngineOptions(OpenSSLEngineOptions sslEngineOptions) {
399         return cast(PgConnectOptions) super.setOpenSslEngineOptions(sslEngineOptions);
400     }
401 
402     override
403     PgConnectOptions setReusePort(bool reusePort) {
404         return cast(PgConnectOptions) super.setReusePort(reusePort);
405     }
406 
407     override
408     PgConnectOptions setTcpFastOpen(bool tcpFastOpen) {
409         return cast(PgConnectOptions) super.setTcpFastOpen(tcpFastOpen);
410     }
411 
412     override
413     PgConnectOptions setTcpCork(bool tcpCork) {
414         return cast(PgConnectOptions) super.setTcpCork(tcpCork);
415     }
416 
417     override
418     PgConnectOptions setTcpQuickAck(bool tcpQuickAck) {
419         return cast(PgConnectOptions) super.setTcpQuickAck(tcpQuickAck);
420     }
421 
422     // override
423     // PgConnectOptions setEnabledSecureTransportProtocols(Set!(string) enabledSecureTransportProtocols) {
424     //     return cast(PgConnectOptions) super.setEnabledSecureTransportProtocols(enabledSecureTransportProtocols);
425     // }
426 
427     override
428     PgConnectOptions setSslHandshakeTimeout(Duration sslHandshakeTimeout) {
429         return cast(PgConnectOptions) super.setSslHandshakeTimeout(sslHandshakeTimeout);
430     }
431 
432     // override
433     // PgConnectOptions setSslHandshakeTimeoutUnit(TimeUnit sslHandshakeTimeoutUnit) {
434     //     return cast(PgConnectOptions) super.setSslHandshakeTimeoutUnit(sslHandshakeTimeoutUnit);
435     // }
436 
437     /**
438      * Initialize with the default options.
439      */
440     override protected void initialize() {
441         this.setHost(DEFAULT_HOST);
442         this.setPort(DEFAULT_PORT);
443         this.setUser(DEFAULT_USER);
444         this.setPassword(DEFAULT_PASSWORD);
445         this.setDatabase(DEFAULT_DATABASE);
446         pipeliningLimit = DEFAULT_PIPELINING_LIMIT;
447         sslMode = DEFAULT_SSLMODE;
448         this.setProperties(new HashMap!(string, string)(DEFAULT_PROPERTIES));
449     }
450 
451     // override
452     // JsonObject toJson() {
453     //     JsonObject json = super.toJson();
454     //     PgConnectOptionsConverter.toJson(this, json);
455     //     return json;
456     // }
457 
458     override
459     bool opEquals(Object o) {
460         if (this is o) return true;
461         if (!super.opEquals(o)) return false;
462 
463         PgConnectOptions that = cast(PgConnectOptions) o;
464         if(that is null) return false;
465 
466         if (pipeliningLimit != that.pipeliningLimit) return false;
467         if (sslMode != that.sslMode) return false;
468 
469         return true;
470     }
471 
472     override
473     size_t toHash() @trusted nothrow {
474         size_t result = super.toHash();
475         result = 31 * result + pipeliningLimit;
476         result = 31 * result + sslMode.hashOf();
477         return result;
478     }
479 
480     bool isUsingDomainSocket() {
481         return this.getHost().startsWith("/");
482     }
483 }