balta2ar / brotab

Control your browser's tabs from the command line
MIT License
389 stars 27 forks source link

How to use it on Windows Chrome #19

Closed naeloob closed 4 years ago

naeloob commented 4 years ago

First to thank you for this great tool. It's Awesome!!

I managed to use it on Windows-Chrome.

That's are the changes i've done.

Change SIGPIPE

On windows there's no SIGPIPE signal. I've seen on the python docs that they advise to catch the exception BrokenPipeError:

From https://docs.python.org/3.7/library/signal.html#note-on-sigpipe

Changes on main function of brotab_mediator.py def main():

signal.signal(signal.SIGPIPE, signal_pipe)

monkeypatch_socket_bind()
disable_click_echo()

global actual_port
for port in range(DEFAULT_MIN_HTTP_PORT, DEFAULT_MAX_HTTP_PORT):
    logger.info('Starting mediator on %s:%s...',
                DEFAULT_HTTP_IFACE, port)
    actual_port = port
    try:
        app.run(DEFAULT_HTTP_IFACE, port, debug=False, threaded=False)
        logger.info('Exiting mediator...')
        break
    except OSError as e:
        logger.info('Cannot bind on port %s: %s', port, e)
    except BrokenPipeError:
        signal_pipe

else:
    logger.error(
        'No TCP ports available for bind in range from %s to %s',
        DEFAULT_MIN_HTTP_PORT, DEFAULT_MAX_HTTP_PORT)

I think this way is compatible with all OS.

How to Configure for Chrome on Windows

A) Changes on brotab_mediator.json: Path entry must have double \

Example: "path": "D:\\Python-3.7.6.0\\Envs\\BroTab\\Scripts\\bt_mediator.EXE",

B) Create a Registry Key

From https://developer.chrome.com/extensions/nativeMessaging#native-messaging-host-location

On Windows, the manifest file can be located anywhere in the file system. The application installer must create registry key HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application or HKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application, and set default value of that key to the full path to the manifest file. For example, using the following command: REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.my_company.my_application" /ve /t REG_SZ /d "C:\path\to\nmh-manifest.json" /for using the following .reg file: Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.my_company.my_application] @="C:\path\to\nmh-manifest.json"

In this case i've used : Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\brotab_mediator] @="[PathWhereManifestFileIs]\brotab_mediator.json"

Enable Logging on Chrome

Just a quick note if you want to see what's happenning on Chrome side...

From https://www.chromium.org/for-testers/enable-logging

To enable logging, launch Chrome with these command line flags:

--enable-logging=stderr --v=1 # Linux (newer instructions for Linux: here) --enable-logging --v=1 # Windows --enable-logging=stderr --v=1 > log.txt 2>&1 # Windows, seems to capture more output

Hope to get time to make it work on FF.

Edit : I cannot get any response from query command, in any of its variations. Always returns b'[]'

2020-02-12 17:40:00,818 19656 INFO       getting browser name
2020-02-12 17:40:00,818 19656 INFO       SENDING: {'name': 'get_browser'}
2020-02-12 17:40:00,819 19656 INFO       RECEIVED: b'"chrome/chromium"'
2020-02-12 17:40:03,751 19656 INFO       query info: eyJ1cmwiOiBbIio6Ly8qLmdvb2dsZS5jb20vKiJdfQ==
2020-02-12 17:40:03,752 19656 INFO       SENDING: {'name': 'query_tabs', 'query_info': 'eyJ1cmwiOiBbIio6Ly8qLmdvb2dsZS5jb20vKiJdfQ=='}
2020-02-12 17:40:03,755 19656 INFO       RECEIVED: b'[]'
2020-02-12 17:42:04,148 19656 INFO       getting browser name
2020-02-12 17:42:04,149 19656 INFO       SENDING: {'name': 'get_browser'}
2020-02-12 17:42:04,150 19656 INFO       RECEIVED: b'"chrome/chromium"'
2020-02-12 17:42:07,076 19656 INFO       query info: eyJ1cmwiOiBbIioiXX0=
2020-02-12 17:42:07,076 19656 INFO       SENDING: {'name': 'query_tabs', 'query_info': 'eyJ1cmwiOiBbIioiXX0='}
2020-02-12 17:42:07,077 19656 INFO       RECEIVED: b'[]'
2020-02-12 17:42:50,217 19656 INFO       getting browser name
2020-02-12 17:42:50,217 19656 INFO       SENDING: {'name': 'get_browser'}
2020-02-12 17:42:50,218 19656 INFO       RECEIVED: b'"chrome/chromium"'
2020-02-12 17:43:51,644 19656 INFO       getting browser name
2020-02-12 17:43:51,645 19656 INFO       SENDING: {'name': 'get_browser'}
2020-02-12 17:43:51,647 19656 INFO       RECEIVED: b'"chrome/chromium"'
2020-02-12 17:43:54,571 19656 INFO       query info: eyJ0aXRsZSI6ICIqIn0=
2020-02-12 17:43:54,572 19656 INFO       SENDING: {'name': 'query_tabs', 'query_info': 'eyJ0aXRsZSI6ICIqIn0='}
2020-02-12 17:43:54,575 19656 INFO       RECEIVED: b'[]'

