33module redis
44
55import net
6+ import net.ssl
67import strings
78
89// RedisValue represents all possible RESP (Redis Serialization Protocol) data types
@@ -19,7 +20,9 @@ pub struct DB {
1920pub mut :
2021 version int // RESP protocol version
2122mut :
22- conn & net.TcpConn = unsafe { nil } // TCP connection to Redis
23+ conn & net.TcpConn = unsafe { nil } // TCP connection to Redis
24+ ssl_conn & ssl.SSLConn = unsafe { nil } // SSL connection to Redis
25+ tls bool
2326
2427 // Pre-allocated buffers to reduce memory allocations
2528 cmd_buf []u8 // Buffer for building commands
@@ -36,18 +39,27 @@ pub mut:
3639 host string = '127.0.0.1' // Redis server host
3740 port u16 = 6379 // Redis server port
3841 password string // Redis server password (optional)
42+ tls bool // Enable TLS/SSL connection
3943 version int = 2 // RESP protocol version (default: v2)
4044}
4145
4246// connect establishes a connection to a Redis server
4347pub fn connect (config Config) ! DB {
4448 mut db := DB{
45- conn: net.dial_tcp ('${config.host} :${config.port} ' )!
4649 version: config.version
50+ tls: config.tls
4751 cmd_buf: []u8 {cap: cmd_buf_pre_allocate_len}
4852 resp_buf: []u8 {cap: resp_buf_pre_allocate_len}
4953 }
5054
55+ if config.tls {
56+ mut ssl_conn := ssl.new_ssl_conn (ssl.SSLConnectConfig{ validate: false })!
57+ ssl_conn.dial (config.host, int (config.port))!
58+ db.ssl_conn = ssl_conn
59+ } else {
60+ db.conn = net.dial_tcp ('${config.host} :${config.port} ' )!
61+ }
62+
5163 // Authenticate if password is provided
5264 if config.password.len > 0 {
5365 db.auth (config.password)!
@@ -58,7 +70,36 @@ pub fn connect(config Config) !DB {
5870
5971// close terminates the connection to Redis server
6072pub fn (mut db DB) close () ! {
61- db.conn.close ()!
73+ if db.tls {
74+ db.ssl_conn.close ()!
75+ } else {
76+ db.conn.close ()!
77+ }
78+ }
79+
80+ // Helper methods for TLS abstraction
81+ fn (mut db DB) write_data (data []u8 ) ! {
82+ if db.tls {
83+ db.ssl_conn.write (data)!
84+ } else {
85+ db.conn.write (data)!
86+ }
87+ }
88+
89+ fn (mut db DB) read_data (mut buf []u8 ) ! int {
90+ if db.tls {
91+ return db.ssl_conn.read (mut buf)
92+ } else {
93+ return db.conn.read (mut buf)
94+ }
95+ }
96+
97+ fn (mut db DB) read_ptr_data (ptr & u8 , len int ) ! int {
98+ if db.tls {
99+ return db.ssl_conn.socket_read_into_ptr (ptr, len)!
100+ } else {
101+ return db.conn.read_ptr (ptr, len)!
102+ }
62103}
63104
64105// auth sends an AUTH command to the server with the given password.
@@ -78,8 +119,7 @@ pub fn (mut db DB) auth(password string) ! {
78119
79120// ping sends a PING command to verify server responsiveness
80121pub fn (mut db DB) ping () ! string {
81- db.conn.write_string ('*1\r\n $4 \r\n PING\r\n ' )!
82- return db.read_response ()! as string
122+ return db.cmd ('PING' )! as string
83123}
84124
85125// del deletes a `key`
@@ -92,7 +132,7 @@ pub fn (mut db DB) del(key string) !i64 {
92132 db.pipeline_buffer << db.cmd_buf
93133 db.pipeline_cmd_count++
94134 } else {
95- db.conn. write (db.cmd_buf)!
135+ db.write_data (db.cmd_buf)!
96136
97137 // read resp
98138 return db.read_response ()! as i64
@@ -121,7 +161,7 @@ pub fn (mut db DB) set[T](key string, value T) !string {
121161 db.pipeline_buffer << db.cmd_buf
122162 db.pipeline_cmd_count++
123163 } else {
124- db.conn. write (db.cmd_buf)!
164+ db.write_data (db.cmd_buf)!
125165 return db.read_response ()! as string
126166 }
127167 return ''
@@ -137,7 +177,7 @@ pub fn (mut db DB) get[T](key string) !T {
137177 db.pipeline_buffer << db.cmd_buf
138178 db.pipeline_cmd_count++
139179 } else {
140- db.conn. write (db.cmd_buf)!
180+ db.write_data (db.cmd_buf)!
141181 resp := db.read_response ()!
142182 match resp {
143183 []u8 {
@@ -171,7 +211,7 @@ pub fn (mut db DB) incr(key string) !i64 {
171211 db.pipeline_buffer << db.cmd_buf
172212 db.pipeline_cmd_count++
173213 } else {
174- db.conn. write (db.cmd_buf)!
214+ db.write_data (db.cmd_buf)!
175215
176216 // read resp
177217 return db.read_response ()! as i64
@@ -189,7 +229,7 @@ pub fn (mut db DB) decr(key string) !i64 {
189229 db.pipeline_buffer << db.cmd_buf
190230 db.pipeline_cmd_count++
191231 } else {
192- db.conn. write (db.cmd_buf)!
232+ db.write_data (db.cmd_buf)!
193233
194234 // read resp
195235 return db.read_response ()! as i64
@@ -222,7 +262,7 @@ pub fn (mut db DB) hset[T](key string, m map[string]T) !int {
222262 db.pipeline_buffer << db.cmd_buf
223263 db.pipeline_cmd_count++
224264 } else {
225- db.conn. write (db.cmd_buf)!
265+ db.write_data (db.cmd_buf)!
226266 return int (db.read_response ()! as i64 )
227267 }
228268 return 0
@@ -239,7 +279,7 @@ pub fn (mut db DB) hget[T](key string, m_key string) !T {
239279 db.pipeline_buffer << db.cmd_buf
240280 db.pipeline_cmd_count++
241281 } else {
242- db.conn. write (db.cmd_buf)!
282+ db.write_data (db.cmd_buf)!
243283 resp := db.read_response ()! as []u8
244284 $if T is string {
245285 return resp.bytestr ()
@@ -266,7 +306,7 @@ pub fn (mut db DB) hgetall[T](key string) !map[string]T {
266306 db.pipeline_buffer << db.cmd_buf
267307 db.pipeline_cmd_count++
268308 } else {
269- db.conn. write (db.cmd_buf)!
309+ db.write_data (db.cmd_buf)!
270310 resp := db.read_response ()!
271311 match resp {
272312 []RedisValue {
@@ -315,7 +355,7 @@ pub fn (mut db DB) expire(key string, seconds int) !bool {
315355 db.pipeline_buffer << db.cmd_buf
316356 db.pipeline_cmd_count++
317357 } else {
318- db.conn. write (db.cmd_buf)!
358+ db.write_data (db.cmd_buf)!
319359
320360 // read resp
321361 resp := db.read_response ()! as i64
@@ -331,7 +371,7 @@ fn (mut db DB) read_response_bulk_string() !RedisValue {
331371
332372 db.resp_buf.clear ()
333373 for {
334- bytes_read := db.conn. read (mut chunk) or {
374+ bytes_read := db.read_data (mut chunk) or {
335375 return error ('`read_response_bulk_string()`: connection error ${err} ' )
336376 }
337377 if bytes_read == 0 {
@@ -355,7 +395,7 @@ fn (mut db DB) read_response_bulk_string() !RedisValue {
355395
356396 if data_length == 0 {
357397 mut terminator := []u8 {len: 2 }
358- db.conn. read (mut terminator)!
398+ db.read_data (mut terminator)!
359399 if terminator[0 ] != `\r ` || terminator[1 ] != `\n ` {
360400 return error ('invalid terminator for empty string' )
361401 }
@@ -373,7 +413,7 @@ fn (mut db DB) read_response_bulk_string() !RedisValue {
373413 chunk_size := if remaining > 1 { 1 } else { remaining }
374414 mut chunk_ptr := unsafe { & data_buf[total_read] }
375415
376- bytes_read := db.conn. read_ptr (chunk_ptr, chunk_size)!
416+ bytes_read := db.read_ptr_data (chunk_ptr, chunk_size)!
377417 total_read + = bytes_read
378418
379419 if bytes_read == 0 && total_read < data_buf.len {
@@ -400,7 +440,7 @@ fn (mut db DB) read_response_i64() !i64 {
400440 chunk_size := if remaining > 1 { 1 } else { remaining }
401441 mut chunk_ptr := unsafe { & db.resp_buf[total_read] }
402442
403- bytes_read := db.conn. read_ptr (chunk_ptr, chunk_size)!
443+ bytes_read := db.read_ptr_data (chunk_ptr, chunk_size)!
404444 total_read + = bytes_read
405445
406446 if total_read > 2 {
@@ -427,7 +467,7 @@ fn (mut db DB) read_response_simple_string() !string {
427467 chunk_size := if remaining > 1 { 1 } else { remaining }
428468 mut chunk_ptr := unsafe { & db.resp_buf[total_read] }
429469
430- bytes_read := db.conn. read_ptr (chunk_ptr, chunk_size)!
470+ bytes_read := db.read_ptr_data (chunk_ptr, chunk_size)!
431471 total_read + = bytes_read
432472
433473 if total_read > 2 {
@@ -449,7 +489,7 @@ fn (mut db DB) read_response_array() !RedisValue {
449489
450490 db.resp_buf.clear ()
451491 for {
452- bytes_read := db.conn. read (mut chunk) or {
492+ bytes_read := db.read_data (mut chunk) or {
453493 return error ('`read_response_array()`: connection error: ${err} ' )
454494 }
455495 if bytes_read == 0 {
@@ -492,7 +532,7 @@ fn (mut db DB) read_response_array() !RedisValue {
492532fn (mut db DB) read_response () ! RedisValue {
493533 db.resp_buf.clear ()
494534 unsafe { db.resp_buf.grow_len (1 ) }
495- read_len := db.conn. read (mut db.resp_buf)!
535+ read_len := db.read_data (mut db.resp_buf)!
496536 if read_len != 1 {
497537 return error ('`read_response()`: empty response from server' )
498538 }
@@ -532,7 +572,7 @@ pub fn (mut db DB) cmd(cmd ...string) !RedisValue {
532572 db.pipeline_buffer << unsafe { sb.reuse_as_plain_u8_array () }
533573 db.pipeline_cmd_count++
534574 } else {
535- unsafe { db.conn. write ( sb.reuse_as_plain_u8_array ()) ! }
575+ db. write_data ( unsafe { sb.reuse_as_plain_u8_array () }) !
536576 return db.read_response ()!
537577 }
538578 return RedisNull{}
@@ -557,7 +597,7 @@ pub fn (mut db DB) pipeline_execute() ![]RedisValue {
557597 return []RedisValue{}
558598 }
559599
560- db.conn. write (db.pipeline_buffer)!
600+ db.write_data (db.pipeline_buffer)!
561601
562602 mut results := []RedisValue{cap: db.pipeline_cmd_count}
563603 for _ in 0 .. db.pipeline_cmd_count {
0 commit comments