# frozen_string_literal: true

class PIDFile
	class NonExclusive < StandardError
		def initalize
			super("PID file exists and is locked by another process")
		end
	end

	class OpenPIDFile
		def initialize(handle, pid)
			@handle = handle
			@pid = pid
		end

		def refresh
			# This rewrites the file to move the modified time up
			# I _very likely_ don't have to rewrite the contents, because
			# hopefully no one else has dumped crap into my file since that
			# last time, and I could just write nothing...
			#
			# But since I need to do this at least once, it's not worse to do
			# it later too, it's so few cycles really, and it also heals the
			# file if something weird happened...
			@handle.rewind
			@handle.write("#{@pid}\n")
			@handle.flush
			@handle.truncate(@handle.pos)
		end
	end

	def initialize(filename, pid=Process.pid)
		@pid = pid
		@filename = filename
	end

	def lock
		File.open(@filename, File::RDWR | File::CREAT, 0o644) do |f|
			raise NonExclusive unless f.flock(File::LOCK_EX | File::LOCK_NB)

			begin
				open_pid = OpenPIDFile.new(f, @pid)

				# Start us off by writing to the file at least once
				open_pid.refresh

				# Then run the block, which can optionally refresh if they like
				yield open_pid
			ensure
				# Cleanup the pidfile on shutdown
				# But only if we obtained the lock
				File.delete(@filename)
			end
		end
	end
end