Any clue?

naeloob commented 4 years ago

Changes to make Move work under Windows :

Changes on inout.py A) Add encoding utf-8 on save_tabs_to_file and load_tabs_from_file. I think this change is safe for any OS.

def save_tabs_to_file(tabs, filename):
    with open(filename, 'w', encoding='utf-8') as file_:
        file_.write('\n'.join(tabs))

def load_tabs_from_file(filename):
    with open(filename, encoding='utf-8') as file_:
        Lines = [line.strip() for line in file_.readlines()]
    if os.path.exists(filename):
        os.remove(filename)
    return Lines

B)

balta2ar commented 4 years ago

Thanks for the great and detailed write up! Your suggestions definitely need to be merged when I have a bit more time.

To enable logging, launch Chrome with these command line flags

That was and is a huge pain point for me. It was so inconvenient to check extension's logs in a browser given that I work mostly in command-line. I'll try that and I wish there were simple and reliable way to do the same in Firefox.

naeloob commented 4 years ago

Another change in api.py :

Just add an slash, in line

            words |= set(self._get(
                '/get_words/%s/?match_regex=%s&join_with=%s' % (tab_id, match_regex, join_with)
    def get_words(self, tab_ids, match_regex, join_with):
        words = set()
        match_regex = encode_query(match_regex)
        join_with = encode_query(join_with)

        for tab_id in tab_ids:
            prefix, _window_id, tab_id = tab_id.split('.')
            if prefix + '.' != self._prefix:
                continue

            logger.info(
                'SingleMediatorAPI: get_words: %s, match_regex: %s, join_with: %s',
                tab_id, match_regex, join_with)
            words |= set(self._get(
                '/get_words/%s/?match_regex=%s&join_with=%s' % (tab_id, match_regex, join_with)
            ).splitlines())

        if not tab_ids:
            words = set(self._get(
                '/get_words/?match_regex=%s&join_with=%s' % (match_regex, join_with)
            ).splitlines())

        return sorted(list(words))

Else Flask server makes a 308 permanent redirect to that url, that urlopen cannot handle.

naeloob commented 4 years ago

brotab_mediator.py

Added is_port_accepting_connections() from inout.py

def is_port_accepting_connections(port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(0.100)
    result = s.connect_ex(('127.0.0.1', port))
    s.close()
    return result == 0

Changed main() in order to check the port is not open

def main():
    #signal.signal(signal.SIGPIPE, signal_pipe)
    monkeypatch_socket_bind()
    disable_click_echo()

    global actual_port
    for port in range(DEFAULT_MIN_HTTP_PORT, DEFAULT_MAX_HTTP_PORT):
        logger.info('Starting mediator on %s:%s...',
                    DEFAULT_HTTP_IFACE, port)
        if is_port_accepting_connections(port):
            continue
        actual_port = port
        try:
            app.run(DEFAULT_HTTP_IFACE, port, debug=False, threaded=False)
            logger.info('Exiting mediator...')
            break
        except OSError as e:
            logger.info('Cannot bind on port %s: %s', port, e)
        except BrokenPipeError:
            signal_pipe

    else:
        logger.error(
            'No TCP ports available for bind in range from %s to %s',
            DEFAULT_MIN_HTTP_PORT, DEFAULT_MAX_HTTP_PORT)
naeloob commented 4 years ago

I have no results from any query, and the error message on log is : [13864:21284:0213/004303.367:INFO:CONSOLE(224)] "TypeError: Error in invocation of tabs.query(object queryInfo, function callback): No matching signature.", source: chrome-extension://mhpeahbikehnfkfnmopaigggliclhmnc/background.js (224)

Background.js

It's posible that query methods are wrong?

BrowserTabs Class

  query(queryInfo, onSuccess) {
    throw new Error('query is not implemented');
  } 

FirefoxTabs Class

  query(queryInfo, onSuccess, onFailure) {
    this._browser.tabs.query(queryInfo)
      .then(onSuccess, onFailure);
  }

ChromeTabs

 query(queryInfo, onSuccess, onFailure) {
    this._browser.tabs.query(queryInfo)
      .then(onSuccess, onFailure);
  }

BrowserTabs has 2 parameters, but FF and Chrome have 3.

And Chrome seem a copy/paste from firefox. Chrome query method has 2 parameters tabs.query(object queryInfo, function callback)

Edit: SOLVED!! I've changed query(queryInfo, onSuccess) to just two parameters in browsertabs, ff, and chrome classes.

naeloob commented 4 years ago

I've made a pull request in order to aggregate these things : https://github.com/balta2ar/brotab/pull/21

It lacks the changes on brotab_mediator.json (Path to bt_mediator.EXE entry must have double ) and the creation of the Registry Key.

balta2ar commented 4 years ago

It lacks the changes on brotab_mediator.json (Path to bt_mediator.EXE entry must have double ) and the creation of the Registry Key.

Added all your changes from the pull request and also implemented these two. Now Windows support should be much better.