• Welcome, Guest. Please login.
 
May 26, 2019, 12:38:05 am

News:

Welcome to the SQLitening support forums!


FileWatcher

Started by cj, July 02, 2015, 08:53:22 am

Previous topic - Next topic

cj

July 02, 2015, 08:53:22 am Last Edit: July 02, 2015, 09:15:17 am by cj
Monitor SQLiteningServer.log or even an entire database for any change.
Only text files may be viewed.

May be useful to alert you when people are logging in or using a database.
Thanks to Larry Charlton at the PowerBASIC site for the code.
http://www.powerbasic.com/support/pbforums/showthread.php?t=50986


FileWatcher.Bas

#COMPILE EXE
#DIM ALL
'http://www.powerbasic.com/support/pbforums/showthread.php?t=50986
'Larry Charlton modified  7/2/2015 with 3 modifications for SQLitening
'
'Added 3 modifications:
'filename to watch, beep on change, optionally show log
'
$FileNameToWatch="c:\sql\bin\sqliteningserver.log" 'modification 1 remark to ask for name
%BeepOnAnyChange = 1  'modification 2  change to 0 for no beep on changes
%ShowLogOnChanges =1  'modification 3

%UNICODE = 1
#INCLUDE ONCE "win32api.inc"
#INCLUDE ONCE "FileWatcher.inc"

GLOBAL fw AS iFileWatcher  ' File watcher
GLOBAL filename AS WSTRING ' File we're watching
GLOBAL hDlg AS DWORD:       ' Open dialog

%FILE_EXIT    = 1005
%FILE_OPEN    = 1006
%CTL_TEXT     = 1001

FUNCTION PBMAIN()
  LOCAL hFont, hTopMenu, hFileMenu, hAccel, hRes AS DWORD
  DIM menuAccel(0) AS ACCELAPI

  DIALOG NEW PIXELS, %HWND_DESKTOP, "File Watcher", 105, 114, 607, 483, %WS_OVERLAPPEDWINDOW, TO hDlg
  CONTROL ADD TEXTBOX, hDlg, %CTL_TEXT, "", 0, 0, 0, 0, %WS_CHILD OR _
                                                            %WS_VISIBLE OR _
                                                            %WS_BORDER OR _
                                                            %WS_TABSTOP OR _
                                                            %WS_VSCROLL OR _
                                                            %WS_HSCROLL OR _
                                                            %ES_LEFT OR _
                                                            %ES_MULTILINE OR _
                                                            %ES_READONLY OR _
                                                            %ES_AUTOHSCROLL OR _
                                                            %ES_AUTOVSCROLL,_
                                                            %WS_EX_RIGHTSCROLLBAR
  FONT NEW "Courier New", 10, 0, %ANSI_CHARSET TO hFont
  CONTROL SET FONT hDlg, %CTL_TEXT, hFont

  MENU NEW BAR TO hTopMenu
  MENU NEW POPUP TO hFileMenu

  MENU ADD POPUP, hTopMenu, "File", hFileMenu, %MF_ENABLED
  MENU ADD STRING, hFileMenu, "&Open" & $TAB & "Ctrl+O", %FILE_OPEN, %MF_ENABLED
  MENU ADD STRING, hFileMenu, "-", 0, 0
  MENU ADD STRING, hFileMenu, "E&xit", %FILE_EXIT, %MF_ENABLED

  MENU ATTACH hTopMenu, hDlg

  menuAccel(0).fVirt = %FVIRTKEY OR %FCONTROL OR %FNOINVERT
  menuAccel(0).Key = ASC("O")
  menuAccel(0).Cmd = %FILE_OPEN

  ACCEL ATTACH hDlg, menuAccel() TO hAccel

  DIALOG SHOW MODELESS hDlg, CALL ShowFileWatcherProc TO hRes
  GetNewFile()
  IF ISNOTHING( fw ) THEN EXIT FUNCTION

  CALL OnFileChanged( filename ): ' Initial load

  DO
    DIALOG DOEVENTS
  LOOP WHILE ISWIN(hDlg)

  IF ISOBJECT( fw ) THEN fw.Stop()

  FONT END hFont
