Class: Win32::DirMonitor

Inherits:
Object
  • Object
show all
Defined in:
lib/win32/dirmonitor.rb

Defined Under Namespace

Classes: DirMonitorStruct, Error

Constant Summary collapse

VERSION =

The version of the win32-dirmonitor library

'1.0.1'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, host = Socket.gethostname) ⇒ DirMonitor

Creates a new DirMonitor object which sets the path and hostname on which the filesystem will be monitored for changes. If no hostname is provided, then the current host is assumed.

Raises:

  • (ArgumentError)

30
31
32
33
34
35
36
37
38
# File 'lib/win32/dirmonitor.rb', line 30

def initialize(path, host = Socket.gethostname)
  raise ArgumentError unless File.exist?(path)
  raise TypeError unless path.is_a?(String)
  raise TypeError unless host.is_a?(String)

  @path = path.tr("/", "\\")
  @host = host
  @conn = "winmgmts:{impersonationlevel=impersonate}!//#{host}/root/cimv2"
end

Instance Attribute Details

#hostObject (readonly)

The host on which to monitor the path.


24
25
26
# File 'lib/win32/dirmonitor.rb', line 24

def host
  @host
end

#pathObject (readonly)

The path to be monitored.


21
22
23
# File 'lib/win32/dirmonitor.rb', line 21

def path
  @path
end

Instance Method Details

#wait(seconds = nil) ⇒ Object

A event loop that will yield a DirMonitorStruct object whenever there is a change in a file on the path set in the constructor. The loop will timeout after the number of seconds provided, or indefinitely if no argument is provided.

The DirMonitorStruct contains the following members:

  • file # The full path of the file that was changed.

  • action # Either create, delete or modify.

  • changes # If modified, includes an array of changes.

If a modification occurs, the 'changes' struct member contains an array of arrays that describes the change. Each sub-array contains three members - the item that was modified, the previous value, and the current value.

Example:

mon = Win32::DirMonitor.new(“C:/Users/foo”)

# Monitor filesystem for one minute. mon.wait(60){ |s| p s }

# Sample struct returned after file was marked # hidden and read-only:

#<struct Struct::DirMonitorStruct

  file="c:\\Users\\foo\\test.txt",
  action="modify",
  changes=[
    ["AccessMask", "2032127", "2032057"],
    ["Hidden", "false", "true"],
    ["Writeable", "true", "false"]
  ]
>

Raises:

  • (TypeError)

76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/win32/dirmonitor.rb', line 76

def wait(seconds = nil)
  raise TypeError unless seconds.is_a?(Numeric) if seconds

  ole    = WIN32OLE.connect(@conn)
  drive  = @path.split(':').first + ":"
  folder = @path.split(':').last.gsub("\\", "\\\\\\\\")
  folder << "\\\\" unless folder[-1] == "\\"

  query = %Q{
    select * from __instanceOperationEvent
    within 2
    where targetInstance isa 'CIM_DataFile'
    and targetInstance.Drive='#{drive}'
    and targetInstance.Path='#{folder}'
  }

  # Asynchronous call. This will let the user break out of it manually.
  sink  = WIN32OLE.new('WbemScripting.SWbemSink')
  event = WIN32OLE_EVENT.new(sink)

  ole.execNotificationQueryAsync(sink, query)
  sleep 0.5

  event.on_event("OnObjectReady"){ |object, context|
    target = object.TargetInstance
    struct = DirMonitorStruct.new
    struct[:file] = target.Name

    case object.Path_.Class.to_s
    when "__InstanceCreationEvent"
      struct[:action] = 'create'
    when "__InstanceDeletionEvent"
      struct[:action] = 'delete'
    when "__InstanceModificationEvent"
      previous = object.PreviousInstance
      struct[:action] = 'modify'
      struct[:changes] = []

      target.Properties_.each{ |prop|
        if prop.Value != previous.send(prop.Name)
          struct[:changes] << [
            prop.Name,
            previous.send(prop.Name).to_s,
            prop.Value.to_s
          ]
        end
      }
    end

    yield struct
  }

  # If an argument is provided, timeout after that many seconds.
  if seconds
    begin
      Timeout.timeout(seconds){
        loop do
          WIN32OLE_EVENT.message_loop
        end
      }
    rescue Timeout::Error
      # Do nothing, return control to user
    end
  else
    loop do
      WIN32OLE_EVENT.message_loop
    end
  end
end