twilio: detecting that a dial target is busy? - python-3.x

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.

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

Return from before_request() in flask

I'm new to flask and currently converting an existing WSGI application to run through flask as long term it'll make life easier.
All requests are POST to specific routes however the current application inspects the post data prior to executing the route to see if the request needs to be run at all or not (i.e. if an identifier supplied in the post data already exists in our database or not).
If it does exist a 200 code and json is returned "early" and no other action is taken; if not the application continues to route as normal.
I think I can replicate the activity at the right point by calling before_request() but I'm not sure if returning a flask Response object from before_request() would terminate the request adequately at that point? Or if there's a better way of doing this?
NB: I must return this as a 200 - other examples I've seen result in a redirect or 4xx error handling (as a close parallel to this activity is authentication) so ultimately I'm doing this at the end of before_request():
if check_request_in_progress(post_data) is True:
response = jsonify({'request_status': 'already_running'})
response.status_code = 200
return response
else:
add_to_requests_in_progress(post_data)
Should this work (return and prevent further routing)?
If not how can I prevent further routing after calling before_request()?
Is there a better way?
Based on what they have said in the documents, it should do what you want it to do.
The function will be called without any arguments. If the function returns a non-None value, it’s handled as if it was the return value from the view and further request handling is stopped.
(source)
#app.route("/<name>")
def index(name):
return f"hello {name}"
#app.before_request
def thing():
if "john" in request.path:
return "before ran"
with the above code, if there is a "john" in the url_path, we will see the before ran in the output, not the actual intended view. you will see hello X for other string.
so yes, using before_request and returning something, anything other than None will stop flask from serving your actual view. you can redirect the user or send them a proper response.

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.

Error: Can't set headers after they are sent only on page refresh

I have this problem only when I try refresh the page and I can not solve it, I tried everything but still happens the same. It began to happen when I add socket.io at the project. The project run in several servers which are connected one each other throught sockets.
TEST CASES: When I render the page, at the first time everything goes well but, if I refresh the same page, I get this error:
ERROR: "Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)"
ATTENTION: when get in IF() and send "return res.end('The Activation Code is INVALID!');" it DOESN'T HAPPEND! I refresh it and refresh it and everything goes well. My problem is in the RENDER.
MY CODE BELOW:
activationUser = function(req,res,next){
var data = {
activationCode : req.params.activationCode,
now : new Date().valueOf(),
ip : req.connection.remoteAddress,
fId : frontalId
}
socketCore.emit('activationUser', data);
socketCore.on(frontalId + 'activationUserResp', function(data){
if(data.msg == "CHECKED!"){
next();
}else{
return res.end(data.msg);
}
});
}
router.get('/activationUser/:activationCode',activationUser,function(req,res){
var data = {
activationCode : req.params.activationCode,
fId : frontalId
}
socketCore.emit('step2', data);
socketCore.on(frontalId + 'step2Resp', function(data){
if(data.msg == 'err'){
return res.end('The Activation Code is INVALID!');
}else{
return res.render('registro2', {title: 'title | '+ data.name + ' ' + data.lastname, user:data});
}
});
});
Thank you!
The particular error you are getting happens when you try to send anything on the res object after the complete response has already been sent. This often occurs because of errors in asynchronous logic. In your particular case, it apepars to be because you are assigning a new event handler with socketCore.on() every single time the router is hit. Those event handlers will accumulate and after the first time the route is hit, they will execute multiple times triggering the sending of multiple responses on the same response object, thus trigger that error.
The main ways to fix your particular problem are:
Use .once() instead of .on() so the event handler automatically removes itself after being triggered.
Manually remove the .on() event handler after you get the response.
Move the event handler outside of the route so it's only ever installed once.
In your particular case, since socketCore is a shared object available to all requests, it appears that you also have a race condition. If multiple users trigger the '/activationUser/:activationCode' route in the same general time frame, then you will register two event handlers with socketCore.on() (one for each route that is hit) and you will do two socketCore.emit('step2', data);. But, you have no way of associating which response belongs with which request and the two responses could easily get mixed up - going to the wrong request.
This highlights how socket.io connections are not request/response. They are message/answer, but unless you manually code a correspondence between a specific message request and a specific answer, there is no way to correlate which goes with which. So, without assigning some particular responseID that lets you know which response belongs to which message, you can't use a socket.io connection like this in a multi-user environment. It will just cause race conditions. It's actually simpler to use an HTTP request/response for this type of data fetching because each response goes only with the request that made it in the HTTP architecture.
You can change your architecture for making the socketCore request, but you will have to manually assign an ID to each request and make sure the server is sending back that ID with the response that belongs to that request. Then, you can write a few lines of code on the receiving side of things that will make sure the right response gets fed to the code with the matching request.

Call multiple numbers sequentially using twilio outgoing call

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.

Resources