VB.net download file via ftpwebrequest -> directory topic? - vb.net

I need to download a file from a FTP Server.
The path and the file name is
ftp://10.17.20.60/ata0b/OpconData/StationData/Station.dat
When i want to see all Files in the StationData directory i use
Dim request As Net.FtpWebRequest = Net.FtpWebRequest.Create("ftp://10.17.20.60/%2F/ata0b/OpconData/StationData/")
request.Method = Net.WebRequestMethods.Ftp.ListDirectory
request.Credentials = New Net.NetworkCredential(form1.txtFTPUser.Text, form1.txtFTPPasswort.Text)
Dim response As Net.FtpWebResponse = request.GetResponse()
With this i get the content of the directory. Of course i see the Station.dat file. I was able to make it work since i use the %2F parameter to change the directory to ata0b.
So far so good!
Now i want to download the Station.dat file. But i always get an error (550) File unavailable (e.g., file not found, no access) at the last line in code below.
My code looks like this:
'Create Request To Download File'
Dim wrDownload As FtpWebRequest = WebRequest.Create("ftp://10.17.20.60/%2F/ata0b/OpconData/StationData/Station.dat")
'Specify That You Want To Download A File'
wrDownload.Method = WebRequestMethods.Ftp.DownloadFile
'Specify Username & Password'
wrDownload.Credentials = New NetworkCredential("opconadmin", "OpconAdmin")
'Response Object'
Dim rDownloadResponse As FtpWebResponse = wrDownload.GetResponse()
What's my failure? In my point of view the file must be at the given path. I really hope somebody can give me a hint.
BR
Steffen

The error means what it says.But let me explain why this might occur :
1 • The file might be unavailable/not present on the server
2 • You might face 'Security Problem on file' issue .
There could be other causes like server timeout or other..
However,you need to find out what the error message really is.TO do this, you can use a TRY-CATCH statement. E.g.
Try
'YOur code here
Catch e as WebException
Msgbox(e.Message) 'you can use e.tostring for more details
After you find out what exactly is the problem,then you'ld be able to solve it.Take a look at these :
http://www.dreamincode.net/forums/topic/76361-file-upload-to-server/
https://nickstips.wordpress.com/2010/10/25/c-ftp-upload-error-the-remote-server-returned-an-error-550-file-unavailable-e-g-file-not-found-no-access/
https://forums.asp.net/t/1777881.aspx
But one thing i'ld like to suggest is to check whether you have any Permission/Security issues or not.And after you get the exact error message,it may(or may not) turn out to be that you don't have enough disk space.However,try my solution and leave a reply for further assistance.
UPDATE
Try replacing the FTP link with this : ftp://10.17.20.60//ata0b/OpconData/StationData/Station.da

Related

Using a local image with EmbedBuilder

