Reopening closed file: Lua - windows

I have a file called backup.lua, which the program should write to every so often in order to backup its status, in case of a failure.
The problem is that the program writes the backup.lua file completely fine first-time round, but any other times it refuses to write to the file.
I tried removing the file while the program was still open but Windows told me that the file was in use by 'CrysisWarsDedicatedServer.exe', which is the program. I have told the host Lua function to close the backup.lua file, so why isn't it letting me modify the file at will after it has been closed?
I can't find anything on the internet (Google actually tried to correct my search) and the secondary programmer on the project doesn't know either.
So I'm wondering if any of you folks know what we are doing wrong here?
Host function code:
function ServerBackup(todo)
local write, read;
if todo=="write" then
write = true;
else
read = true;
end
if (write) then
local source = io.open(Root().."Mods/Infinity/System/Read/backup.lua", "w");
System.Log(TeamInstantAction:GetTeamScore(2).." for 2, and for 1: "..TeamInstantAction:GetTeamScore(1))
System.LogAlways("[System] Backing up serverdata to file 'backup.lua'");
source:write("--[[ The server is dependent on this file; editing it will lead to serious problems.If there is a problem with this file, please re-write it by accessing the backup system ingame.--]]");
source:write("Backup = {};Backup.Time = '"..os.date("%H:%M").."';Backup.Date = '"..os.date("%d/%m/%Y").."';");
source:write(XFormat("TeamInstantAction:SetTeamScore(2, %d);TeamInstantAction:SetTeamScore(1, %d);TeamInstantAction:UpdateScores();",TeamInstantAction:GetTeamScore(2), TeamInstantAction:GetTeamScore(1) ));
source:close();
for i,player in pairs(g_gameRules.game:GetPlayers() or {}) do
if (IsModerator(player)) then
CMPlayer(player, "[!backup] Completed server backup.");
end
end
end
--local source = io.open(Root().."Mods/Infinity/System/Read/backup.lua", "r"); Can the file be open here and by the Lua scriptloader too?
if (read) then
System.LogAlways("[System] Restoring serverdata from file 'backup.lua'");
--source:close();
Backup = {};
Script.LoadScript(Root().."Mods/Infinity/System/Read/backup.lua");
if not Backup or #Backup < 1 then
System.LogAlways("[System] Error restoring serverdata from file 'backup.lua'");
end
end
end
Thanks all :).
Edit:
Although the file is now written to the disk fine, the system fails to read the dumped file.