END FUNCTION

CALLBACK FUNCTION ShowFileWatcherProc()
  LOCAL w, h AS LONG

  SELECT CASE CONST CB.MSG
    CASE %WM_SIZE
      DIALOG GET CLIENT hDlg TO w, h
      CONTROL SET SIZE hDlg, %CTL_TEXT, w, h

    CASE %WM_COMMAND
      SELECT CASE CONST CB.CTL
        CASE %FILE_OPEN: CALL GetNewFile():   CALL OnFileChanged( filename )
        CASE %FILE_EXIT: DIALOG END hDlg
      END SELECT
  END SELECT
END FUNCTION

SUB GetNewFile()
  'do not display file to watch if $FileNametoWatch is used
  LOCAL newFile AS WSTRING
  #IF %DEF($FilenameToWatch)
    newfile = $FilenameToWatch
  #ELSE
  DISPLAY OPENFILE 0, , , "Select File To Watch", "\sql\bin", "logs"+$NUL+"*.log"+$NUL,"sqliteningserver.log", "", %OFN_FILEMUSTEXIST TO newFile
  IF newFile = "" THEN EXIT SUB
  #ENDIF
  IF ISOBJECT( fw ) THEN fw.Stop()
  fw = NOTHING
  filename = newFile
  CALL StartFileWatcher( fw, newFile, CODEPTR( OnFileChanged ) )
END SUB

SUB OnFileChanged( filename AS WSTRING )
  LOCAL value, c AS STRING
  LOCAL i, f AS LONG
  STATIC cnt AS LONG

  IF %BeepOnAnyChange THEN BEEP
  IF %ShowLogOnChanges = 0 THEN GOTO OnlyShowCount

  ' Reload file
  ERRCLEAR
  f = FREEFILE
  FOR i=1 TO 10
    OPEN filename FOR BINARY ACCESS READ LOCK SHARED AS #f
    IF ERR=0 THEN EXIT FOR
    ERRCLEAR
    SLEEP 100
  NEXT
  IF ERR<>0 THEN
    CLOSE #f
    CONTROL SET TEXT hDlg, %CTL_TEXT, "(unable to open file " + ERROR$ + ")"
  ELSE
    GET$ #f, LOF(#f), value
    CLOSE #f
OnlyshowCount:
    INCR cnt
    c = FORMAT$( cnt, "#,##0" )
    value = BUILD$("Load round ", c, $CRLF, value )
    CONTROL SET TEXT hDlg, %CTL_TEXT, value
  END IF
END SUB

FileWatcher.Inc

%BUFSIZE = 1024

SUB NewFileWatcher( obj AS iFileWatcher, filename AS WSTRING, BYVAL notifyRoutine AS DWORD )
  obj = CLASS "cFileWatcher"
  obj.Initialize( filename, notifyRoutine )
END SUB

SUB StartFilewatcher( obj AS iFileWatcher, filename AS WSTRING, BYVAL notifyRoutine AS DWORD )
  CALL NewFileWatcher( obj, filename, notifyRoutine )
  obj.Launch( BYVAL 0 )
END SUB

SUB NotifyPattern( filename AS WSTRING )
END SUB

