33# SPDX-License-Identifier: MIT 
44
55""" 
6- `adafruit_esp32spi_socket ` 
6+ `adafruit_esp32spi_socketpool ` 
77================================================================================ 
88
99A socket compatible interface thru the ESP SPI command set 
1010
1111* Author(s): ladyada 
1212""" 
13+ from  __future__ import  annotations 
14+ 
15+ try :
16+     from  typing  import  TYPE_CHECKING , Optional 
17+ 
18+     if  TYPE_CHECKING :
19+         from  esp32spi .adafruit_esp32spi  import  ESP_SPIcontrol 
20+ except  ImportError :
21+     pass 
1322
14- # pylint: disable=no-name-in-module 
1523
1624import  time 
1725import  gc 
1826from  micropython  import  const 
19- from  adafruit_esp32spi  import  adafruit_esp32spi 
27+ from  adafruit_esp32spi  import  adafruit_esp32spi   as   esp32spi 
2028
21- _the_interface  =  None    # pylint: disable=invalid-name 
29+ _global_socketpool  =  {} 
2230
2331
24- def  set_interface (iface ):
25-     """Helper to set the global internet interface""" 
26-     global  _the_interface   # pylint: disable=global-statement, invalid-name 
27-     _the_interface  =  iface 
32+ class  SocketPoolContants :  # pylint: disable=too-few-public-methods 
33+     """Helper class for the constants that are needed everywhere""" 
2834
35+     SOCK_STREAM  =  const (0 )
36+     SOCK_DGRAM  =  const (1 )
37+     AF_INET  =  const (2 )
38+     NO_SOCKET_AVAIL  =  const (255 )
2939
30- SOCK_STREAM  =  const (0 )
31- SOCK_DGRAM  =  const (1 )
32- AF_INET  =  const (2 )
33- NO_SOCKET_AVAIL  =  const (255 )
40+     MAX_PACKET  =  const (4000 )
3441
35- MAX_PACKET  =  const (4000 )
3642
43+ class  SocketPool (SocketPoolContants ):
44+     """ESP32SPI SocketPool library""" 
3745
38- # pylint: disable=too-many-arguments, unused-argument 
39- def  getaddrinfo (host , port , family = 0 , socktype = 0 , proto = 0 , flags = 0 ):
40-     """Given a hostname and a port name, return a 'socket.getaddrinfo' 
41-     compatible list of tuples. Honestly, we ignore anything but host & port""" 
42-     if  not  isinstance (port , int ):
43-         raise  ValueError ("Port must be an integer" )
44-     ipaddr  =  _the_interface .get_host_by_name (host )
45-     return  [(AF_INET , socktype , proto , "" , (ipaddr , port ))]
46+     def  __new__ (cls , iface : ESP_SPIcontrol ):
47+         # We want to make sure to return the same pool for the same interface 
48+         if  iface  not  in   _global_socketpool :
49+             _global_socketpool [iface ] =  super ().__new__ (cls )
50+         return  _global_socketpool [iface ]
4651
52+     def  __init__ (self , iface : ESP_SPIcontrol ):
53+         self ._interface  =  iface 
4754
48- # pylint: enable=too-many-arguments, unused-argument 
55+     def  getaddrinfo (  # pylint: disable=too-many-arguments,unused-argument 
56+         self , host , port , family = 0 , socktype = 0 , proto = 0 , flags = 0 
57+     ):
58+         """Given a hostname and a port name, return a 'socket.getaddrinfo' 
59+         compatible list of tuples. Honestly, we ignore anything but host & port""" 
60+         if  not  isinstance (port , int ):
61+             raise  ValueError ("Port must be an integer" )
62+         ipaddr  =  self ._interface .get_host_by_name (host )
63+         return  [(SocketPoolContants .AF_INET , socktype , proto , "" , (ipaddr , port ))]
64+ 
65+     def  socket (  # pylint: disable=redefined-builtin 
66+         self ,
67+         family = SocketPoolContants .AF_INET ,
68+         type = SocketPoolContants .SOCK_STREAM ,
69+         proto = 0 ,
70+         fileno = None ,
71+     ):
72+         """Create a new socket and return it""" 
73+         return  Socket (self , family , type , proto , fileno )
4974
5075
51- # pylint: disable=unused-argument, redefined-builtin, invalid-name 
52- class  socket :
76+ class  Socket :
5377    """A simplified implementation of the Python 'socket' class, for connecting 
5478    through an interface to a remote device""" 
5579
56-     # pylint: disable=too-many-arguments 
57-     def  __init__ (
58-         self , family = AF_INET , type = SOCK_STREAM , proto = 0 , fileno = None , socknum = None 
80+     def  __init__ (  # pylint: disable=redefined-builtin,too-many-arguments,unused-argument 
81+         self ,
82+         socket_pool : SocketPool ,
83+         family : int  =  SocketPool .AF_INET ,
84+         type : int  =  SocketPool .SOCK_STREAM ,
85+         proto : int  =  0 ,
86+         fileno : Optional [int ] =  None ,
5987    ):
60-         if  family  !=  AF_INET :
88+         if  family  !=  SocketPool . AF_INET :
6189            raise  ValueError ("Only AF_INET family supported" )
90+         self ._socket_pool  =  socket_pool 
91+         self ._interface  =  self ._socket_pool ._interface 
6292        self ._type  =  type 
6393        self ._buffer  =  b"" 
64-         self ._socknum  =  socknum   if   socknum   else   _the_interface .get_socket ()
94+         self ._socknum  =  self . _interface .get_socket ()
6595        self .settimeout (0 )
6696
67-     # pylint: enable=too-many-arguments 
68- 
6997    def  __enter__ (self ):
7098        return  self 
7199
72100    def  __exit__ (self , exc_type , exc_val , exc_tb ) ->  None :
73101        self .close ()
74-         while  (
75-             _the_interface .socket_status (self ._socknum )
76-             !=  adafruit_esp32spi .SOCKET_CLOSED 
77-         ):
102+         while  self ._interface .socket_status (self ._socknum ) !=  esp32spi .SOCKET_CLOSED :
78103            pass 
79104
80105    def  connect (self , address , conntype = None ):
@@ -83,20 +108,20 @@ def connect(self, address, conntype=None):
83108        depending on the underlying interface""" 
84109        host , port  =  address 
85110        if  conntype  is  None :
86-             conntype  =  _the_interface .TCP_MODE 
87-         if  not  _the_interface .socket_connect (
111+             conntype  =  self . _interface .TCP_MODE 
112+         if  not  self . _interface .socket_connect (
88113            self ._socknum , host , port , conn_mode = conntype 
89114        ):
90115            raise  ConnectionError ("Failed to connect to host" , host )
91116        self ._buffer  =  b"" 
92117
93-     def  send (self , data ):   # pylint: disable=no-self-use 
118+     def  send (self , data ):
94119        """Send some data to the socket.""" 
95-         if  self ._type  is  SOCK_DGRAM :
96-             conntype  =  _the_interface .UDP_MODE 
120+         if  self ._type  is  SocketPool . SOCK_DGRAM :
121+             conntype  =  self . _interface .UDP_MODE 
97122        else :
98-             conntype  =  _the_interface .TCP_MODE 
99-         _the_interface .socket_write (self ._socknum , data , conn_mode = conntype )
123+             conntype  =  self . _interface .TCP_MODE 
124+         self . _interface .socket_write (self ._socknum , data , conn_mode = conntype )
100125        gc .collect ()
101126
102127    def  recv (self , bufsize : int ) ->  bytes :
@@ -140,7 +165,7 @@ def recv_into(self, buffer, nbytes: int = 0):
140165            num_avail  =  self ._available ()
141166            if  num_avail  >  0 :
142167                last_read_time  =  time .monotonic ()
143-                 bytes_read  =  _the_interface .socket_read (
168+                 bytes_read  =  self . _interface .socket_read (
144169                    self ._socknum , min (num_to_read , num_avail )
145170                )
146171                buffer [num_read  : num_read  +  len (bytes_read )] =  bytes_read 
@@ -162,43 +187,42 @@ def settimeout(self, value):
162187
163188    def  _available (self ):
164189        """Returns how many bytes of data are available to be read (up to the MAX_PACKET length)""" 
165-         if  self ._socknum  !=  NO_SOCKET_AVAIL :
166-             return  min (_the_interface .socket_available (self ._socknum ), MAX_PACKET )
190+         if  self ._socknum  !=  SocketPool .NO_SOCKET_AVAIL :
191+             return  min (
192+                 self ._interface .socket_available (self ._socknum ), SocketPool .MAX_PACKET 
193+             )
167194        return  0 
168195
169196    def  _connected (self ):
170197        """Whether or not we are connected to the socket""" 
171-         if  self ._socknum  ==  NO_SOCKET_AVAIL :
198+         if  self ._socknum  ==  SocketPool . NO_SOCKET_AVAIL :
172199            return  False 
173200        if  self ._available ():
174201            return  True 
175-         status  =  _the_interface .socket_status (self ._socknum )
202+         status  =  self . _interface .socket_status (self ._socknum )
176203        result  =  status  not  in   (
177-             adafruit_esp32spi .SOCKET_LISTEN ,
178-             adafruit_esp32spi .SOCKET_CLOSED ,
179-             adafruit_esp32spi .SOCKET_FIN_WAIT_1 ,
180-             adafruit_esp32spi .SOCKET_FIN_WAIT_2 ,
181-             adafruit_esp32spi .SOCKET_TIME_WAIT ,
182-             adafruit_esp32spi .SOCKET_SYN_SENT ,
183-             adafruit_esp32spi .SOCKET_SYN_RCVD ,
184-             adafruit_esp32spi .SOCKET_CLOSE_WAIT ,
204+             esp32spi .SOCKET_LISTEN ,
205+             esp32spi .SOCKET_CLOSED ,
206+             esp32spi .SOCKET_FIN_WAIT_1 ,
207+             esp32spi .SOCKET_FIN_WAIT_2 ,
208+             esp32spi .SOCKET_TIME_WAIT ,
209+             esp32spi .SOCKET_SYN_SENT ,
210+             esp32spi .SOCKET_SYN_RCVD ,
211+             esp32spi .SOCKET_CLOSE_WAIT ,
185212        )
186213        if  not  result :
187214            self .close ()
188-             self ._socknum  =  NO_SOCKET_AVAIL 
215+             self ._socknum  =  SocketPool . NO_SOCKET_AVAIL 
189216        return  result 
190217
191218    def  close (self ):
192219        """Close the socket, after reading whatever remains""" 
193-         _the_interface .socket_close (self ._socknum )
220+         self . _interface .socket_close (self ._socknum )
194221
195222
196- class  timeout (TimeoutError ):
223+ class  timeout (TimeoutError ):   # pylint: disable=invalid-name 
197224    """TimeoutError class. An instance of this error will be raised by recv_into() if 
198225    the timeout has elapsed and we haven't received any data yet.""" 
199226
200227    def  __init__ (self , msg ):
201228        super ().__init__ (msg )
202- 
203- 
204- # pylint: enable=unused-argument, redefined-builtin, invalid-name 
0 commit comments