CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/json_hash_file.rb
Views: 11766
1
# -*- coding => binary -*-
2
3
require 'json'
4
require 'fileutils'
5
6
#
7
# This class provides a thread-friendly hash file store in JSON format
8
#
9
module Rex
10
class JSONHashFile
11
12
attr_accessor :path
13
14
def initialize(path)
15
self.path = path
16
@lock = Mutex.new
17
@hash = {}
18
@last = 0
19
end
20
21
def [](k)
22
synced_update
23
@hash[k]
24
end
25
26
def []=(k,v)
27
synced_update do
28
@hash[k] = v
29
end
30
end
31
32
def keys
33
synced_update
34
@hash.keys
35
end
36
37
def delete(k)
38
synced_update do
39
@hash.delete(k)
40
end
41
end
42
43
def clear
44
synced_update do
45
@hash.clear
46
end
47
end
48
49
private
50
51
# Save the file, but prevent thread & process contention
52
def synced_update(&block)
53
@lock.synchronize do
54
::FileUtils.mkdir_p(::File.dirname(path))
55
::File.open(path, ::File::RDWR|::File::CREAT) do |fd|
56
fd.flock(::File::LOCK_EX)
57
58
# Reload and merge if the file has changed recently
59
if fd.stat.mtime.to_f > @last
60
parse_data(fd.read).merge(@hash).each_pair do |k,v|
61
@hash[k] = v
62
end
63
end
64
65
res = nil
66
67
# Update the file on disk if new data is written
68
if block_given?
69
res = block.call
70
fd.rewind
71
fd.write(JSON.pretty_generate(@hash))
72
fd.sync
73
fd.truncate(fd.pos)
74
end
75
76
@last = fd.stat.mtime.to_f
77
78
res
79
end
80
end
81
end
82
83
def parse_data(data)
84
return {} if data.to_s.strip.length == 0
85
begin
86
JSON.parse(data)
87
rescue JSON::ParserError => e
88
elog("JSONHashFile at #{path} was corrupt", error: e)
89
{}
90
end
91
end
92
93
end
94
end
95
96