Asynchronous IPC: Initial implementation

This commit adds a mixin which sets up a modal operator which:
* Starts a subprocess
* Polls for messages from that subprocesses
This commit is contained in:
gandalf3
2017-06-29 17:46:08 -07:00
parent 2268925733
commit 9dfd58671e
4 changed files with 86 additions and 17 deletions

View File

@@ -9,11 +9,18 @@ import bpy
class PackageSettings(bpy.types.PropertyGroup): class PackageSettings(bpy.types.PropertyGroup):
url = bpy.props.StringProperty(name="URL") url = bpy.props.StringProperty(name="URL")
# class PackageManager:
# # For some reason accessing 'settings' PointerProperty via wm.package_manager.settings gives a value error
# # but accessing it when not stored in this class (wm.package_manager_settings) is fine?
# # settings = bpy.props.PointerProperty(type=PackageSettings)
# pipes = []
def register(): def register():
from . import (pkg_ops, pkg_ui) from . import (pkg_ops, pkg_ui)
bpy.utils.register_class(PackageSettings) bpy.utils.register_class(PackageSettings)
bpy.types.WindowManager.PackageManagerSettings = bpy.props.PointerProperty(type=PackageSettings) # bpy.types.WindowManager.package_manager = PackageManager()
bpy.types.WindowManager.package_manager_settings = bpy.props.PointerProperty(type=PackageSettings)
pkg_ops.register() pkg_ops.register()
pkg_ui.register() pkg_ui.register()
@@ -22,5 +29,6 @@ def unregister():
pkg_ops.unregister() pkg_ops.unregister()
pkg_ui.unregister(); pkg_ui.unregister();
del bpy.types.WindowManager.PackageManagerSettings bpy.utils.unregister_class(PackageSettings)
del bpy.types.WindowManager.package_manager

View File

@@ -21,10 +21,20 @@ SCHEMA_VERSION = 1
class BadAddon(Exception): class BadAddon(Exception):
pass pass
def fetch(url): def fetch(url, pipe):
pipe[0].close()
try:
# TODO: do conditional request # TODO: do conditional request
re = requests.get(url) re = requests.get(url)
print(re.json()) # print(re.json())
pipe[1].send(re.headers)
finally:
pipe[1].close()
# class Package():
# def __init__(self):
def parse_blinfo(source: str) -> dict: def parse_blinfo(source: str) -> dict:

View File

@@ -1,21 +1,72 @@
import bpy import bpy
from multiprocessing import Process import logging
from multiprocessing import Process, Pipe
from . import blenderpack from . import blenderpack
class PACKAGE_OT_fetch_lists(bpy.types.Operator): class SubprocessOperatorMixin:
bl_idname = "package.fetch_lists" timer = None
bl_label = "Update package list(s)"
# run once in invoke
def setup(self):
pass
# run on receipt of data from subprocess
def handle_response(self, resp):
pass
def __init__(self):
self.pipe = Pipe()
self.subprocess = None
def execute(self, context):
return self.invoke(context, None)
def invoke(self, context, event):
self.subprocess.start()
# we have to explicitly close the end of the pipe we are NOT using,
# otherwise no exception will be generated when the other process closes its end.
self.pipe[1].close()
wm = context.window_manager
wm.modal_handler_add(self)
self.timer = wm.event_timer_add(.01, context.window)
self.setup()
return {'RUNNING_MODAL'}
def modal(self, context, event):
print("polling")
try:
if self.pipe[0].poll():
newdata = self.pipe[0].recv()
else:
newdata = None
except EOFError:
return {'FINISHED'}
if newdata is not None:
self.handle_response(newdata)
return {'PASS_THROUGH'}
class PACKAGE_OT_fetch(SubprocessOperatorMixin, bpy.types.Operator):
bl_idname = "package.fetch"
bl_label = "Update package list(s)"
def __init__(self):
SubprocessOperatorMixin.__init__(self)
settings = bpy.context.window_manager.package_manager_settings
self.subprocess = Process(target=blenderpack.fetch, args=(settings.url, self.pipe))
def handle_response(self, resp):
print("your response:", resp)
def execute(self, context): def execute(self, context):
settings = context.window_manager.PackageManagerSettings
proc = Process(target=lambda: blenderpack.fetch(settings.url))
proc.start()
return {'FINISHED'} return {'FINISHED'}
def register(): def register():
bpy.utils.register_class(PACKAGE_OT_fetch_lists) bpy.utils.register_class(PACKAGE_OT_fetch)
def unregister(): def unregister():
bpy.utils.unregister_class(PACKAGE_OT_fetch_lists) bpy.utils.unregister_class(PACKAGE_OT_fetch)

View File

@@ -16,8 +16,8 @@ class USERPREF_PT_packages(bpy.types.Panel):
layout = self.layout layout = self.layout
row = layout.row() row = layout.row()
row.prop(context.window_manager.PackageManagerSettings, "url") row.prop(context.window_manager.package_manager_settings, "url")
row.operator(pkg_ops.PACKAGE_OT_fetch_lists.bl_idname, text="Fetch") row.operator(pkg_ops.PACKAGE_OT_fetch.bl_idname, text="Fetch")
def register(): def register():
bpy.utils.register_class(USERPREF_PT_packages) bpy.utils.register_class(USERPREF_PT_packages)