Call multiple numbers sequentially using twilio outgoing call - python-3.x

So I'm using the twilio api to do outgoing calls from a list
NUMS = ['xxx-xxx-xxxx', 'jjj-jjj-jjjj']
for num in NUMS:
c = make_call(num, "Hi-how-are-you!!!")
and the make_call function contains the twillio code
def make_call(to_number, mesg):
global FROM
call_status = ['COMPLETED', 'FAILED', 'BUSY', 'NO_ANSWER']
# put your own credentials here
ACCOUNT_SID = "--------------------"
AUTH_TOKEN = "--------------------"
client = TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN)
call = client.calls.create(
to=to_number,
from_=FROM,
url=URL+"/voice/reply/"+mesg,
method="POST",
status_callback=URL+"/voice/status",
status_callback_method="POST",
timeout=10
)
return call
No idea what i'm doing wrong, but it queues BOTH and then CALLS THEM BOTH AT THE SAME TIME. If I pick up on call, the other one ends.
I want to call sequentially, and putting a time.sleep() doesn't work either.
Help is appreciated.

Twilio evangelist here.
Each call to client.calls.create is simple an HTTP request to Twilios REST API that tells it to start an outbound phone call. Calls are made asynchronously, so if you wanted to you could call that function 10 times to simultaneously start ten separate phone calls.
If you want to make calls in a serial fashion, rather than using a loop to start the calls I would suggest starting the first call and then using the StatusCallback route handler to have Twilio tell you when that first call has completed (and why) and then in that handler, start the next call.
Each time the active call completes, Twilio will request that StatusCallback route allowing you to start the next call in your sequence.
Hope that helps.

Related

What is the "normal" way to feedback game actions to central server (MMO)

Basically I need to feed "events" back to the central server using gdscript. i.e. User picked up this, user dropped this, etc.... Im assuming the mobile phone holds an "event queue" that needs to be shipped off to the server. HTTPS is fine for my purposes. (A technique that would apply to any application that needs to share activity events between applications)
How does one implement a queue/thread in gdscript to handle this activity?
Im inclined to drop events into an sqlite database, then have some kind of "thread" that picks up and retries sending the events. Is this something that is normally coded from scratch? How do you do threads? If there are not threads, how do you handle when a http request fails, how do you ensure that something retries the message.
At this point in time, there does not appear to be a standardized/built in event queue style framework.
A simple class/node with an array acting as a queue works well with a simple function to queue messages. This demonstrates submitting a http request, where a callback is made to a function called http_result when the request is complete or fails.
http_request = HTTPRequest.new()
add_child(http_request)
http_request.connect("request_completed", self, "http_result")
http result handling:
func signin_status(result, response_code, headers, body):
if response_code == 200:
var data = parse_json(body.get_string_from_utf8())
print("json: ", data)
print("headers: ", headers)
else:
print("http response: ", response_code, " CODE: ", result, " data:", body.get_string_from_utf8())
remove_child(http_request)
http_request = null

How to get status of placed call on Amazon Connect?

I'm writing an app which sends an automated call via Amazon Connect. The app needs to retry to another destination number should the first one fail to pick up. The app is being written in Python3 and is to be hosted in Lambda.
This is the resource is used
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/connect.html#Connect.Client.get_contact_attributes
https://docs.aws.amazon.com/connect/latest/APIReference/API_GetContactAttributes.html
The problem is that "send call" is kicked off asynchronously and so it is not immediately clear if the call has succeeded or not. To check the call I invoke "get_contact_attributes" to identify status or any attributes which could point to the status of the placed call.
response=client.start_outbound_voice_contact(
ContactFlowId='XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
DestinationPhoneNumber=event["DestinationPhoneNumber"],
SourcePhoneNumber=event["OriginationPhoneNumber"],
InstanceId="YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY",
Attributes={
"message":f'{event["message"]}'
}
)
contactid=response["ContactId"]
attr = client.get_contact_attributes(
InstanceId='YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY',
InitialContactId=contactid
)
I expected it to return "connected_at" or something like it I could use to identify the outcome of the call, however, it only returns "custom" attributes set by myself.
this is the solution i found:
1) in the Contact Flow i added "Set Attribute" node where i set "status=1" right after the start. Basically, if a call enters Contact Flow (i.e. call picked up) it is marked as successfully completed
Set Contact Sttributes
2) inside my Python code (lambda) i check for the status to show up and if it doesn't in so many seconds i cancel the call and try another number:
attr = client.get_contact_attributes(
InstanceId=instanceid,
InitialContactId=contactid
)
stop_call=client.stop_contact(
ContactId=contactid,
InstanceId=instanceid
)

