1 /*
2  * Hunt - A redis client library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11  
12 module hunt.redis.RedisFactory;
13 
14 import hunt.pool.PooledObject;
15 import hunt.pool.PooledObjectFactory;
16 import hunt.pool.impl.DefaultPooledObject;
17 
18 import hunt.redis.BinaryRedis;
19 import hunt.redis.Exceptions;
20 import hunt.redis.HostAndPort;
21 import hunt.redis.Redis;
22 import hunt.redis.util.RedisURIHelper;
23 
24 import hunt.logging.ConsoleLogger;
25 import hunt.net.util.HttpURI;
26 
27 import std.format;
28 import std.range;
29 
30 /**
31  * PoolableObjectFactory custom impl.
32  */
33 class RedisFactory : PooledObjectFactory!(Redis) {
34     private HostAndPort hostAndPort; 
35     private int connectionTimeout;
36     private int soTimeout;
37     private string password;
38     private int database;
39     private string clientName;
40     private bool ssl;
41     // private SSLSocketFactory sslSocketFactory;
42     // private SSLParameters sslParameters;
43     // private HostnameVerifier hostnameVerifier;
44 
45     this(string host, int port, int connectionTimeout, int soTimeout,
46             string password, int database, string clientName) {
47         this.hostAndPort = new HostAndPort(host, port);
48         this.connectionTimeout = connectionTimeout;
49         this.soTimeout = soTimeout;
50         this.password = password;
51         this.database = database;
52         this.clientName = clientName;
53         this.ssl = false;
54     }
55 
56     this(HttpURI uri, int connectionTimeout, int soTimeout, string clientName) {
57         if (!RedisURIHelper.isValid(uri)) {
58             throw new InvalidURIException(format(
59                     "Cannot open Redis connection due invalid HttpURI. %s", uri.toString()));
60         }
61 
62         this.hostAndPort = new HostAndPort(uri.getHost(), uri.getPort());
63         this.connectionTimeout = connectionTimeout;
64         this.soTimeout = soTimeout;
65         this.password = RedisURIHelper.getPassword(uri);
66         this.database = RedisURIHelper.getDBIndex(uri);
67         this.clientName = clientName;
68         this.ssl = false; //RedisURIHelper.isRedisSSLScheme(uri);
69     }
70 
71     void setHostAndPort(HostAndPort hostAndPort) {
72         this.hostAndPort = hostAndPort;
73     }
74 
75     void activateObject(IPooledObject pooledRedis) {
76         Redis redis = (cast(PooledObject!Redis)pooledRedis).getObject();
77         if (redis.getDB() != database) {
78             redis.select(database);
79         }
80     }
81 
82     void destroyObject(IPooledObject pooledRedis) {
83         Redis redis = (cast(PooledObject!Redis)pooledRedis).getObject();
84         if (redis.isConnected()) {
85             try {
86                 try {
87                     redis.quit();
88                 } catch (Exception e) {
89                 }
90                 redis.disconnect();
91             } catch (Exception e) {
92 
93             }
94         }
95 
96     }
97 
98     IPooledObject makeObject() {
99         HostAndPort hostAndPort = this.hostAndPort;
100         
101         version(HUNT_REDIS_DEBUG) infof("%s", hostAndPort.toString());
102         Redis redis = new Redis(hostAndPort.getHost(), hostAndPort.getPort(),
103                 connectionTimeout, soTimeout, ssl);
104 
105         try {
106             redis.connect();
107 
108             if (!password.empty) {
109                 redis.auth(password);
110             }
111 
112             if (database != 0) {
113                 redis.select(database);
114             }
115             if (clientName !is null) {
116                 redis.clientSetname(clientName);
117             }
118         } catch (RedisException je) {
119             debug warning(je.msg);
120             version(HUNT_DEBUG) warning(je);
121             redis.close();
122             throw je;
123         }
124 
125         return new DefaultPooledObject!(Redis)(redis);
126 
127     }
128 
129     void passivateObject(IPooledObject pooledRedis) {
130         // TODO maybe should select db 0? Not sure right now.
131     }
132 
133     bool validateObject(IPooledObject pooledRedis) {
134         BinaryRedis redis = cast(BinaryRedis)(cast(PooledObject!Redis)pooledRedis).getObject();
135         try {
136             HostAndPort hostAndPort = this.hostAndPort;
137 
138             string connectionHost = redis.getClient().getHost();
139             int connectionPort = redis.getClient().getPort();
140 
141             return hostAndPort.getHost() == connectionHost && hostAndPort.getPort() == connectionPort
142                 && redis.isConnected() && redis.ping() == "PONG";
143         } catch (Exception e) {
144             return false;
145         }
146     }
147 }