diff --git a/src/blenderbim/blenderbim/bim/module/csv/operator.py b/src/blenderbim/blenderbim/bim/module/csv/operator.py index 466a9f4d3d..b85b5bddfb 100644 --- a/src/blenderbim/blenderbim/bim/module/csv/operator.py +++ b/src/blenderbim/blenderbim/bim/module/csv/operator.py @@ -24,6 +24,7 @@ import logging import tempfile import ifcopenshell import ifcopenshell.util.selector +import blenderbim.core.search as core import blenderbim.tool as tool import blenderbim.bim.module.drawing.scheduler as scheduler from blenderbim.bim.ifc import IfcStore @@ -313,4 +314,5 @@ class OpenWebUi(bpy.types.Operator): bl_label = "Open Web UI" def execute(self, context): + core.open_web_ui(tool.Search) return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/core/search.py b/src/blenderbim/blenderbim/core/search.py index 0fe60fdb65..11644d128e 100644 --- a/src/blenderbim/blenderbim/core/search.py +++ b/src/blenderbim/blenderbim/core/search.py @@ -1,2 +1,6 @@ def show_scene_elements(spatial): spatial.show_scene_objects() + + +def open_web_ui(search): + search.open_web_ui() diff --git a/src/blenderbim/blenderbim/tool/search.py b/src/blenderbim/blenderbim/tool/search.py index e018d3aa12..2f990e3393 100644 --- a/src/blenderbim/blenderbim/tool/search.py +++ b/src/blenderbim/blenderbim/tool/search.py @@ -6,6 +6,16 @@ import ifcopenshell.guid import ifcopenshell.util.selector from blenderbim.bim.prop import BIMFacet from typing import Union, Literal +import os +import webbrowser +import asyncio +import threading +import websockets +import json + +connected_sockets = set() +websocket_server: websockets.WebSocketServer +ws_thread_loop = asyncio.new_event_loop() class Search(blenderbim.core.tool.Search): @@ -113,6 +123,64 @@ class Search(blenderbim.core.tool.Search): return value return '"' + value.replace('"', '\\"') + '"' + @classmethod + def get_webui_data(cls): + data = {} + data["ifc_file"] = bpy.context.scene.BIMProperties.ifc_file + return json.dumps(data) + + @classmethod + async def broadcast(cls, message): + for sock in connected_sockets: + await sock.send(message) + + @classmethod + async def ws_server_handler(cls, websocket): + connected_sockets.add(websocket) + intial_data = cls.get_webui_data() + await cls.broadcast(intial_data) + try: + async for message in websocket: + # TODO: handle incoming messages + continue + finally: + connected_sockets.remove(websocket) + + @classmethod + async def run_ws_server(cls): + websocket_server = await websockets.serve(cls.ws_server_handler, "localhost", 8765) + # WebSocket server started. + + # Check if a client is connected every 10 seconds + async def check_connections(): + while True: + await asyncio.sleep(10) + if not connected_sockets: + websocket_server.close() + break + + await check_connections() + await websocket_server.wait_closed() + + @classmethod + def open_web_ui(cls): + def set_thread_loop(): + asyncio.set_event_loop(ws_thread_loop) + asyncio.run(cls.run_ws_server()) + + wserver_thread = threading.Thread(target=set_thread_loop) + wserver_thread.daemon = True + wserver_thread.start() + + def open_browser(): + # TODO: add web ui HTML/JS files to open + # webbrowser.open("file://" + os.path.join(bpy.context.scene.BIMProperties.data_dir, "webui", "index.html") + pass + + # Delay for 2 seconds before openning browser + timer = threading.Timer(2.0, open_browser) + timer.start() + class ImportFilterQueryTransformer(lark.Transformer): def __init__(self, filter_groups):