twilio: detecting that a dial target is busy?

I'm using the twilio REST interface via flask under python3.
I am using the dial method to route incoming calls to another number (stored in the target variable), as follows:
resp = VoiceResponse()
resp.dial(
target,
action=url_for('callstatus'),
method='GET',
timeout=20
)
return Response(str(resp), 200, mimetype='application/xml')
This works with no problem if the target number starts ringing. However, if the target number is busy, the dial method does not detect this, and it just lets the caller hear the busy signal until the timeout occurs.
I'd like to somehow immediately detect that the target is busy and then route the call to voicemail in that case.
I know how to do the routing to voicemail, but I don't know how to make this happen automatically upon encountering a busy signal.
Is there any way to do this via the twilio REST API?
UPDATE: I tried the following, and it didn't work ...
resp = VoiceResponse()
dial = Dial(
action=url_for('callstatus'),
method='GET',
timeout=20
)
dial.number(
target,
status_callback=url_for('callstatus'),
status_callback_event='initiated ringing answered completed',
status_callback_method='GET'
)
resp.append(dial)
return Response(str(resp), 200, mimetype='application/xml')
When I do it this way, I get a busy signal, and it goes on forever. The time out in the original Dial object gets ignored.
NOTE: I based the above code on this following example within the twilio documentation for Number ...
response = VoiceResponse()
dial = Dial()
dial.number(
'+14158675310',
status_callback_event='initiated ringing answered completed',
status_callback='https://myapp.com/calls/events',
status_callback_method='POST'
)
response.append(dial)
print(response)
ANOTHER NOTE: the status_callback is ignored within the number object. If I comment out action in the dial object, my status callback never gets called, even if I hang up the call. And if I put action back into the dial object and comment out all the status_callback attributes in the number object, the action callback does get called when I hang up the call. This means that action is being recognized, but status_callback is being ignored.
... and I get exactly the same behavior, whether I set the method to POST or GET.
Twilio developer evangelist here.
You could try using <Number> within the <Dial> you have there and including a statusCallback attribute. When the dialled number is busy, Twilio will send a webhook to say that the call is completed and the reason was that it was busy. You could then use the REST API to modify the call and send it to some new TwiML to collect voicemail.
Alternatively, you could put the incoming call into a queue with <Enqueue> and use the REST API to dial out to the phone number. If that call then comes back as busy you can redirect the incoming call out of the queue and into voicemail. If the outbound call is a success then you respond with <Dial> and <Queue> to connect the callers.

receive SMS using python and python-smpp