CLASS cFileWatcher
  INSTANCE ThreadParam AS LONG
  INSTANCE running_ AS LONG
  INSTANCE notifier_ AS iFileWatchNotifier
  INSTANCE notifyRoutine_ AS DWORD
  INSTANCE filename_ AS WSTRING
  INSTANCE hStop AS DWORD

  THREAD METHOD MAIN() AS LONG
  #ALIGN 4
    LOCAL buffer1 AS STRINGZ * %BUFSIZE
    LOCAL buffer2 AS STRINGZ * %BUFSIZE
    LOCAL hover AS OVERLAPPED
    LOCAL hWait() AS DWORD
    LOCAL dwWaitStatus, flags, hDir AS DWORD
    LOCAL fullPath, modFile AS WSTRING
    LOCAL finished, numBytes, cnt, i AS LONG
    LOCAL fn AS WSTRING PTR
    LOCAL fi AS FILE_NOTIFY_INFORMATION

    REDIM hWait(1) AS LOCAL DWORD

    IF ISFALSE ISFILE( filename_ ) OR notifyRoutine_=0 THEN EXIT METHOD
    CALL StartFileWatchNotifier( notifier_, filename_, notifyRoutine_ )

    fullPath = PATHSCAN$( PATH, filename_ )

    ' Other things we can watch for
    '%FILE_NOTIFY_CHANGE_FILE_NAME
    '%FILE_NOTIFY_CHANGE_DIR_NAME
    '%FILE_NOTIFY_CHANGE_ATTRIBUTES
    '%FILE_NOTIFY_CHANGE_SIZE
    '%FILE_NOTIFY_CHANGE_SECURITY
    flags = %FILE_NOTIFY_CHANGE_LAST_WRITE: ' Watching for file changes/writes
    hDir = CreateFile( BYVAL STRPTR(fullPath), %FILE_LIST_DIRECTORY, %FILE_SHARE_READ OR %FILE_SHARE_WRITE OR %FILE_SHARE_DELETE, BYVAL %NULL, %OPEN_EXISTING, %FILE_FLAG_BACKUP_SEMANTICS OR %FILE_FLAG_OVERLAPPED , %NULL)
    hWait(0) = CreateEvent( BYVAL %NULL, 0, 0, BYVAL %NULL )
    hWait(1) = CreateEvent( BYVAL %NULL, 0, 0, BYVAL %NULL )
    hStop = hWait(1)
    hover.hEvent = hWait(0)

    DO WHILE -1
      MEMORY FILL VARPTR( buffer1 ), %BUFSIZE, BYTE 0
      ResetEvent( hover.hEvent )

      'do not use VARPTR with Jose Roca includes
      IF ReadDirectoryChangesW(hDir, VARPTR(buffer1), %BUFSIZE, %FALSE, flags, %NULL, hover, %NULL) THEN
      'IF ReadDirectoryChangesW(hDir, buffer1, %BUFSIZE, %FALSE, flags, %NULL, hover, %NULL) THEN

        dwWaitStatus = WaitForMultipleObjects( 2, hWait(0), %FALSE, %INFINITE )
        SELECT CASE CONST dwWaitStatus - %WAIT_OBJECT_0
          CASE 0: ' Directory change signaled
            'If returnedBytes>0 Then
              MEMORY COPY VARPTR( buffer1 ), VARPTR( buffer2 ), %BUFSIZE
              notifier_.Changed( VARPTR( buffer2 ) )
            'End If
          CASE 1: ' hStop signaled
            EXIT LOOP
        END SELECT
      END IF
    LOOP
    hStop = 0
    CloseHandle( hWait(0) )
    CloseHandle( hWait(1) )
    CloseHandle( hDir )
    notifier_.Stop()
    notifier_ = NOTHING
  END METHOD

  INTERFACE iFileWatcher
    INHERIT IPOWERTHREAD

    METHOD Initialize( filename AS WSTRING, notifyRoutine AS DWORD )
      IF filename="" OR notifyRoutine=0 THEN EXIT METHOD
      IF filename_ = "" OR notifyRoutine_ = 0 THEN
        filename_ = filename
        notifyRoutine_ = notifyRoutine
      END IF
    END METHOD

    PROPERTY GET Running() AS LONG
      PROPERTY = running_
    END PROPERTY

    PROPERTY GET Filename() AS WSTRING
      PROPERTY = filename_
    END PROPERTY

    PROPERTY GET NotifyRoutine() AS DWORD
      PROPERTY = notifyRoutine_
    END PROPERTY

    METHOD STOP()
      LOCAL fw AS iFileWatcher
      fw = ME
      SetEvent( hStop )
      fw.Join( fw, 0 )
      fw = NOTHING
    END METHOD

  END INTERFACE