So, now the problem is that the "LoadScript" function isn't doing what you expect:
Because I'm psychic, i have divined that you're writing a Crysis plugin, and are attempting to use it's LoadScript API call.
(Please don't assume everyone here would guess this, or be bothered to look for it. It's vital information that must form part of your questions)
The script you're writing attempts to set Backup - but your script, as written - does not separate lines with newline characters. As the first line is a comment, the entire script will be ignored.
Basicallty the script you've written looks like this, which is all treated as a comment.
--[[ comment ]]--Backup="Hello!"
You need to write a "\n" after the comment (and, I'd recommend in other places too) to make it like this. In fact, you don't really need block comments at all.
-- comment
Backup="Hello!"

Related

Failing to read a named pipe being written to

I have a stream of data that I’m writing to a named pipe:
named_pipe = '/tmp/pipe' # Location of named pipe
File.mkfifo(named_pipe) # Create named pipe
File.open(named_pipe, 'w+') # Necessary to not get a broken pipe when ⌃C from another process later on
system('youtube-dl', '--newline', 'https://www.youtube.com/watch?v=aqz-KE-bpKQ', out: named_pipe) # Output download progress, one line at a time
Trouble is, while I can cat /tmp/pipe and get the information, I’m unable to read the file from another Ruby process. I’ve tried File.readlines, File.read with seeking, File.open then reading, and other stuff I no longer remember. Some of those hang, others error out.
How can I get the same result as with cat, in pure Ruby?
Note I don’t have to use system to send to the pipe (Open3 would be acceptable), but any solution requiring external dependencies is a no-go.
it looks like File.readlines/IO.readlines, File.read/IO.read need to load the whole temp file first so you don't see any be printed out.
try File#each/IO.foreach which process a file line by line and it does not require the whole file be loaded into memory
File.foreach("/tmp/pipe") { |line| p line }
# or
File.open('/tmp/pipe','r').each { |line| p line }

"Too many open files" error when using named pipes

I'm running 2 scripts and after a while, I'm getting Too many open files # error/blob.c/ImageToFile/1832.
Simplified version of the first scripts. It's supposed to read images written to image_pipe, process them, and write them to ocr_pipe for the OCR to read.
# creates 2 named pipes
File.mkfifo(image_pipe) rescue nil
File.mkfifo(ocr_pipe) rescue nil
while image = Image.read(image_pipe)
# do some stuff with `image`...
end
The second script is using ffmpeg to extract frames from a video, writing them to image_pipe
# image_pipe is the same as the script above.
(14..movie.duration).step(0.5) do
`/usr/local/bin/ffmpeg [some options...] #{image_pipe}`
end
I think the issue is RMagick opening too many file descriptors when reading the images in the loop of the first script, but I'm not sure how to stop that from happening. The Magick::Image class doesn't have a close method or anything, afaik.
I did not find the root cause of the issue, but ulferts helped me find a workaround that's acceptable for me.
Instead of letting RMagick open the file itself, we should handle it on our side, and then use .from_blob to create the Magick::Image instance.
while f = File.read(image_pipe)
image = Image.from_blob(f)
# ... do stuff with image.
end

Ruby: Add line in file [duplicate]

This question already has answers here:
What are the Ruby File.open modes and options?
(2 answers)
Closed 6 years ago.
I have a file in which one I want to store some datas.
Using IRB, I can add different lines in the file. However, using a Ruby script writen in a file, I have issues.
I can write a line, it is stored as it should be, but when I re launch the script and re use the method, it overwrites what was in the file instead of adding content at the next line.
def create_new_account
puts "Set the account's name"
#account_name = gets
puts "New account's name: #{#account_name}
open("accounts.txt","w+") do |account_file|
account_file.write "ac;#{#account_name}\n"
end
end
I had a look to the different parameters of the method open, but seems like it's not there.
Moreover, I tried puts instead of write, but there is no difference, always the same problem.
Could someone help me understand what is wrong with the code?
Thanks
Try opening the file in append mode like so
open('accounts.txt', 'a+')
otherwise the file is opened so as to overwrite the existing data.
"a" - Write-only, each write call appends data at end of file.
Creates a new file for writing if file does not exist.

Sinatra File deleter

I am using sinatra,ruby and MongoDB to export a CSV file from the MongoDB. I am able to create the CSV file and export it.
I delete the file after exporting it.
But it gets deleted only after I exit sinatra.
Can anybody explain why is this?
Suppose a file abc****.csv is created.
I am deleting this file using
file_path = '/home/Test_app';
file = Tempfile.new([##uname,'.csv'],file_path);
file_name = file.path();
puts file_name # gives /home/Test_app/xyz****.csv
send_file(file_name, :disposition => 'attachment', :filename =>File.basename(file_name));
File.delete(file_name);
File.unlink(file_name);
But it gets deleted only after I exit sinatra server. Can anyone explain please?
Your never call file.close, meaning the file will be kept open and therefore not deleted until your application exits.
Try following the suggestion given in the Tempfile documentation:
file = Tempfile.new('foo')
begin
...do something with file...
ensure
file.close
file.unlink # deletes the temp file
end
This will make sure the file is properly closed and deleted even in the event of exceptions being raised in the code between begin and ensure.
Perhaps this is a large file; since the HTTP connection does not close until the streaming is complete, the code after send_file is not getting executed. That might be a valid reason. Have you checked if the entire file is being downloaded to the client? If that is not the case, try it out with a smaller file. I'm assuming you've implemented (but haven't written it here) the code for the data getting written into the file_name from MongoDB.

How can I delete a file in Sinatra after it has been sent via send_file?

I have a simple sinatra application that needs to generate a file (via an external process), send that file to the browser, and finally, delete the file from the filesystem. Something along these lines:
class MyApp < Sinatra::Base
get '/generate-file' do
# calls out to an external process,
# and returns the path to the generated file
file_path = generate_the_file()
# send the file to the browser
send_file(file_path)
# remove the generated file, so we don't
# completely fill up the filesystem.
File.delete(file_path)
# File.delete is never called.
end
end
It seems, however, that the send_file call completes the request, and any code after it does not get run.
Is there some way to ensure that the generated file is cleaned up after it has been successfully sent to the browser? Or will I need to resort to a cron job running a cleanup script on some interval?
Unfortunately there is no any callbacks when you use send_file. Common solution here is to use cron tasks to clean temp files
It could be a solution to temporarily store the contents of the file in a variable, like:
contents = file.read
After this, delete the file:
File.delete(file_path)
Finally, return the contents:
contents
This has the same effect as your send_file().
send_file is streaming the file, it is not a synchronous call, so you may not be able to catch the end of it to the cleanup the file. I suggest using it for static files or really big files. For the big files, you'll need a cron job or some other solution to cleanup later. You can't do it in the same method because send_file will not terminate while the execution is still in the get method. If you don't really care about the streaming part, you may use the synchronous option.
begin
file_path = generate_the_file()
result File.read(file_path)
#...
result # This is the return
ensure
File.delete(file_path) # This will be called..
end
Of course, if you're not doing anything fancy with the file, you may stick with Jochem's answer which eliminate begin-ensure-end altogether.

Resources