Рубрики
Без рубрики

Чтение данных о состоянии OpenVPN с Python (3 из 3)

Получите практические, реальные навыки Python на наших ресурсах и пути

Автор оригинала: Mike Driscoll.

Мы обсуждали, как использовать OpenVPN с Python в последних двух статьях. В этом заключительном посте я покажу, как принести все это вместе в графический интерфейс с кодом WXPYPHON. Я также собираюсь обсудить некоторые важные фрагменты.

Первый фрагмент, чтобы принять к сведению в Беги метод. Нам нужно убедиться, что служба OpenVPN работает при запуске нашей программы или файл журнала не будет обновлен. Итак, вы заметите, что используется метод StartService Win32ServiceUtil. Мы положили это в попробуйте Заявление, чтобы поймать ошибку, которая произойдет, если служба OpenVPN уже работает, не найден или не может быть запущен. Как правило, вы не должны использовать голые, кроме как можно маскировать другие ошибки в вашей программе; Тем не менее, я не смог найти соответствующий код ошибки для использования, поэтому я оставлю это для читателя.

def run(self):
    """
    Run the openvpn.exe script
    """
    vpnname='MCISVPN'
    configfile='mcisvpn.conf'
    defaultgw=''
    vpnserver=''
    vpnserverip = ''

    print 'Starting OpenVPN Service...',
    try:
        win32serviceutil.StartService('OpenVPN Service', None)
    except Exception, e:
        print e
    print 'success!'

    delayedresult.startWorker(self._resultConsumer, self._resultProducer, 
                              wargs=(self.jobID,self.abortEvent), jobID=self.jobID)

После попытки запустить службу OpenVPN, я использую модель резьбы, предоставленную wxpython, чтобы запустить код Watcher.py, который я написал о последнем времени, а также отслеживать мое местоположение в файле журнала.

Ниже приведен основной код GUI в полном объеме:

from vpnTBIcon import VPNIconCtrl

import os
import sys
import Queue
import threading
import time
import win32file
import win32con
import win32serviceutil
import wx
import wx.lib.delayedresult as delayedresult

ACTIONS = {
  1 : "Created",
  2 : "Deleted",
  3 : "Updated",
  4 : "Renamed to something",
  5 : "Renamed from something"
}

def watch_path (path_to_watch, include_subdirectories=False):
    FILE_LIST_DIRECTORY = 0x0001
    hDir = win32file.CreateFile (
        path_to_watch,
        FILE_LIST_DIRECTORY,
        win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
        None,
        win32con.OPEN_EXISTING,
        win32con.FILE_FLAG_BACKUP_SEMANTICS,
        None
        )
    while 1:
        results = win32file.ReadDirectoryChangesW (
            hDir,
            1024,
            include_subdirectories,
            win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
            win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
            win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
            win32con.FILE_NOTIFY_CHANGE_SIZE |
            win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
            win32con.FILE_NOTIFY_CHANGE_SECURITY,
            None,
            None
            )
        for action, file in results:
            full_filename = os.path.join (path_to_watch, file)
            if not os.path.exists (full_filename):
                file_type = ""
            elif os.path.isdir (full_filename):
                file_type = 'folder'
            else:
                file_type = 'file'
            yield (file_type, full_filename, ACTIONS.get (action, "Unknown"))

class Watcher (threading.Thread):

    def __init__ (self, path_to_watch, results_queue, **kwds):
        threading.Thread.__init__ (self, **kwds)
        self.setDaemon (1)
        self.path_to_watch = path_to_watch
        self.results_queue = results_queue
        self.start ()

    def run (self):
        for result in watch_path (self.path_to_watch):
            self.results_queue.put (result)

# -------------------------------------------------------------------------
# GUI Code starts here

