Upload file to Node.js server using Socket.io-stream from iOS - ios

I'm writing a native iOS client to interact with a Node.js server using the Socket.IO-objc wrapper. I'm currently able to send individual events to the server just fine. However, the server is using Socket.IO-stream to handle upload file streams, and I need to make my iOS code interact with it somehow. My socket.io wrapper doesn't seem to have any relevant API for accomplishing this. The receiving server.js code is like:
io.sockets.on('connection', function (socket) {
console.log("connection occurring");
ss(socket).on('uploadFile', function (stream, data, callback) {
//...I can't get a 'stream' to this event for it to work with
});
socket.on('passwordLogin', function (data, callback) {
//...I can cause these kind of events just fine
});
//...other event declarations
}
I typically call events in this manner, and it works fine for 'socket.on' declared events:
[_socket sendEvent:#"passwordLogin"
withData:#{...login info...}
andAcknowledge:aCallbackBlock];
I figure I need to expand Socket.IO-objc, unless there is something I'm missing, with something like:
//TODO: Attempt to expand SocketIO to include streams.
- (void) sendEvent:(NSString *)eventName withStream:(NSStream*) stream withData:(id) data andAcknowledge:(SocketIOCallback) function
{
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:eventName forKey:#"name"];
// do not require arguments
if (data != nil) {
[dict setObject:[NSArray arrayWithObject:data] forKey:#"args"];
}
SocketIOPacket *packet = [[SocketIOPacket alloc] initWithType:#"event"];
packet.data = [SocketIOJSONSerialization JSONStringFromObject:dict error:nil];
packet.pId = [self addAcknowledge:function];
//Is this even a valid approach?
packet.stream = stream;//<--NEW BIT
if (function) {
packet.ack = #"data";
}
[self send:packet];
}
I'm pretty lost as to what exactly to do, having never really worked with server communications before. I've followed Apple documentation about the built-in NSStream and CFStream objects, but it doesn't seem to get me any closer to interacting with the server's event. Any help is appreciated, as I'm a bit at my wit's end.

Related

React Native CallKeep isCallActive using CXCallObserver

I am using https://github.com/react-native-webrtc/react-native-callkeep to implement a VOIP app in React Native.
It has a built in method for checking if a Call is going by passing the uuid to method isCallActive, it didn't work correctly for me so i have implement my own native module to check using the same code with promise:
RCT_EXPORT_METHOD(isCallActive:
(NSString *)uuidString
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
CXCallObserver *callObserver = [[CXCallObserver alloc] init];
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
BOOL _mybool = false;
for(CXCall *call in callObserver.calls){
NSLog(#"[RNCallKeep] isCallActive %# %d ?", call.UUID, [call.UUID isEqual:uuid]);
if([call.UUID isEqual:[[NSUUID alloc] initWithUUIDString:uuidString]] && !call.hasConnected){
_mybool = true;
resolve(#"true");
}
}
if(!_mybool){
reject(false, false, false);
}
}
The code is working and I am able to access it like this:
NativeModules?.CallManager?.isCallActive(uuid)
.then((value) => {
console.log('isCallActive then', value);
})
.catch((error) => {
console.log('isCallActive catch', error);
});
Now the problem here is that, if I receive a call, it displays CallKit UI then in my console i see it resolves the promise quickly even though i haven't accepted call yet and its ringing in the phone. I am unable to understand why is this happening.
EDIT:
How does hasConnected work? Even though i have accepted the call it always returns false? If I wait for my app to start completely behind callKit UI and then accept the call, it gives me true for hasConnected and I am assuming because the Twilio audio session is started at that point. But if i accept call early, i don't get true for hasConnected because audio session was not started. Is my understanding correct?

Gupshup - multiple messages delay feature not working

I've tried to implement a delay feature on my bot to display multiple messages one after the other. The delay feature is displaying in my Flow Bot Builder diagram, but when I test in the conversation tester, and proxy bot on Messenger, the delay doesn't actually happen - all the messages display at once.
I have added the delay code in the IDE to the default.scr file:
[main]
label_dych:Hi! I'm delay-bot and I'm here to help you with any questions you have.:continue
((delay 2000))
label_gthk:I'll never need to take any personal or financial information from you, so as we chat please don't tell me any!:continue
((delay 1000))
label_ylbn:{"name":"quickreply","type":"quick_reply","alias":"What can I help you with?","msgid":"117af569-5188-ff7e-9b48-8c553c2f36cb","content":{"type":"text","text":"What can I help you with?"},"options":[{"type":"text","title":"My Page","iconurl":"","id":"ac49ad32-c9bc-469f-2152-c7c842bad8ea","isDuplicate":false,"name":"user"},{"type":"text","title":"Team Spaces","iconurl":"","id":"8a2017ac-2fc3-0901-be8d-1fad5a2dba12","isDuplicate":false,"name":"user"},{"type":"text","title":"Offline Support","iconurl":"","id":"70861407-e706-17a3-207b-c43958fde83e","isDuplicate":false,"name":"user"},{"type":"text","title":"Something else","iconurl":"","id":"d3f7b6b4-e70a-098d-dde9-1da3e8cc08dc","isDuplicate":false,"name":"user"}]}
I've also added the options.apikey line of code to the index.js file as instructed to do here: https://www.gupshup.io/developer/docs/bot-platform/guide/sending-multiple-messages-botscript
function ScriptHandler(context, event){
var options = Object.assign({}, scr_config);
options.current_dir = __dirname;
//options.default_message = "Sorry Some Error Occurred.";
// You can add any start point by just mentioning the
<script_file_name>.<section_name>
// options.start_section = "default.main";
options.success = function(opm){
context.sendResponse(JSON.stringify(opm));
};
options.error = function(err) {
console.log(err.stack);
context.sendResponse(options.default_message);
};
botScriptExecutor.execute(options, event, context);
options.apikey = "1mbccef47ab24dacad3f99557cb35643";
}
Is there any obvious reason why the delay effect wouldn't be working in between messages? I've used the apikey that is displayed for my gupshup account when I click the logo in the top right.
You have placed the API key after the scripting tool execute function is called. Place the API Key anywhere before the botScriptExecutor.execute and the delay should work.
Also, the timing of the delay is in milliseconds.
Sample:
function ScriptHandler(context, event){
var options = Object.assign({}, scr_config);
options.current_dir = __dirname;
//options.default_message = "Sorry Some Error Occurred.";
options.apikey = "1mbccef47ab24dacad3f99557cb35643";
// You can add any start point by just mentioning the
<script_file_name>.<section_name>
// options.start_section = "default.main";
options.success = function(opm){
context.sendResponse(JSON.stringify(opm));
};
options.error = function(err) {
console.log(err.stack);
context.sendResponse(options.default_message);
};
botScriptExecutor.execute(options, event, context);
}

Send MMS using Twilio.TwimlResponse()

I'm using a node server with a webhook for handling receiving Twilio messages to one of my numbers. I use this number to forward communications between users, essentially anonymizing things for them (they communicate with our number so they don't have to give theirs to the other user).
In my handler, I currently basically do this:
var sendTo = /* other user's number */;
var sendFrom = /* sender number in received message */;
var body = /* body of message received */;
twimlResponse(body, {
to: sendTo,
from: sendFrom
});
response.send(twimlResponse.toString());
This works perfect for text messages. However, my debug log is showing errors for media messages with no body (also not forwarding the media in general, since I'm not currently telling it to).
So, I'm trying to update to send the media messages as well. This is not working well.
I found this documentation: https://www.twilio.com/docs/guides/how-to-receive-and-reply-in-node-js#respond-with-media-mms-message
However, it doesn't work. I get an error saying 'this' has no method 'To'.
I tried modifying my code a bit,
var sendTo = /* other user's number */;
var sendFrom = /* sender number in received message */;
var body = /* body of message received */;
var mediaUrl = /* mediaUrl0 of the received message */
if( body && mediaUrl ) {
twimlResponse(body, {
to: sendTo,
from: sendFrom,
mediaUrl: mediaUrl
});
}
else if( body ) {
twimlResponse(body, {
to: sendTo,
from: sendFrom
});
}
else if( mediaUrl ) {
twimlResponse(nil, {
to: sendTo,
from: sendFrom,
mediaUrl: mediaUrl
});
}
response.send(twimlResponse.toString());
I haven't yet verified that last one is correct for sending a message with no body, but my issue is that I can't figure out how to tell the twiml response to include the media. I've tried Media, media, MediaUrl, MediaUrl0, mediaUrl0, and mediaUrl. Each time I get a warning in my debugger saying it was an invalid noun. The Twiml Documentation says the nouns should be case sensitive and capitalized, though for some reason to and from are taken lower case. That part all works fine. I just can't figure out how to attach the media url.
Any tips are appreciated!
Edit -
Here is one attempt based on the linked documentation, which I thought wasn't working at all, but re-arranging the order of properties I set, I see I'm just not setting the to / from number appropriately. I know a twiml without those passed in automatically responds to the number that sent a message, from the number that received it. I need to specify both those values since I'm forwarding one user's message to another.
twimlResp.message(function() {
this.body(body);
this.media(media0);
this.to(sendTo);
this.from(sendFrom);
});
This snippet works fine for body and media, similar to the documentation, but crashes when setting to
Edit - I've tried changing this.to and this.from to this.To and this.From, but those don't work.
I've also tried this:
twimlResp.message(function() {
this.body(body);
this.media(media0);
});
twimlResp.to = sendTo;
twimlResp.from = sendFrom;
Which also does not work - .to and .from are ignored, causing the response to go back to the sending user from the number that received the original message.
I think you've gotten confused between the 2.0 and the 3.0 SDK. You can change between SDK versions by clicking in the top right of the example screen.
With your example provided, using the 3.0 SDK you can achieve this by:
var MessagingResponse = require('twilio').twiml.MessagingResponse;
var twiml = new MessagingResponse();
// Place your constraints here
var message = twiml.message({ to: sendTo, from: sendFrom });
if( body && mediaUrl ) {
message.body(body);
message.media(mediaUrl);
}
else if( body ) {
messsage.body(body);
}
else if( mediaUrl ) {
messsage.media(mediaUrl);
}
response.send(twiml.toString());
If you need a more in-depth detail on how I formulated this code, check out the MessagingResposne.js source. I'm assuming you have no restrictions on switching SDK versions, the reason I gave an example with the 3.0 SDK is because Twilio will be ending support for the 2.0 SDK as of 8/31/2017.
Howto with SDK 2.0
Since some users will need to migrate a large part of their codebase, here is how you can set a different to and from numbers with the SDK 2.0.
twimlResp.message(function() {
this.body(body);
this.media(media0);
}, {
to: sendTo,
from: sendFrom
});

Reading / writing file on local machine

I pretty much copied this code right out of the MDN File I/O page.. except I added an if statement to check if the file exists already and if it does, read it instead.
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
var file = Components.classes["#mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("Desk", Components.interfaces.nsIFile);
file.append("test.txt");
if (!file.exists()) {
this.user_id = Math.floor(Math.random()*10001) +'-'+ Math.floor(Math.random()*10001) +'-'+ Math.floor(Math.random()*10001) +'-'+ Math.floor(Math.random()*10001);
var ostream = FileUtils.openSafeFileOutputStream(file)
var converter = Components.classes["#mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var istream = converter.convertToInputStream(this.user_id);
// The last argument (the callback) is optional.
NetUtil.asyncCopy(istream, ostream, function(status) {
if (!Components.isSuccessCode(status)) {
alert('Error '+ status);
return;
}
alert('File created');
});
} else
{
NetUtil.asyncFetch(file, function(inputStream, status) {
if (!Components.isSuccessCode(status)) {
alert('error '+ status);
return;
}
// The file data is contained within inputStream.
// You can read it into a string with
this.user_id = NetUtil.readInputStreamToString(inputStream, inputStream.available());
});
alert('File exists already, do not create');
}
alert(this.user_id);
It creates the file just fine, I can open it and read it. If the file already exists however, it does not populate this.user_id.. just equals null. So my issue is specifically with reading the file.
File reading in your code works asynchronously - meaning that your code completes (including the alert() call which will show that this.user_id is null), then at some point the callback from NetUtil.asyncFetch() gets called with the data. Until that happens this.user_id won't be set of course. If you move alert(this.user_id) into the callback function it should show the correct value.
Note that it is highly recommended to keep file I/O operations asynchronous because they might take significant time depending on the current state of the file system. But you have to structure your code in such a way that it doesn't assume that file operations happen immediately.

Abnormally disconnected TCP sockets and write timeout

I will try to explain the problem in shortest possible words. I am using c++ builder 2010.
I am using TIdTCPServer and sending voice packets to a list of connected clients. Everything works ok untill any client is disconnected abnormally, For example power failure etc. I can reproduce similar disconnect by cutting the ethernet connection of a connected client.
So now we have a disconnected socket but as you know it is not yet detected at server side so server will continue to try to send data to that client too.
But when server try to write data to that disconnected client ...... Write() or WriteLn() HANGS there in trying to write, It is like it is wating for somekind of Write timeout. This hangs the hole packet distribution process as a result creating a lag in data transmission to all other clients. After few seconds "Socket Connection Closed" Exception is raised and data flow continues.
Here is the code
try
{
EnterCriticalSection(&SlotListenersCriticalSection);
for(int i=0;i<SlotListeners->Count;i++)
{
try
{
//Here the process will HANG for several seconds on a disconnected socket
((TIdContext*) SlotListeners->Objects[i])->Connection->IOHandler->WriteLn("Some DATA");
}catch(Exception &e)
{
SlotListeners->Delete(i);
}
}
}__finally
{
LeaveCriticalSection(&SlotListenersCriticalSection);
}
Ok i already have a keep alive mechanism which disconnect the socket after n seconds of inactivity. But as you can imagine, still this mechnism cant sync exactly with this braodcasting loop because this braodcasting loop is running almost all the time.
So is there any Write timeouts i can specify may be through iohandler or something ? I have seen many many threads about "Detecting disconnected tcp socket" but my problem is little different, i need to avoid that hangup for few seconds during the write attempt.
So is there any solution ?
Or should i consider using some different mechanism for such data broadcasting for example the broadcasting loop put the data packet in some kind of FIFO buffer and client threads continuously check for available data and pick and deliver it to themselves ? This way if one thread hangs it will not stop/delay the over all distribution thread.
Any ideas please ? Thanks for your time and help.
Regards
Jams
There are no write timeouts implemented in Indy. For that, you will have to use the TIdSocketHandle.SetSockOpt() method to set the socket-level timeouts directly.
The FIFO buffer is a better option (and a better design in general). For example:
void __fastcall TForm1::IdTCPServer1Connect(TIdContext *AContext)
{
...
AContext->Data = new TIdThreadSafeStringList;
...
}
void __fastcall TForm1::IdTCPServer1Disconnect(TIdContext *AContext)
{
...
delete AContext->Data;
AContext->Data = NULL;
...
}
void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
{
TIdThreadSafeStringList *Queue = (TIdThreadSafeStringList*) AContext->Data;
TStringList *Outbound = NULL;
TStringList *List = Queue->Lock();
try
{
if( List->Count > 0 )
{
Outbound = new TStringList;
Outbound->Assign(List);
List->Clear();
}
}
__finally
{
Queue->Unlock();
}
if( Outbound )
{
try
{
AContext->Connection->IOHandler->Write(Outbound);
}
__finally
{
delete Outbound;
}
}
...
}
...
try
{
EnterCriticalSection(&SlotListenersCriticalSection);
int i = 0;
while( i < SlotListeners->Count )
{
try
{
TIdContext *Ctx = (TIdContext*) SlotListeners->Objects[i];
TIdThreadSafeStringList *Queue = (TIdThreadSafeStringList*) Ctx->Data;
Queue->Add("Some DATA");
++i;
}
catch(const Exception &e)
{
SlotListeners->Delete(i);
}
}
}
__finally
{
LeaveCriticalSection(&SlotListenersCriticalSection);
}

Resources