According to the Discord.NET documentation page for the EmbedBuilder class, the syntax (converted to VB) to add a local image to an EmbedBuilder object should look something like this:
Dim fileName = "image.png"
Dim embed = New EmbedBuilder() With {
.ImageUrl = $"attachment://{fileName}"
}.Build()
I'm trying to use something like this to add a dynamically created image to the EmbedBuilder, but I can't seem to get it to work properly. Here's basically what I've got:
Dim TweetBuilder As New Discord.EmbedBuilder
Dim DynamicImagePath As String = CreateDynamicImage()
Dim AttachURI As String = $"attachment:///" & DynamicImagePath.Replace("\", "/").Replace(" ", "%20")
With Builder
.Description = "SAMPLE DESCRIPTION"
.ImageUrl = AttachURI
End With
MyClient.GetGuild(ServerID).GetTextChannel(PostChannelID).SendMessageAsync("THIS IS A TEST", False, Builder.Build)
My CreateDynamicImage method returns the full path to the locally created image (e.g., C:\Folder\Another Folder\image.png). I've done a fair amount of "fighting"/testing with this to get past the Url must be a well-formed URI exception I was initially getting because of the [SPACE] in the path.
MyClient is a Discord.WebSocket.SocketClient object set elsewhere.
The SendMessageAsync method does send the Embed to Discord on the correct channel, but without the embedded image.
If I instead send the image using the SendFileAsync method (like so):
MyClient.GetGuild(ServerID).GetTextChannel(PostChannelID).SendFileAsync(DynamicImagePath, "THIS IS A TEST", False, Builder.Build)
the image is sent, but as a part of the message, rather than included as a part of the Embed (this is expected behavior - I only bring it up b/c it was a part of my testing to ensure that there wasn't a problem with actually sending the image to Discord).
I've tried using the file:/// scheme instead of the attachment:/// scheme, but that results in the entire post never making it to Discord at all.
Additionally, I've tried setting the ImageUrl property to a Web resource (e.g., https://www.somesite.com/someimage.png) and the Embed looks exactly as expected with the image and everything when it successfully posts to Discord.
So, I'm just wondering at this point if I'm just missing something, or if I'm just doing it completely wrong?
I cross-posted this to issue #1609 in the Discord.Net GitHub project to get a better idea of what options are available for this and received a good explanation of the issue:
The Embed (and EmbedImage) objects don't do anything with files. They simply pass the URI as configured straight into Discord. Discord then expects a URI in the form attachment://filename.ext if you want to refer to an attached image.
What you need to do is use SendFileAsync with the embed. You have two options here:
Use SendFileAsync with the Stream stream, string filename overload. I think this makes it clear what you need to do: you provide a file stream (via File.OpenRead or similar) and a filename. The provided filename does not have to match any file on disk. > So, for example:
var embed = new EmbedBuilder()
.WithImageUrl("attachment://myimage.png")
.Build();
await channel.SendFileAsync(stream, "myimage.png", embed: embed);
Alternatively, you can use SendFileAsync with the string filePath overload. Internally, this gets a stream of the file at the path, and sets filename (as sent to Discord) to the last part of the path. So it's equivalent to:
using var stream = File.OpenRead(filePath);
var filename = Path.GetFileName(filePath);
await channel.SendFileAsync(stream, filename);
From here, you can see that if you want to use the string filePath overload, you need to set embed image URI to something like $"attachment://{Path.GetFileName(filePath)}", because the attachment filename must match the one sent to Discord.
I almost had it with my code above, but I misunderstood the intention and usage of the method and property. I guess I thought the .ImageUrl property somehow "automatically" initiated a Stream in the background. Additionally, I missed one very important piece:
As it's an async method, you must await (or whatever the VB.NET equivalent is) on SendFileAsync.
So, after making my calling method into an async method, my code now looks like this:
Private Async Sub TestMessageToDiscord()
Dim Builder As New Discord.EmbedBuilder
Dim AttachmentPath As String = CreateDynamicImage() '<-- Returns the full, local path to the created file
With Builder
.Description = "SAMPLE DESCRIPTION"
.ImageUrl = $"attachment://{IO.Path.GetFileName(AttachmentPath)}"
End With
Using AttachmentStream As IO.Stream = IO.File.OpenRead(AttachmentPath)
Await MyClient.GetGuild(ServerID).GetTextChannel(PostChannelID).SendFileAsync(AttachmentStream, IO.Path.GetFileName(AttachmentPath), "THIS IS A TEST", False, Builder.Build)
End Using
End Sub
Now, everything works exactly as expected and I didn't have to resort to uploading the image to a hosting site and using the new URL (I actually had that working before I got the response on GitHub. I'm sure that code won't go to waste).
EDIT
Okay, so I still ended up going back to my separately hosted image option for one reason: I have a separate event method that modifies the original Embed object during which I want to remove the image and replace the text. However, when that event fired, while the text was replaced, the image was "moved" to the body of the Discord message. While I may have been able to figure out how to get rid of the image entirely, I decided to "drop back and punt" since I had already worked out the hosted image solution.
I've tried everyting I could, but I got stuck at the same point at where you are now.
My guesses are that Discord doesn't like the embedded images from https://cdn.discordapp.com/attachments, and only accepts the new files from https://media.discordapp.net. I might be wrong though, this is the way it worked for me.
I believe it's only a visual glitch, as I found if you send a link for an image from cdn.discordapp.com/attchments in your regular Discord client, it bugs out and shows an empty embed for some reason.
That would make sense since the default link used in an embedded image actually starts with https://cdn.discordapp.com/attachments/...
You could solve this issue by using https://media.discordapp.net, but it seems like Discord.net is configured to use the old domain.

Using Leigh version of S3Wrapper.cfc Can't get past Init

I am new to S3 and need to use it for image storage. I found a half dozen versions of an s2wrapper for cf but it appears that the only one set of for v4 is one modified by Leigh
https://gist.github.com/Leigh-/26993ed79c956c9309a9dfe40f1fce29
Dropped in the com directory and created a "test" page that contains the following code:
s3 = createObject('component','com.S3Wrapper').init(application.s3.AccessKeyId,application.s3.SecretAccessKey);
but got the following error :
So I changed the line 37 from
variables.Sv4Util = createObject('component', 'Sv4').init(arguments.S3AccessKey, arguments.S3SecretAccessKey);
to
variables.Sv4Util = createObject('component', 'Sv4Util').init(arguments.S3AccessKey, arguments.S3SecretAccessKey);
Now I am getting:
I feel like going through Leigh code and start changing things is a bad idea since I have lurked here for year an know Leigh's code is solid.
Does any know if there are any examples on how to use this anywhere? If not what I am doing wrong. If it makes a difference I am using Lucee 5 and not Adobe's CF engine.
UPDATE :
I followed Leigh's directions and the error is now gone. I am addedsome more code to my test page which now looks like this :
<cfscript>
s3 = createObject('component','com.S3v4').init(application.s3.AccessKeyId,application.s3.SecretAccessKey);
bucket = "imgbkt.domain.com";
obj = "fake.ping";
region = "s3-us-west-1"
test = s3.getObject(bucket,obj,region);
writeDump(test);
test2 = s3.getObjectLink(bucket,obj,region);
writeDump(test2);
writeDump(s3);
</cfscript>
Regardless of what I put in for bucket, obj or region I get :
JIC I did go to AWS and get new keys:
Leigh if you are still around or anyone how has used one of the s3Wrappers any suggestions or guidance?
UPDATE #2:
Even after Alex's help I am not able to get this to work. The Link I receive from getObjectLink is not valid and getObject never does download an object. I thought I would try the putObject method
test3 = s3.putObject(bucketName=bucket,regionName=region,keyName="favicon.ico");
writeDump(test3);
to see if there is any additional information, I received this :
I did find this article https://shlomoswidler.com/2009/08/amazon-s3-gotcha-using-virtual-host.html but it is pretty old and since S3 specifically suggests using dots in bucketnames I don't that it is relevant any longer. There is obviously something I am doing wrong but I have spent hours trying to resolve this and I can't seem to figure out what it might be.
I will give you a rundown of what the code does:
getObjectLink returns a HTTP URL for the file fake.ping that is found looking in the bucket imgbkt.domain.com of region s3-us-west-1. This link is temporary and expires after 60 seconds by default.
getObject invokes getObjectLink and immediately requests the URL using HTTP GET. The response is then saved to the directory of the S3v4.cfc with the filename fake.ping by default. Finally the function returns the full path of the downloaded file: E:\wwwDevRoot\taa\fake.ping
To save the file in a different location, you would invoke:
downloadPath = 'E:\';
test = s3.getObject(bucket,obj,region,downloadPath);
writeDump(test);
The HTTP request is synchronous, meaning the file will be downloaded completely when the functions returns the filepath.
If you want to access the actual content of the file, you can do this:
test = s3.getObject(bucket,obj,region);
contentAsString = fileRead(test); // returns the file content as string
// or
contentAsBinary = fileReadBinary(test); // returns the content as binary (byte array)
writeDump(contentAsString);
writeDump(contentAsBinary);
(You might want to stream the content if the file is large since fileRead/fileReadBinary reads the whole file into buffer. Use fileOpen to stream the content.
Does that help you?

How to download a Byte Array?

So, using vb.net, I retrieve from my server the byte data for a file that the user wishes to download. I always know what the filename and extension is, but what I don't know is how to start downloading the byte data and in the proper file format. How do I got about doing this?
EDIT: Just to clarify, I already retrieve the data in byte format in code, I just need to download it as the proper file type which is also known. I'm keeping the URL to the file hidden at all times so it's never exposed.
If you want to download the file directly to the hard drive, the easiest solution is to use WebClient.DownloadFile. The MSDN page contains a nice example.
If you want to put the file into a byte array instead of a file on disk, use WebClient.DownloadData instead:
Dim myWebClient As New WebClient()
Dim myByteArray = myWebClient.DownloadData("http://...")
Again, a larger example can be found on the MSDN page.
If you want your program to stay responsive while downloading, check out the asynchronous versions of those methods.
EDIT: I'm still having a hard time understanding your situation, but it you already have a byte array and just want to write it to the disk, you can use File.WriteAllBytes:
File.WriteAllBytes("C:\my\path\myfile.bin", myByteArray)
Okay, I figured it out. Using BinaryWrite with the other Response functions like AddHeader and ContentType I got it to work. GetMimeType is a function I made. Code below:
Response.Clear()
Response.AddHeader("Content-Disposition", "attachment; filename=" + FileName)
Response.ContentType = GetMimeType(FileName)
Response.BinaryWrite(data)
Response.End()
Response.Flush()
Thanks to those who tried to help!

an error 3013 thrown when writing a file Adobe AIR

I'm trying to write/create a JSON file from a AIR app, I'm trying not so show a 'Save as' dialogue box.
Here's the code I'm using:
var fileDetails:Object = CreativeMakerJSX.getFileDetails();
var fileName:String = String(fileDetails.data.filename);
var path:String = String(fileDetails.data.path);
var f:File = File.userDirectory.resolvePath( path );
var stream:FileStream = new FileStream();
stream.open(f, FileMode.WRITE );
stream.writeUTFBytes( jsonToExport );
stream.close();
The problem I'm having is that I get a 'Error 3013. File or directory in use'. The directory/path is gathered from a Creative Suite Extension I'm building, this path is the same as the FLA being developed in CS that the Extension is being used with.
So I'm not sure if the problem is that there are already files in the directory I'm writing the JSON file to?
Do I need to add a timer in order to close the stream after a slight delay, giving some time to writing the file?
Can you set up some trace() commands? I would need to know what the values of the String variables are, and the f.url.
Can you read from the file that you are trying to write to, or does nothing work?
Where is CreativeMakerJSX.getFileDetails() coming from? Is it giving you data about a file that is in use?
And from Googling around, this seems like it may be a bug. Try setting up a listener for when you are finished, if you have had the file open previously.
I re-wrote how the file was written, no longer running into this issue.

"The directory name is invalid" error on Process.Start?

I am writing a launcher program, and when I go to start the process I get the "The directory name is invalid" error. Here is the code that is launching the process:
Const DEBUG_ROOT = _
"Z:\Kiosk_JC\KioskSignIn.root\KioskSignIn\KioskSignIn\KioskSignIn\bin\Debug"
Dim oKiosk As New System.Diagnostics.Process
oKiosk.StartInfo.UserName = oEnc.Decrypt(Username)
oKiosk.StartInfo.Password = oEnc.DecryptSecure(Password)
oKiosk.StartInfo.Domain = oEnc.Decrypt(Domain)
''// The AddBS function appends a '\' to the passed string if it is not present
oKiosk.StartInfo.WorkingDirectory = AddBS(DEBUG_ROOT)
oKiosk.StartInfo.FileName = "KioskSignIn.exe"
oKiosk.StartInfo.UseShellExecute = False
Dim proc As Process = Nothing
proc = System.Diagnostics.Process.Start(oKiosk.StartInfo)
I saw on another question here that I needed to set the WorkingDirectory (before I started searching I was getting the error). Even though I have this property set, I am still getting the error. Any thoughts?
More info
I should also note that my Z:\ is a on my network. I have a function that resolves a path to UNC. When I ran this function on DEBUG_ROOT, I get the same error.
I tried moving the application to c:\kiosk. Same result. I am logged in as the user I am impersonating, so I have access to all shares and files.
Here is the link, for some reason the URL formating wants to consume all the text after the link is designated:
Referred Post
Mapped drives are per-user. You are likely starting the process with a different user.
Sounds like the process can't see the Z: drive or doesn't have security access. What user context does the app run under? Perhaps the Z: drive is not available in that context.
I got the same error as you do. most likely the user you use to run the process does not have access to specified resource (exe file)
try to move your exe to some other location and/or give your user access rights to the file.