I'm a newbie in SMPP but I need to simulate traffic over the SMPP protocol. I have found the tutorial how to send SMS using smpp lib from Python How to Send SMS using SMPP Protocol
I'm trying to write a receiver,but I am unable to get it to work. Please help.
My code is:
import smpplib
class ClientCl():
client=None
def receive_SMS(self):
client=smpplib.client.Client('localhost',1000)
try:
client.connect()
client.bind_receiver("sysID","login","password")
sms=client.get_message()
print(sms)
except :
print("boom! nothing works")
pass
sms_getter=ClientCl.receive_SMS
From what I can understand the smpplib you are using is the one available at github. Looking at your code and the client code, I can't find the function client.get_message. Perhaps you have an older version of the library? Or I have the wrong library. In any case, it is likely that the get_message function does not block and wait for the message to arrive.
Looking at the client code it seems that you have two options:
Poll the library until you get a valid message
Setup the library to listen to the SMPP port and call a function once a message arrives.
If you look at the README.md file it shows how you can setup the library to implement the second option (which is the better option).
...
client = smpplib.client.Client('example.com', SOMEPORTNUMBER)
# Print when obtain message_id
client.set_message_sent_handler(
lambda pdu: sys.stdout.write('sent {} {}\n'.format(pdu.sequence, pdu.message_id)))
client.set_message_received_handler(
lambda pdu: sys.stdout.write('delivered {}\n'.format(pdu.receipted_message_id)))
client.connect()
client.bind_transceiver(system_id='login', password='secret')
for part in parts:
pdu = client.send_message(
source_addr_ton=smpplib.consts.SMPP_TON_INTL,
#source_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure it is a byte string, not unicode:
source_addr='SENDERPHONENUM',
dest_addr_ton=smpplib.consts.SMPP_TON_INTL,
#dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN,
# Make sure thease two params are byte strings, not unicode:
destination_addr='PHONENUMBER',
short_message=part,
data_coding=encoding_flag,
esm_class=msg_type_flag,
registered_delivery=True,
)
print(pdu.sequence)
client.listen()
...
When receiving a message or delivery receipt the function defined in client.set_message_received_handler() will be called. In the example, it is a lambda function. There is also an example on how to set up for listening in a thread.
If you prefer the simpler polling option you should use the poll function. For the simplest implementation all you need to do is:
while True:
client.Poll()
As before, the function set in client.set_message_received_handler() will be called once a message arrives.

How can aws api gateway listen to 2 lambda functions?

My design is that api will trigger first lambda function, this function then send sns and return, sns triggers second lambda function. Now I want that api get the response from the second lambda function.
Here is the flow:
The api get the request from the user and then trigger the first lambda function, the first lambda function creates a sns and return. Now the api is at the lambda function stage and still waiting for the response from the second lambda. sns triggers the second lambda function; the second lambda function return some result and pass it to the api. api gets the response and send it back to user.
I know there is a way using sdk to get the second lambda function and set event type to make it async. But here I want to use sns, is it possible?
Need some help/advices. Thanks in advance!
You need something to share the lambda_func_2's return with lambda_func_1, the api gateway request context only return when you call callback on func1, you can not save or send the request contex to another lb_func.
My solution for this case is use Dynamodb (or every database) to share the f2's result.
F1 send data to sns, the date include a key like transactionID (uuid or timestamp). Then "wait" until F1 receive the result in table (ex: tbl_f2_result) and execute callback function with the result. Maybe query with transactionID until you receive data or only try 10 times (with time out 2s for one time, in worst case you will wait 20 seconds)
F2 has been trigged by SNS, do somthing with data include the transactionID then insert the result (success or not, error message ...) to result table(tbl_f2_result) with transactionID => result, callback finish F2.
transactionID is index key of table :D
You have to increase F1's timeout - Default is 6 seconds.
Of course you can. Lambda provides you a way to implement almost any arbitrary functionality that you want, whether it's inserting a record into your DynamoDB, reading an object from your S3 bucket, calculating the tax amount for the selected item on an e-commerce site, or simply calling an API.
Notice that here you don't need any event to call your api from the lambda, as simply you call the api directly.
As you are using Node, you can simply use an http request; something like this:
var options = {
host: YOUR_API_URL,
port: 80,
path: 'REST_API_END_POINT',
method: 'YOUR_HTTP_METHOD' //POST/GET/...
};
http.request(options, function(res) {
//Whatever you want to do with the reply...
}).end();
Below is what is possible for your problem, but requires polling.
API GTW
integration to --> Lambda1
Lambda1
create unique sha create a folder inside the bucket say s3://response-bucket/
Triggers SNS through sdk with payload having sha
Poll from the key s3://response-bucket/ ( with timeout set )
if result is placed then response is sent back from Lambda1 --> ApiGTW
if timeout then error is returned.
If success then trigger SNS for cleanup of response data in bucket with payload being SHA which will be cleaned up by another lambda.
SNS
Now the payload with the SHA is there in SNS
Lambda2
SNS triggers lambda2
pull out the unique sha from the payload
lambda result is placed in same s3://response-bucket/
exit from lambda2

Resources