diff --git a/utils_v2/sms/nimbus/async_nimbus.py b/utils_v2/sms/nimbus/async_nimbus.py index 18fd70a..58d1a78 100644 --- a/utils_v2/sms/nimbus/async_nimbus.py +++ b/utils_v2/sms/nimbus/async_nimbus.py @@ -109,7 +109,7 @@ class AsyncNimbusSMS: self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) if not debug: self.__printer.disable() - # Create an HTTP client to work with: + # Accept/create an HTTP client to work with: if http_client: self.__http_client = http_client else: self.__http_client = httpx.AsyncClient( limits = httpx.Limits( diff --git a/utils_v2/sms/savvy_bulk_sms/async_savvy_bulk_sms.py b/utils_v2/sms/savvy_bulk_sms/async_savvy_bulk_sms.py index 058d9f2..c2ad78e 100644 --- a/utils_v2/sms/savvy_bulk_sms/async_savvy_bulk_sms.py +++ b/utils_v2/sms/savvy_bulk_sms/async_savvy_bulk_sms.py @@ -6,16 +6,15 @@ DATE: - Monday, 9th Sept., 2024 + Wednesday, 4th Dec., 2024 OBJECTIVE: - To be able to send SMSs from Nimbus's API and manage the templates and other things from one place. + To be able to send SMSs from Savvy Bulk SMS's API. REFERENCES: - 01. https://github.com/innovativevijay/SmsHitApiSample - 02. https://nimbusit.net/appforms/apimanual.php + N/A DOWNLOADS: @@ -23,7 +22,7 @@ WEB-PORTAL: - 01. http://nimbusit.net/ + N/A """ @@ -74,30 +73,23 @@ from icecream import IceCreamDebugger # ***************************************************************************************************************** -class AsyncNimbusSMS: - - MESSAGE_TYPE_REGULAR = 0 - MESSAGE_TYPE_UNICODE = 1 - - MESSAGE_TYPE_NOT_FLASH = 0 - MESSAGE_TYPE_FLASH = 1 +class AsyncSavvyBulkSMS: def __init__( self, - entity_id, - sender_id, - user_id, - api_key, + api_key: str, + partner_id: str, + short_code: str, + http_client: httpx.AsyncClient = None, debug = True, - debug_prefix = "Nimbus SMS | " + debug_prefix = "Savvy SMS | " ): """ - Sets up an instance of the SMS sender through Nimbus IT. - :param entity_id: The entity id as registered with DLT. - :param sender_id: The 6-char code like "HDFCBK", "NSESMS", "ZRODHA" that you see in your SMS inbox. - :param user_id: The 6-digit id that Nimbus has assigned to you. - :param api_key: The API key generated through Nimbus's portal. + Sets up an instance of an SMS sender that sends messages through Savvy Bulk SMS's API. + :param api_key: The API key received from Savvy Bulk SMS. + :param partner_id: Your id with Savvy Bulk SMS. + :param short_code: Your short code with Savvy Bulk SMS. :param debug: Whether, or not, you would like to show debugging messages (can be changed on the fly). :param debug_prefix: The prefix text to show with the debug string. """ @@ -106,122 +98,88 @@ class AsyncNimbusSMS: self.__printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) if not debug: self.__printer.disable() - # Create an HTTP client to work with: - limits = httpx.Limits( - max_connections = 5, - max_keepalive_connections = 5, - keepalive_expiry = 3600 + # Accept/create an HTTP client to work with: + if http_client: self.__http_client = http_client + else: self.__http_client = httpx.AsyncClient( + limits = httpx.Limits( + max_connections = 100, # ............ Maximum number of connections allowed in the pool. + max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive. + ), + timeout = httpx.Timeout( + pool = 120.0, # .... Time to wait for a free connection from the pool. + connect = 2.5, # ... Time to wait for establishing a connection to the server. + write = 10.0, # .... Time to wait for sending data. + read = 2.5 # ....... Time to wait for receiving data. + ) ) - self.__http_client = httpx.AsyncClient(limits = limits, timeout = 120) # Capture the input config: - self.__entity_id = entity_id - self.__sender_id = sender_id - self.__user_id = user_id, self.__api_key = api_key - - async def get_balance(self): - - """ - Checks the balance in the Nimbus wallet. - :return: The balance (float) if the request was successful, else None. - """ - - balance = None - - try: - - # Call the API: - response = await self.__http_client.get( - url = r"http://nimbusit.net/api/balance", - params = {"user": self.__user_id, "authkey": self.__api_key} - ) - - # The response of a successful API call looks like "BALANCE:599". We need just the number: - if response.status_code in [200]: balance = float(response.content.decode().split(":")[-1].strip()) - - except Exception as exception: - self.__printer(exception) - - return balance + self.__partner_id = partner_id + self.__short_code = short_code async def send_sms( self, - template_id, recipient_number, - message, - message_type = MESSAGE_TYPE_REGULAR, - flash = MESSAGE_TYPE_NOT_FLASH - ): + message + ) -> dict | None: """ - Sends one SMS through Nimbus IT's system. The text of the message must match the template that had been - submitted. A mismatch may cause the message to fail at best, and raise troubles in the real-world with - government bodies at worst. Be careful. - :param template_id: The id of the SMS template as registered on Nimbus's portal. - :param recipient_number: The phone number of the recipient. You can send an array of numbers, too, BUT IT IS - STRONGLY RECOMMENDED TO NOT DO THAT TO AVOID BEING BLOCKED BY DLT. - :param message: The message to send to the recipient. Should match the template that is being sent. - :param message_type: Choose between 'AsyncNimbusSMS.MESSAGE_TYPE_REGULAR' (default) and - 'AsyncNimbusSMS.MESSAGE_TYPE_UNICODE' based on the type of characters being sent. Both are class variables. - :param flash: to choose between a regular inbox SMS, or a flash SMS. - :return: The dict of all the details of the message that was sent including whether, or not, it was successfully - sent. Other details depend on the service provider (Nimbus IT in this case). + Send one SMS from Savvy Bulk SMS's API. + :param recipient_number: The mobile no. of the target recipient. + :param message: The message to send to the target recipient. + :return: """ # Construct the basic structure of the response of this method: summary = { "success": False, "info": None, - "sender": self.__sender_id, + "sender": { + "partnerId": self.__partner_id, + "shortCode": self.__short_code + }, "recipient": recipient_number, "message": message, "length": len(message), - "template_id": template_id, "raw": None, - "isFlash": True if flash else False } try: - # Pre-process the recipient's number: - if not isinstance(recipient_number, (list, set, tuple)): recipient_number = [recipient_number] - # Call the API: - response = await self.__http_client.get( - url = r"http://nimbusit.net/api/pushsms", + api_response = await self.__http_client.get( + url = r"https://sms.savvybulksms.com/api/services/sendsms/", params = { - "user": self.__user_id, - "authkey": self.__api_key, - "sender": self.__sender_id, - "mobile": ",".join([str(num) for num in recipient_number]), - "text": message, - "entityid": self.__entity_id, - "templateid": template_id, - "type": message_type, - "flash": flash + "apikey": self.__api_key, + "partnerID": self.__partner_id, + "message": message, + "shortcode": self.__short_code, + "mobile": recipient_number, } ) # For a successful API call: - if response.status_code == 200: - response_json = response.json() - summary["success"] = True if response_json.get("STATUS", "ERROR").lower() in ["ok"] else False - summary["info"] = response_json.get("RESPONSE", {}).get("INFO") + if api_response.status_code in [200]: + api_json = api_response.json() + first_desc = api_json.get("responses", [{}])[0].get("response-description", "N/A").lower().strip() + summary["success"] = True if first_desc == "success" else False summary["raw"] = { - "http_code": response.status_code, - "response": response_json, + "http_code": api_response.status_code, + "response": api_json, } # For any other code that indicates some form of failure: else: summary["raw"] = { - "http_code": response.status_code, - "response": response.content.decode() + "http_code": api_response.status_code, + "response": api_response.content.decode() } + # If something goes wrong along the way: except Exception as exception: self.__printer(exception) + # Done here: return summary @@ -238,22 +196,17 @@ if __name__ == "__main__": async def main(): - sender = AsyncNimbusSMS( - entity_id = "", - sender_id = "", - user_id = "", - api_key = "" + sender = AsyncSavvyBulkSMS( + api_key = "", + partner_id = "", + short_code = "" ) response = await sender.send_sms( - template_id = "", - recipient_number = "", - message = "" + recipient_number = "", + message = "" ) print("SMS API RESPONSE:", response) - my_balance = await sender.get_balance() - print("REMAINING BALANCE:", my_balance) - asyncio.run(main())