diff --git a/app/app.py b/app/app.py index 1db10109..2dd80190 100644 --- a/app/app.py +++ b/app/app.py @@ -4,60 +4,19 @@ def main(): # Interface Test - - ## Create Connection - connection = devtools.Connection() - - connection.list_tabs() - - ## Simulate Commands - print( - connection.browser_session.send_command( - "command1", dict(param1="1", param2="a") - ) - ) - print( - connection.browser_session.send_command( - "command2", dict(param1="2", param2="b") - ) - ) - - ## Create Tab - myTab = connection.create_tab() - connection.list_tabs() - - ## Simulate Commands - print(myTab.send_command("tabCommand1", dict(param1="tab1", param2="taba"))) - print(myTab.send_command("tabCommand2", dict(param1="tab2", param2="tabb"))) - print( - connection.browser_session.send_command( - "command3", dict(param1="3", param2="c") - ) - ) - - ## Close Tab - connection.close_tab(myTab) - connection.list_tabs() - - ## Simulate Commands - print( - connection.browser_session.send_command( - "command4", dict(param1="4", param2="d") - ) - ) - # Process/Pipes Test - with devtools.Browser() as browser: - pipe = browser.pipe + with devtools.Browser(headless=False) as browser: + ## Create Protocol + connection = browser.protocol - pipe.write("{}") - print(pipe.read_jsons(debug=True)) - print(pipe.read_jsons(blocking=False, debug=True)) - print(pipe.read_jsons(blocking=False, debug=True)) - print(pipe.read_jsons(blocking=False, debug=True)) + connection.send_command(command="Target.createTarget", params={"url": "https://www.youtube.com/"}) - time.sleep(10) + connection.pipe.read_jsons(debug=True) + connection.pipe.read_jsons(blocking=False, debug=True) + connection.pipe.read_jsons(blocking=False, debug=True) + connection.pipe.read_jsons(blocking=False, debug=True) + time.sleep(10) if __name__ == "__main__": main() diff --git a/app/app_devtools.py b/app/app_devtools.py index 44ddbdc9..be791c11 100644 --- a/app/app_devtools.py +++ b/app/app_devtools.py @@ -54,14 +54,15 @@ list_r = [r1, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12] -## Create Connection -browser = devtools.Connection() -browser.list_tabs() +## Create Protocol +browser = devtools.Browser() +connection = browser.protocol +connection.list_tabs() ## Print Commands for r in list_r: print( - browser.browser_session.send_command( + connection.browser_session.send_command( command=r["method"], params=r["params"] if "params" in r else None ) ) diff --git a/devtools/__init__.py b/devtools/__init__.py index ba194ae4..16210cf4 100644 --- a/devtools/__init__.py +++ b/devtools/__init__.py @@ -1,4 +1,3 @@ from .browser import Browser -from .connection import Connection -__all__ = [Browser, Connection] +__all__ = [Browser] diff --git a/devtools/browser.py b/devtools/browser.py index 2ba0d121..31a22fa4 100644 --- a/devtools/browser.py +++ b/devtools/browser.py @@ -1,4 +1,5 @@ from .pipe import Pipe +from .protocol import Protocol import platform import os import sys @@ -7,7 +8,7 @@ class Browser: - def __init__(self, debug=None, path=None): + def __init__(self, debug=None, path=None, headless=True): self.pipe = Pipe() if not debug: # false o None @@ -27,6 +28,9 @@ def __init__(self, debug=None, path=None): new_env = os.environ.copy() new_env["CHROMIUM_PATH"] = path + if headless: + new_env["HEADLESS"] = "--headless" + win_only = {} if platform.system() == "Windows": win_only = {"creationflags": subprocess.CREATE_NEW_PROCESS_GROUP} @@ -46,6 +50,7 @@ def __init__(self, debug=None, path=None): **win_only, ) self.subprocess = proc + self.protocol = Protocol(self.pipe) def __enter__(self): return self @@ -60,3 +65,6 @@ def close_browser(self): self.subprocess.terminate() self.subprocess.wait(5) self.subprocess.kill() + + def send_command(self, command, params=None, cb=None): + return self.protocol.send_command(self, command, params, cb) diff --git a/devtools/chrome_wrapper.py b/devtools/chrome_wrapper.py index 62f50b89..8700e5c7 100644 --- a/devtools/chrome_wrapper.py +++ b/devtools/chrome_wrapper.py @@ -28,12 +28,14 @@ cli = [ path, - "--headless", "--remote-debugging-pipe", "--disable-breakpad", "--allow-file-access-from-files", ] +if "HEADLESS" in os.environ: + cli.append("--headless") + if system == "Windows": to_chromium_handle = msvcrt.get_osfhandle(3) os.set_handle_inheritable(to_chromium_handle, True) diff --git a/devtools/connection.py b/devtools/connection.py deleted file mode 100644 index a7e46f37..00000000 --- a/devtools/connection.py +++ /dev/null @@ -1,29 +0,0 @@ -from .session import Session -from collections import OrderedDict -import uuid - - -class Connection: - def __init__(self): - self.browser_session = Session(self, session_id="") - self.tab_sessions = OrderedDict() - - def create_tab(self): - session_id = str(uuid.uuid4()) - session_obj = Session(self, session_id=session_id) - self.tab_sessions[id(session_obj)] = session_obj - print(f"New Session Created: {session_obj.session_id}") - return session_obj - - def list_tabs(self): - print("Sessions".center(50,'-')) - for session_instance in self.tab_sessions.values(): - print(str(session_instance.session_id).center(50,' ')) - print("End".center(50,'-')) - - def close_tab(self, session_obj): - del self.tab_sessions[id(session_obj)] - print(f"The following session was deleted: {session_obj.session_id}") - - def send_command(self, command, params=None, cb=None): - return self.browser_session.send_command(self, command, params, cb) diff --git a/devtools/pipe.py b/devtools/pipe.py index b504561f..719e5a55 100644 --- a/devtools/pipe.py +++ b/devtools/pipe.py @@ -12,8 +12,20 @@ def __init__(self): self.read_from_chromium, self.write_from_chromium = list(os.pipe()) self.read_to_chromium, self.write_to_chromium = list(os.pipe()) - def write(self, msg): # this should accept an objects not a string - os.write(self.write_to_chromium, str.encode(msg + "\0")) + def write_json( + self, message_id, method, params=None, session_id="" + ): # this should accept an objects not a string + if params: + message = {"id": message_id, "method": method, "params": params} + else: + message = {"id": message_id, "method": method} + + if session_id != "": + message["session_id"] = session_id + + encoded_message = json.dumps(message).encode() + b"\0" + + os.write(self.write_to_chromium, encoded_message) def read_jsons(self, blocking=True, debug=False): if debug: diff --git a/devtools/protocol.py b/devtools/protocol.py new file mode 100644 index 00000000..de231b69 --- /dev/null +++ b/devtools/protocol.py @@ -0,0 +1,33 @@ +from .tab import Tab +from .session import Session +from collections import OrderedDict + + +class Protocol: + def __init__(self, browser_pipe): + self.browser_session = Session(self, session_id="") + self.target_id = 0 + self.tabs = OrderedDict() + self.pipe = browser_pipe + + def create_tab(self): + tab_obj = Tab() + self.tabs[tab_obj.target_id] = tab_obj + print(f"New Tab Created: {tab_obj.target_id}") + return tab_obj + + def list_tabs(self): + print("Tabs".center(50, "-")) + for target_id in self.tabs.keys(): + print(target_id.center(50, " ")) + print("End".center(50, "-")) + + def close_tab(self, tab_id): + if isinstance(tab_id, str): + del self.tabs[tab_id] + else: + del self.tabs[tab_id.target_id] + print(f"The following tab was deleted: {tab_id}") + + def send_command(self, command, params=None, cb=None): + return self.browser_session.send_command(command, params, cb) diff --git a/devtools/session.py b/devtools/session.py index 3038c732..6b68b76e 100644 --- a/devtools/session.py +++ b/devtools/session.py @@ -1,8 +1,9 @@ import json +import uuid class Session: - def __init__(self, parent, session_id=""): + def __init__(self, parent, session_id=str(uuid.uuid4())): if isinstance(session_id, str): self.session_id = session_id else: @@ -27,15 +28,25 @@ def send_command(self, command, params=None, cb=None): "method": command, } + if self.session_id != "": + json_command["session_id"] = self.session_id + if params: json_command["params"] = params - if self.session_id != "": - json_command["session_id"] = self.session_id + self.parent_connection.pipe.write_json( + message_id=json_command["id"], + method=json_command["method"], + params=json_command["params"], + session_id=self.session_id, + ) + else: + self.parent_connection.pipe.write_json( + message_id=json_command["id"], + method=json_command["method"], + session_id=self.session_id, + ) self.message_id += 1 return json.dumps(json_command) - - def close_tab(self): - self.parent.close_tab(self) diff --git a/devtools/tab.py b/devtools/tab.py new file mode 100644 index 00000000..dd09c2d1 --- /dev/null +++ b/devtools/tab.py @@ -0,0 +1,28 @@ +from .session import Session +from collections import OrderedDict +import uuid + + +class Tab: + def __init__(self): + self.tab_sessions = OrderedDict() + self.target_id = str(uuid.uuid4()) + + def add_session(self): + session_obj = Session(self) + self.tab_sessions[session_obj.session_id] = session_obj + print(f"New Session Added: {session_obj.session_id}") + return session_obj + + def list_sessions(self): + print("Sessions".center(50, "-")) + for session_instance in self.tab_sessions.values(): + print(str(session_instance.session_id).center(50, " ")) + print("End".center(50, "-")) + + def close_session(self, session_obj): + if isinstance(session_obj, str): + del self.tab_sessions[session_obj] + else: + del self.tab_sessions[session_obj.session_id] + print(f"The following session was deleted: {session_obj.session_id}")