class vpnGUI(wx.App):
    """
    wx application that wraps jrb's vpn script to allow it
    to run in the system tray
    """
    def __init__(self, redirect=False, filename=None):
        wx.App.__init__(self, redirect, filename)

        self.frame = wx.Frame(None, wx.ID_ANY, title='Voicemail', size=(800,500) )
                
        self.panel = wx.Panel(self.frame, wx.ID_ANY)

        self.abortEvent = delayedresult.AbortEvent()

        # Set defaults
        # ----------------------------------------------------------------------------------------
        self.jobID = 0

        # Create widget controls
        # ----------------------------------------------------------------------------------------
        # redirect stdout
        self.log = wx.TextCtrl(self.panel, wx.ID_ANY, size=(1000,500),
                               style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
        redir=RedirectText(self.log)
        sys.stdout=redir

        closeBtn = wx.Button(self.panel, wx.ID_ANY, 'Close')
        
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(self.log, 1, wx.ALL|wx.EXPAND, 5)
        mainSizer.Add(closeBtn, 0, wx.ALL|wx.CENTER, 5)
        self.panel.SetSizer(mainSizer)
        
        # Bind events
        # ----------------------------------------------------------------------------------------
        self.Bind(wx.EVT_BUTTON, self.onClose, closeBtn)
        self.Bind(wx.EVT_ICONIZE, self.onMinimize)

        # create the system tray icon:
        try:            
            self.tbicon = VPNIconCtrl(self.frame)                        
        except Exception, e:
            print 'Icon creation exception => %s' % e
            self.tbicon = None

        # comment this line out if you don't want to show the
        # GUI when the program is run
        self.frame.Show(True) # make the frame visible

        self.run()

    def run(self):
        """
        Run the openvpn service
        """
        vpnname='MCISVPN'
        configfile='mcisvpn.conf'
        defaultgw=''
        vpnserver=''
        vpnserverip = ''

        print 'Starting OpenVPN Service...',
        try:
            win32serviceutil.StartService('OpenVPN Service', None)
        except Exception, e:
            print e
        print 'success!'

        delayedresult.startWorker(self._resultConsumer, self._resultProducer, 
                                  wargs=(self.jobID,self.abortEvent), jobID=self.jobID)

    def _resultProducer(self, jobID, abortEvent):
        """
        GUI will freeze if this method is not called in separate thread.
        """
        PATH_TO_WATCH = [r'C:\Program Files\OpenVPN\log']
        try: path_to_watch = sys.argv[1].split (",") or PATH_TO_WATCH
        except: path_to_watch = PATH_TO_WATCH
        path_to_watch = [os.path.abspath (p) for p in path_to_watch]

        print "Watching %s at %s" % (", ".join (path_to_watch), time.asctime ())
        files_changed = Queue.Queue ()
        for p in path_to_watch:
            Watcher (p, files_changed)

        filepath = os.path.join(PATH_TO_WATCH[0], 'mcisvpn.log')
        print 'filepath => ' + filepath
        f = open(filepath)
        for line in f.readlines():
            print line
        last_pos = f.tell()
        f.close()
        
        while not abortEvent():
            try:
                file_type, filename, action = files_changed.get_nowait ()
                if action == 'Updated':
                    print 'Last pos => ', last_pos
                    f = open(filepath)
                    f.seek(last_pos)
                    for line in f.readlines():
                        if line != '\n':
                            print line

                    last_pos = f.tell()
                    f.close()
                    
            except Queue.Empty:
                pass
            time.sleep (1)
        
        return jobID

    def _resultConsumer(self, delayedResult):
        jobID = delayedResult.getJobID()
        assert jobID == self.jobID
        try:
            result = delayedResult.get()
        except Exception, exc:
            print "Result for job %s raised exception: %s" % (jobID, exc) 
            return
        

    def onMinimize(self, event):
        """ Minimize to tray """
        self.frame.Hide()

    def onClose(self, event):
        """
        Close the program
        """

        # recover stdout
        sys.stdout=sys.__stdout__
        
        # stop OpenVPN service
        try:
            print 'Stopping OpenVPN service...'
            win32serviceutil.StopService('OpenVPN Service', None)
        except Exception, e:
            print e        
        
        # stop the threads
        self.abortEvent.set()
        # remove the icon from the tray
        self.tbicon.Destroy()
        # close the frame
        self.frame.Close()

class RedirectText:
    def __init__(self,textDisplay):
        self.out=textDisplay

    def write(self,string):
        self.out.WriteText(string)
        
###### Run script! ######
if __name__ == "__main__":
    app = vpnGUI()
    app.MainLoop()

Вы заметите, что перенаправьте STDOUT в __init__ на нашем виджете управления текстовым управлением. Чтобы написать на виджета, мы используем печатное настроек Python. Мы сбрасываем STDOUT в OnClose обработчик события. Этот обработчик также останавливает службу OpenVPN, уничтожает значок системного лотка и закрывает программу.

И это все там действительно есть. Ниже приведены некоторые ссылки для тех из вас, кто хочет выкопать в этих инструментах.

Ресурсы

Источник для этих примеров

  • vpn.zip
  • vpn.tar.tar.