END CLASS

SUB StartFileWatchNotifier( obj AS iFileWatchNotifier, filename AS WSTRING, BYVAL notifyRoutine AS DWORD )
  obj = CLASS "cFileWatchNotifier"
  obj.Initialize( filename, notifyRoutine )
  obj.Launch( BYVAL 0 )
END SUB

CLASS cFileWatchNotifier
  INSTANCE ThreadParam AS LONG
  INSTANCE changed_ AS DWORD
  INSTANCE stopped_ AS DWORD

  INSTANCE notifyRoutine_ AS DWORD
  INSTANCE filename_ AS WSTRING
  INSTANCE fni AS FILE_NOTIFY_INFORMATION PTR

  THREAD METHOD MAIN() AS LONG
    LOCAL cnt AS LONG
    LOCAL fi AS FILE_NOTIFY_INFORMATION PTR
    LOCAL filename, fullPath, modFile AS WSTRING
    LOCAL i, finished AS LONG
    LOCAL hWait() AS DWORD
    LOCAL ofs AS LONG
    DIM hWait(1) AS LOCAL DWORD
    LOCAL dwWaitStatus AS DWORD

    hWait(0) = CreateEvent( BYVAL %NULL, 0, 0, BYVAL %NULL )
    hWait(1) = CreateEvent( BYVAL %NULL, 0, 0, BYVAL %NULL )
    changed_ = hWait(0)
    stopped_ = hWait(1)

    fullPath = PATHSCAN$( PATH, filename_ )
    filename = LCASE$( PATHSCAN$( NAMEX, filename_ ) )

    DO WHILE -1
      ResetEvent( changed_ )
      dwWaitStatus = WaitForMultipleObjects( 2, hWait(0), %FALSE, %INFINITE )
      SELECT CASE CONST dwWaitStatus - %WAIT_OBJECT_0
        CASE 0: ' Changed
          fi = fni
          finished = 0
          WHILE NOT finished
            finished = ( @fi.NextEntryOffset = 0 )
            IF @fi.Action = %FILE_ACTION_MODIFIED AND @fi.FileNameLength THEN
              modFile = PEEK$$( VARPTR( @fi.FileName ), @fi.FileNameLength )
              i = LEN(modFile)
              WHILE i>1 AND ASC(modFile,i)<=32
                DECR i
              WEND
              modFile=LEFT$(modFile,i)
              modFile = LCASE$( DIR$( fullPath + modFile ) )
              IF modFile = LCASE$( filename ) THEN
                CALL DWORD notifyRoutine_ USING NotifyPattern( filename_ )
              END IF
            END IF
            fi += @fi.NextEntryOffset
          WEND
        CASE 1: ' Stopped
          EXIT LOOP
      END SELECT
    LOOP
  END METHOD

  INTERFACE iFileWatchNotifier
    INHERIT IPOWERTHREAD

    METHOD Initialize( filename AS WSTRING, notifyRoutine AS DWORD )
      IF filename_<>"" OR notifyRoutine_ THEN EXIT METHOD
      filename_ = filename
      notifyRoutine_ = notifyRoutine
    END METHOD

    METHOD STOP()
      LOCAL fwn AS iFileWatchNotifier
      SetEvent( stopped_ )
      fwn = ME
      fwn.Join( fwn, 0 )
      fwn = NOTHING
    END METHOD

    METHOD Changed( BYVAL fi AS DWORD )
      fni = fi
      SetEvent( changed_ )
    END METHOD
  END INTERFACE
END CLASS