runtime/PLCObject.py
changeset 2463 8742337a9fe3
parent 2459 21164625b393
child 2485 ef327451d067
--- a/runtime/PLCObject.py	Tue Nov 27 13:34:14 2018 +0100
+++ b/runtime/PLCObject.py	Tue Dec 04 11:31:58 2018 +0100
@@ -34,6 +34,9 @@
 import Pyro.core as pyro
 import six
 from six.moves import _thread, xrange
+import md5
+from tempfile import mkstemp
+import shutil
 
 from runtime.typemapping import TypeTranslator
 from runtime.loglevels import LogLevelsDefault, LogLevelsCount
@@ -41,6 +44,8 @@
 from runtime import PlcStatus
 from runtime import MainWorker
 
+empty_md5_digest = md5.new().digest()
+
 if os.name in ("nt", "ce"):
     dlopen = _ctypes.LoadLibrary
     dlclose = _ctypes.FreeLibrary
@@ -74,7 +79,11 @@
 
 class PLCObject(object):
     def __init__(self, WorkingDir, argv, statuschange, evaluator, pyruntimevars):
-        self.workingdir = WorkingDir
+        self.workingdir = WorkingDir # must exits already
+        self.tmpdir = os.path.join(WorkingDir, 'tmp')
+        if os.path.exists(self.tmpdir):
+            shutil.rmtree(self.tmpdir)
+        os.mkdir(self.tmpdir)
         # FIXME : is argv of any use nowadays ?
         self.argv = [WorkingDir] + argv  # force argv[0] to be "path" to exec...
         self.statuschange = statuschange
@@ -91,6 +100,8 @@
         self.TraceLock = Lock()
         self.Traces = []
 
+        self._init_blobs()
+
     # First task of worker -> no @RunInMain
     def AutoLoad(self, autostart):
         # Get the last transfered PLC
@@ -447,8 +458,52 @@
     def GetPLCID(self):
         return getPSKID()
 
-    @RunInMain
-    def NewPLC(self, md5sum, data, extrafiles):
+    def _init_blobs(self):
+        self.blobs = {}
+        if os.path.exists(self.tmpdir):
+            shutil.rmtree(self.tmpdir)
+        os.mkdir(self.tmpdir)
+    
+    @RunInMain
+    def AppendChunkToBlob(self, data, blobID):
+        blob = ((mkstemp(dir=self.tmpdir) if data else None)\
+                   + (md5.new(),)) \
+               if blobID == empty_md5_digest \
+               else self.blobs.pop(blobID, None)
+
+        if blob is None:
+            return None
+
+        fobj, path, md5sum = blob
+        md5sum.update(data)
+        newBlobID = md5sum.digest()
+        if data:
+            os.write(fobj,data)
+            self.blobs[newBlobID] = blob
+        return newBlobID
+
+    @RunInMain
+    def PurgeBlobs(self):
+        for fobj, path, md5sum in self.blobs:
+            os.close(fobj) 
+        self._init_blobs()
+
+    def _BlobAsFile(self, blobID, newpath):
+        blob = self.blobs.pop(blobID, None)
+
+        if blob is None:
+            if blobID == md5.new().digest():
+                # create empty file
+                open(newpath,'r').close()
+                return
+            raise Exception(_("Missing data to create file: {}").format(newpath))
+
+        fobj, path, md5sum = blob
+        os.close(fobj)
+        shutil.move(path, newpath)
+            
+    @RunInMain
+    def NewPLC(self, md5sum, plc_object, extrafiles):
         if self.PLCStatus in [PlcStatus.Stopped, PlcStatus.Empty, PlcStatus.Broken]:
             NewFileName = md5sum + lib_ext
             extra_files_log = os.path.join(self.workingdir, "extra_files.txt")
@@ -458,18 +513,13 @@
                 else None
             new_PLC_filename = os.path.join(self.workingdir, NewFileName)
 
-            # Some platform (i.e. Xenomai) don't like reloading same .so file
-            replace_PLC_shared_object = new_PLC_filename != old_PLC_filename
-
-            if replace_PLC_shared_object:
-                self.UnLoadPLC()
+            self.UnLoadPLC()
 
             self.LogMessage("NewPLC (%s)" % md5sum)
             self.PLCStatus = PlcStatus.Empty
 
             try:
-                if replace_PLC_shared_object:
-                    os.remove(old_PLC_filename)
+                os.remove(old_PLC_filename)
                 for filename in open(extra_files_log, "rt").readlines() + [extra_files_log]:
                     try:
                         os.remove(os.path.join(self.workingdir, filename.strip()))
@@ -480,17 +530,16 @@
 
             try:
                 # Create new PLC file
-                if replace_PLC_shared_object:
-                    open(new_PLC_filename, 'wb').write(data)
+                self._BlobAsFile(plc_object, new_PLC_filename)
 
                 # Store new PLC filename based on md5 key
                 open(self._GetMD5FileName(), "w").write(md5sum)
 
                 # Then write the files
                 log = open(extra_files_log, "w")
-                for fname, fdata in extrafiles:
+                for fname, blobID in extrafiles:
                     fpath = os.path.join(self.workingdir, fname)
-                    open(fpath, "wb").write(fdata)
+                    self._BlobAsFile(blobID, fpath)
                     log.write(fname+'\n')
 
                 # Store new PLC filename
@@ -501,9 +550,7 @@
                 PLCprint(traceback.format_exc())
                 return False
 
-            if not replace_PLC_shared_object:
-                self.PLCStatus = PlcStatus.Stopped
-            elif self.LoadPLC():
+            if self.LoadPLC():
                 self.PLCStatus = PlcStatus.Stopped
             else:
                 self.PLCStatus = PlcStatus.Broken