I have use White Raccoon and Black Raccoon both to upload zip file on FTP server.
In White Raccoon I was not able to upload zip file, I always get serverTimeout error. So I tried to upload normal xml file with white raccoon, File is uploaded without any data(0 byte size). Here is the code
-(void)upload:(NSData*)data{
//the upload request needs the input data to be NSData
NSData * ourImageData = data;
//we create the upload request
//we don't autorelease the object so that it will be around when the callback gets called
//this is not a good practice, in real life development you should use a retain property to store a reference to the request
WRRequestUpload * uploadImage = [[WRRequestUpload alloc] init];
uploadImage.delegate = self;
//for anonymous login just leave the username and password nil
uploadImage.hostname = #"hostname";
uploadImage.username = #"username";
uploadImage.password = #"password";
//we set our data
uploadImage.sentData = ourImageData;
//the path needs to be absolute to the FTP root folder.
//full URL would be ftp://xxx.xxx.xxx.xxx/space.jpg
uploadImage.path = #"huge_test.zip";
//we start the request
[uploadImage start];
}
I am using this https://github.com/valentinradu/WhiteRaccoon
-As WhiteRaccoon is not working for me I have tried BlackRaccoon but it is not helping me to even upload a normal xml file, it just give me "Stream timed out with no response from server" error.
here is the code
- (IBAction) uploadFile :(NSData *)datas{
self.uploadData = [NSData dataWithData:datas];
//Here I am just Checking that DATA come from another method is proper or not. I got All thedata which I have passed from method
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/test12121.xml"];
// Write the data to file
[datas writeToFile:path atomically:YES];
self.uploadFile = [[BRRequestUpload alloc] initWithDelegate: self];
//----- for anonymous login just leave the username and password nil
self.uploadFile.path = #"/test.xml";
self.uploadFile.hostname = #"hostname";
self.uploadFile.username = #"username";
self.uploadFile.password = #"password";
//we start the request
[self.uploadFile start];
}
- (long) requestDataSendSize: (BRRequestUpload *) request{
//----- user returns the total size of data to send. Used ONLY for percentComplete
return [self.uploadData length];
}
- (NSData *) requestDataToSend: (BRRequestUpload *) request{
//----- returns data object or nil when complete
//----- basically, first time we return the pointer to the NSData.
//----- and BR will upload the data.
//----- Second time we return nil which means no more data to send
NSData *temp = self.uploadData; // this is a shallow copy of the pointer
self.uploadData = nil; // next time around, return nil...
return temp;
}
-(void) requestFailed:(BRRequest *) request{
if (request == uploadFile)
{
NSLog(#"%#", request.error.message);
uploadFile = nil;
}
NSLog(#"%#", request.error.message);
}
-(BOOL) shouldOverwriteFileWithRequest: (BRRequest *) request
{
//----- set this as appropriate if you want the file to be overwritten
if (request == uploadFile)
{
//----- if uploading a file, we set it to YES
return YES;
}
//----- anything else (directories, etc) we set to NO
return NO;
}
- (void) percentCompleted: (BRRequest *) request
{
NSLog(#"%f completed...", request.percentCompleted);
}
-(void) requestCompleted: (BRRequest *) request
{
//----- handle Create Directory
if (request == uploadFile)
{
NSLog(#"%# completed!", request);
uploadFile = nil;
}
}
I am using https://github.com/lloydsargent/BlackRaccoon.
I have even changed the timeout limit upto 60 but its not working for me. Please anyone can help me?Anyone knows another way to upload zip file to FTP server, then please let me know.
Thanks in advance.
Related
I am trying to write an application that will pull down the contents of a Google Docs file as HTML to allow me to edit it inside the app. After editing the html file I then want to upload the changes back to Google Drive and update the contents of the original Google Docs file. I have been able to pull down the Google Docs file but am not able to upload my changes back to the server.
Can you please help to understand why this error is happening ? And possibly advise me on a fix for the issue ?
I am getting the following NSError:
Error Domain=com.google.GTLJSONRPCErrorDomain Code=500 "The operation couldn’t be completed. (Internal Error)" UserInfo=0x157a8610 {error=Internal Error, GTLStructuredError=GTLErrorObject 0x16846f60: {message:"Internal Error" code:500 data:[1]}, NSLocalizedFailureReason=(Internal Error)}
2014-06-17 12:11:35.188 DrEdit[548:60b] Error UserInfo: {
GTLStructuredError = "GTLErrorObject 0x16846f60: {message:\"Internal Error\" code:500 data:[1]}";
NSLocalizedFailureReason = "(Internal Error)";
error = "Internal Error";
}
Please code being executed when uploading below:
- (void)saveFile {
GTLUploadParameters *uploadParameters = nil;
// Only update the file content if different.
if (![self.originalContent isEqualToString:self.textView.text]) {
// NSData *fileContent =
// [self.textView.text dataUsingEncoding:NSUTF8StringEncoding];
NSAttributedString *s = self.textView.attributedText;
NSDictionary *documentAttributes = [NSDictionary dictionaryWithObjectsAndKeys:NSHTMLTextDocumentType, NSDocumentTypeDocumentAttribute, nil];
NSData *htmlData = [s dataFromRange:NSMakeRange(0, s.length) documentAttributes:documentAttributes error:NULL];
// NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
// NSData *fileContent = [self.textView.attributedText convertToData];
uploadParameters = [GTLUploadParameters uploadParametersWithData:htmlData MIMEType:#"text/html"];
// [GTLUploadParameters uploadParametersWithData:fileContent MIMEType:#"text/plain"];
// [GTLUploadParameters uploadParametersWithData:fileContent MIMEType:#"application/vnd.google-apps.document"];
}
self.driveFile.title = self.updatedTitle;
GTLQueryDrive *query = nil;
if (self.driveFile.identifier == nil || self.driveFile.identifier.length == 0) {
// This is a new file, instantiate an insert query.
query = [GTLQueryDrive queryForFilesInsertWithObject:self.driveFile
uploadParameters:uploadParameters];
} else {
// This file already exists, instantiate an update query.
query = [GTLQueryDrive queryForFilesUpdateWithObject:self.driveFile
fileId:self.driveFile.identifier
uploadParameters:uploadParameters];
}
UIAlertView *alert = [DrEditUtilities showLoadingMessageWithTitle:#"Saving file"
delegate:self];
[self.driveService executeQuery:query completionHandler:^(GTLServiceTicket *ticket,
GTLDriveFile *updatedFile,
NSError *error) {
[alert dismissWithClickedButtonIndex:0 animated:YES];
if (error == nil) {
self.driveFile = updatedFile;
self.originalContent = [self.textView.text copy];
self.updatedTitle = [updatedFile.title copy];
[self toggleSaveButton];
[self.delegate didUpdateFileWithIndex:self.fileIndex
driveFile:self.driveFile];
[self doneEditing:nil];
} else {
NSLog(#"An error occurred: %#", error);
NSLog(#"Error UserInfo: %#", error.userInfo);
[DrEditUtilities showErrorMessageWithTitle:#"Unable to save file"
message:[error description]
delegate:self];
}
}];
}
Thanks,
Michael
Its not possible to write html to a gdoc programmatically.
Currently its only possible to manually paste html but not with an api unfortunately (and strangely)
I was able to solve this problem by changing the property convert to YES on the GTLQueryDrive class. The documentation states that it will attempt to convert the file being uploaded into a native Google Docs format.
Hope this helps. Please see the method I am describing from the SDK below:
// Method: drive.files.update
// Updates file metadata and/or content
// Required:
// fileId: The ID of the file to update.
// Optional:
**// convert: Whether to convert this file to the corresponding Google Docs
// format. (Default false)**
// newRevision: Whether a blob upload should create a new revision. If false,
// the blob data in the current head revision will be replaced. (Default
// true)
// ocr: Whether to attempt OCR on .jpg, .png, or .gif uploads. (Default false)
// ocrLanguage: If ocr is true, hints at the language to use. Valid values are
// ISO 639-1 codes.
// pinned: Whether to pin the new revision. (Default false)
// setModifiedDate: Whether to set the modified date with the supplied
// modified date. (Default false)
// sourceLanguage: The language of the original file to be translated.
// targetLanguage: Target language to translate the file to. If no
// sourceLanguage is provided, the API will attempt to detect the language.
// timedTextLanguage: The language of the timed text.
// timedTextTrackName: The timed text track name.
// updateViewedDate: Whether to update the view date after successfully
// updating the file. (Default true)
// Upload Parameters:
// Maximum size: 10GB
// Accepted MIME type(s): */*
// Authorization scope(s):
// kGTLAuthScopeDrive
// kGTLAuthScopeDriveFile
// Fetches a GTLDriveFile.
+ (id)queryForFilesUpdateWithObject:(GTLDriveFile *)object
fileId:(NSString *)fileId
uploadParameters:(GTLUploadParameters *)uploadParametersOrNil;
Thanks,
Michael
I have an app that's using background downloads with the new NSURLSession APIs. When a download cancels or fails in such a way that NSURLSessionDownloadTaskResumeData is provided, I store the data blob so that it can be resumed later. A very small amount of the time I am noticing a crash in the wild:
Fatal Exception: NSInvalidArgumentException
Invalid resume data for background download. Background downloads must use http or https and must download to an accessible file.
The error occurs here, where resumeData is the NSData blob and session is an instance of NSURLSession:
if (resumeData) {
downloadTask = [session downloadTaskWithResumeData:resumeData];
...
The data is provided by the Apple APIs, is serialized, and is then deserialized at a later point in time. It may be corrupted, but it is never nil (as the if statement checks).
How can I check ahead of time that the resumeData is invalid so that I do not let the app crash?
This is the workaround suggested by Apple:
- (BOOL)__isValidResumeData:(NSData *)data{
if (!data || [data length] < 1) return NO;
NSError *error;
NSDictionary *resumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
if (!resumeDictionary || error) return NO;
NSString *localFilePath = [resumeDictionary objectForKey:#"NSURLSessionResumeInfoLocalPath"];
if ([localFilePath length] < 1) return NO;
return [[NSFileManager defaultManager] fileExistsAtPath:localFilePath];
}
Edit (iOS 7.1 is not NDA'd anymore): I got this from a Twitter exchange with an Apple engineer, he suggested what to do, and I wrote the above implementation
I have not found an answer to how to tell if the data is valid ahead of time.
However, I am presently working around the issue like so:
NSData *resumeData = ...;
NSURLRequest *originalURLRequest = ...;
NSURLSessionDownloadTask *downloadTask = nil;
#try {
downloadTask = [session downloadTaskWithResumeData:resumeData];
}
#catch (NSException *exception) {
if ([NSInvalidArgumentException isEqualToString:exception.name]) {
downloadTask = [session downloadTaskWithRequest:originalURLRequest];
} else {
#throw exception; // only swallow NSInvalidArgumentException for resumeData
}
}
actually, the resume data is a plist file.
it contains the follows key:
NSURLSessionDownloadURL
NSURLSessionResumeBytesReceived
NSURLSessionResumeCurrentRequest
NSURLSessionResumeEntityTag
NSURLSessionResumeInfoTempFileName
NSURLSessionResumeInfoVersion
NSURLSessionResumeOriginalRequest
NSURLSessionResumeServerDownloadDate
so the steps u need to do are:
check the data is a valid plist;
check the plist have keys as above;
check the temp file is exist;
I have upload file on FTP using this classes.
I am using this method for uploading
- upload
{
//the upload request needs the input data to be NSData
//so we first convert the image to NSData
UIImage * ourImage = [UIImage imageNamed:#"space.jpg"];
NSData * ourImageData = UIImageJPEGRepresentation(ourImage, 100);
//we create the upload request
//we don't autorelease the object so that it will be around when the callback gets called
//this is not a good practice, in real life development you should use a retain property to store a reference to the request
WRRequestUpload * uploadImage = [[WRRequestUpload alloc] init];
uploadImage.delegate = self;
//for anonymous login just leave the username and password nil
uploadImage.hostname = #"xxx.xxx.xxx.xxx";
uploadImage.username = #"myuser";
uploadImage.password = #"mypass";
//we set our data
uploadImage.sentData = ourImageData;
//the path needs to be absolute to the FTP root folder.
//full URL would be ftp://xxx.xxx.xxx.xxx/space.jpg
uploadImage.path = #"/space.jpg";
//we start the request
[uploadImage start];
}
-(void) requestCompleted:(WRRequest *) request{
//called if 'request' is completed successfully
NSLog(#"%# completed!", request);
}
-(void) requestFailed:(WRRequest *) request{
//called after 'request' ends in error
//we can print the error message
NSLog(#"%#", request.error.message);
}
-(BOOL) shouldOverwriteFileWithRequest:(WRRequest *)request {
//if the file (ftp://xxx.xxx.xxx.xxx/space.jpg) is already on the FTP server,the delegate is asked if the file should be overwritten
//'request' is the request that intended to create the file
return YES;
}
But I am not successfully upload file on FTP.
Also I am not getting any error.
So, How to upload file on FTP?
Alright, this involves a lot of network coding from this part of a multiplayer tutorial.
Basically, I'm trying to implement a multiplayer game using GameKit as per the tutorial linked above. I put in all of the necessary network coding and more or less understand it, however I've hit a snag somewhere along the line of method calls. Basically, the setup that I have is that one device acts as the host and the rest act as the clients. I have two separate UIViewcontrollers for the host and clients respectively where the connection is established.
Now the thing is, the connection gets established, but it's only the host that recognizes the connection, not the client. The problem is here:
- (void)sendPacketToAllClients:(Packet *)packet
{
[_players enumerateKeysAndObjectsUsingBlock:^(id key, Player *obj, BOOL *stop)
{
obj.receivedResponse = [_session.peerID isEqualToString:obj.peerID];
}];
GKSendDataMode dataMode = GKSendDataReliable;
NSData *data = [packet data];
NSError *error;
if (![_session sendDataToAllPeers:data withDataMode:dataMode error:&error])
{
NSLog(#"Error sending data to clients: %#", error);
}
}
This is implemented in GameMultiplayer, where the actual game will be implemented. What this method is supposed to be doing is sending data packets to each of the clients saying that the host received the connection request and is able to connect with them. After [_session sendDataToAllPeers:data withDataMode:dataMode error:&error] is called (the method in the if statement), this method is supposed to be triggered:
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peerID inSession:(GKSession *)session context:(void *)context
{
#ifdef DEBUG
NSLog(#"Game: receive data from peer: %#, data: %#, length: %d", peerID, data, [data length]);
#endif
Packet *packet = [Packet packetWithData:data];
if (packet == nil)
{
NSLog(#"Invalid packet: %#", data);
return;
}
Player *player = [self playerWithPeerID:peerID];
if (player != nil)
{
player.receivedResponse = YES; // this is the new bit
}
if (self.isServer)
[self serverReceivedPacket:packet fromPlayer:player];
else
[self clientReceivedPacket:packet];
}
This method is in the next part of the tutorial I linked above (which is here) and is supposed to receive the packets that the host sends to all clients and implement the next methods in this networking chain. However, the method never gets called. No debug breakpoints are triggered and I get nothing in the console.
I understand if I need to provide more source material, but there is a lot of network coding already implemented, so I want to keep it down to what people need to see. Also, [_session setDataReceiveHandler:self withContext:nil] and _session.delegate = self are written in another method that is called in GameMultiplayer, so that's not the problem. Does anyone know what I need to fix?
EDIT: As requested, here's where GKSession is initialized:
#property (nonatomic, strong, readonly) GKSession *session; //This is done in the header file
#synthesize session = _session; //This is done in the main file
- (void)startAcceptingConnectionsForSessionID:(NSString *)sessionID
{
if (_serverState == ServerStateIdle)
{
_serverState = ServerStateAcceptingConnections;
_connectedClients = [NSMutableArray arrayWithCapacity:self.maxClients];
_session = [[GKSession alloc] initWithSessionID:sessionID displayName:nil sessionMode:GKSessionModeServer];
_session.delegate = self;
_session.available = YES;
}
}
The session is initialized in MatchmakingServer, which is used in the host view controller. The session is then passed on to the main view controller of the app, which then initializes GameMultiplayer and sends the GKSession to it. Here's where the host view controller sends it to the main view controller:
- (IBAction)startAction:(id)sender
{
if (_matchmakingServer != nil && [_matchmakingServer connectedClientCount] > 0)
{
NSString *name = [self.nameTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([name length] == 0)
name = _matchmakingServer.session.displayName;
[_matchmakingServer stopAcceptingConnections];
[self.delegate hostViewController:self startGameWithSession:_matchmakingServer.session playerName:name clients:_matchmakingServer.connectedClients];
}
}
and then the main view controller handles that method call here:
- (void)hostViewController:(MatchmakerHost *)controller startGameWithSession:(GKSession *)session playerName:(NSString *)name clients:(NSArray *)clients
{
[self dismissViewControllerAnimated:NO completion:^
{
[self startGameWithBlock:^(GameMultiplayer *aGame)
{
[aGame startServerGameWithSession:session playerName:name clients:clients];
}];
}];
}
and finally, this is where that method call is implemented in GameMultiplayer:
- (void)startServerGameWithSession:(GKSession *)session playerName:(NSString *)name clients:(NSArray *)clients
{
_clients = clients;
const char* className = class_getName([[_clients objectAtIndex:0] class]);
NSLog(#"yourObject is a: %s", className);
self.isServer = YES;
_session = session;
_session.available = NO;
_session.delegate = self;
[_session setDataReceiveHandler:self withContext:nil];
_state = GameStateWaitingForSignIn;
[self.delegate gameWaitingForClientsReady:self];
// Create the Player object for the server.
Player *player = [[Player alloc] init];
player.name = name;
player.peerID = _session.peerID;
player.position = PlayerPositionBottom;
[_players setObject:player forKey:player.peerID];
// Add a Player object for each client.
int index = 0;
for (NSString *peerID in clients)
{
Player *player = [[Player alloc] init];
player.peerID = peerID;
[_players setObject:player forKey:player.peerID];
if (index == 0)
player.position = ([clients count] == 1) ? PlayerPositionTop : PlayerPositionLeft;
else if (index == 1)
player.position = PlayerPositionTop;
else
player.position = PlayerPositionRight;
index++;
}
NSLog(#"Players:");
Packet *packet = [Packet packetWithType:PacketTypeSignInRequest];
[self sendPacketToAllClients:packet];
// for (int i = 0; i < [_players count]; i++) {
// NSLog([NSString stringWithFormat:#"%#", [clients objectAtIndex:i]]);
// }
}
I think you are calling send to fast. When server realize about connection it will send confirmation to client to really establish connection - so client knows about it succeed.
If you are sending packets before that happens - it will be lost.
Just do this:
[self performSelector:#selector(sendPacketToAllClients) withObject:nil afterDelay:1.0];
instead of:
[self sendPacketToAllClients];
I had the same problem that connection is established in different moment with small delay on client. The best is to send first packet from client that he is ready to receive packets from server - and than proceed normally from there.
Also try debugging:
- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state
On both devices (server and client).
I have also had my troubles with GKSession. I was interested to learn (on this site) today that GKSession is being deprecated in favor of using the Multipeer Connectivity Framework. With luck, Wenderlich et al. will do a tutorial using the new technology. :)
The system has some similarities to GKSession, so is not too hard to wrap your head around.
Apple's doc link.
I am working with Blackraccoon FTP client to do FTP operations,working with ARC.but i am getting leaks in instruments.
but there were no leaks in sample application here is my code
BRRequestCreateDirectory *createEventDir = [BRRequestCreateDirectory initWithDelegate:nil];
//NSString *EventCode = [[NSUserDefaults standardUserDefaults] stringForKey:kEventCodeKey];
createEventDir.path = #"/12341234";
createEventDir.hostname = #"media.example.com/httpdocs/events/";
createEventDir.username = #"badboy";
createEventDir.password = #"hai!";
createEventDir.tag = 103;
[createEventDir start];
createEventDir = nil;
sample code from FTP clent Blackraccoon FTP client
leaks showing in instruments like,but i am using ARC
can any one help me to solve this prob..
I ported and heavily modified BlackRaccoon. It is designed to use delegates. In other words, delegates are required.
BRRequestCreateDirectory *createEventDir = [BRRequestCreateDirectory initWithDelegate:nil];
//NSString *EventCode = [[NSUserDefaults standardUserDefaults] stringForKey:kEventCodeKey];
createEventDir.path = #"/12341234";
createEventDir.hostname = #"media.example.com/httpdocs/events/";
createEventDir.username = #"badboy";
createEventDir.password = #"hai!";
createEventDir.tag = 103;
[createEventDir start];
createEventDir = nil;
Is incorrect. It starts a lot of things going and then deletes the object - the action is undefined.
Instead you need something as indicated in the code that I provided (that doesn't leak).
First, the class that uses the ftp needs to have BRRequestDelegate to indicate the delegate protocol.
- (IBAction) createDirectory:(id)sender
{
//----- createEventDir must be a variable in your class...
createEventDir = [BRRequestCreateDirectory initWithDelegate: self];
createEventDir.path = #"/12341234;
createEventDir.hostname = #"media.example.com/httpdocs/events/";
createEventDir.username = #"badboy";
createEventDir.password = #"hai!";
[createEventDir start];
//----- createEventDir MUST NOT BE DELETED OR SET TO NIL HERE
}
Then you have to have the two delegates (at a minimum):
-(void) requestCompleted: (BRRequest *) request
{
//----- handle Create Directory
if (request == createEventDir)
{
NSLog(#"%# completed!", request);
//----- everything is done, NOW you can set it to nil
createEventDir = nil;
}
}
-(void) requestFailed: (BRRequest *) request
{
if (request == createEventDir)
{
NSLog(#"%#", request.error.message);
//----- everything is done, NOW you can set it to nil
createEventDir = nil;
}
}
If you go back and look at my test code you'll see how things work. If you are still having issues, post in the issues on http://github.com/lloydsargent/BlackRaccoon
Hopefully this will get you past your problem.