Skip to content

Commit

Permalink
mediator: massive refactoring of mediator
Browse files Browse the repository at this point in the history
In this commit I shuffled around almost all parts of the mediator, and
most importantly, mediator now runs in a separate process. All this fuss
was due to the this deprecation warning:
https://werkzeug.palletsprojects.com/en/2.0.x/serving/#shutting-down-the-server

So I figured I should move to a new shutdown method. Well, it complicated
everything for no solid reason, if you ask me. But here we go, now we are doing
things "the right way".
  • Loading branch information
balta2ar committed Dec 28, 2021
1 parent 26b1787 commit daa0c57
Show file tree
Hide file tree
Showing 15 changed files with 746 additions and 518 deletions.
60 changes: 29 additions & 31 deletions brotab/api.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import io
import json
import logging
import socket
import sys
import time
import socket
import logging
import json
from traceback import print_exc
from urllib.error import URLError, HTTPError
from urllib.request import Request, urlopen
from urllib.parse import quote_plus
from functools import partial
from collections.abc import Mapping

from functools import partial
from http.client import RemoteDisconnected
from traceback import print_exc
from typing import List
from urllib.error import HTTPError
from urllib.error import URLError
from urllib.parse import quote_plus
from urllib.request import Request
from urllib.request import urlopen

from brotab.inout import edit_tabs_in_editor
from brotab.inout import MultiPartForm
from brotab.parallel import call_parallel
from brotab.inout import edit_tabs_in_editor
from brotab.operations import infer_delete_and_move_commands
from brotab.parallel import call_parallel
from brotab.tab import parse_tab_lines
from brotab.utils import encode_query


logger = logging.getLogger('brotab')

HTTP_TIMEOUT = 10.0 # 2 # 10.0
HTTP_TIMEOUT = 10.0
MAX_NUMBER_OF_TABS = 5000


Expand All @@ -35,6 +36,7 @@ class SingleMediatorAPI(object):
"""
This API is designed to work with a single mediator.
"""

def __init__(self, prefix, host='localhost', port=4625, startup_timeout=None):
self._prefix = '%s.' % prefix
self._host = host
Expand All @@ -53,6 +55,10 @@ def wait_for_startup(self, timeout_msec: int) -> bool:
time.sleep(0.050)
return False

@property
def browser(self) -> str:
return self._browser

@property
def ready(self):
return self._browser != '<ERROR>'
Expand All @@ -68,8 +74,8 @@ def prefix_tabs(self, tabs):
return list(map(self.prefix_tab, tabs))

def unprefix_tabs(self, tabs):
N = len(self._prefix)
return [tab[N:]
num = len(self._prefix)
return [tab[num:]
if tab.startswith(self._prefix)
else tab for tab in tabs]

Expand All @@ -86,29 +92,29 @@ def _get_pid(self):
"""Get process ID from the mediator."""
try:
return int(self._get('/get_pid'))
except (URLError, HTTPError, socket.timeout) as e:
except (URLError, HTTPError, socket.timeout, RemoteDisconnected) as e:
logger.info('_get_pid failed: %s', e)
return -1

def _get_browser(self):
"""Get browser name from the mediator."""
try:
return self._get('/get_browser')
except (URLError, HTTPError, socket.timeout) as e:
except (URLError, HTTPError, socket.timeout, RemoteDisconnected) as e:
logger.info('_get_browser failed: %s', e)
return '<ERROR>'

def close_tabs(self, args):
tabs = ','.join(tab_id for _prefix, _window_id,
tab_id in self._split_tabs(args))
tab_id in self._split_tabs(args))
return self._get('/close_tabs/%s' % tabs)

def activate_tab(self, args: List[str], focused: bool):
if len(args) == 0:
return

# args: ['a.1.2']
prefix, window_id, tab_id = args[0].split('.')
_prefix, _window_id, tab_id = args[0].split('.')
self._get('/activate_tab/%s%s' % (tab_id, '?focused=1' if focused else ''))

def get_active_tabs(self, args) -> List[str]:
Expand Down Expand Up @@ -152,9 +158,6 @@ def list_tabs(self, args):
result = self._get('/list_tabs')
lines = []
for line in result.splitlines()[:num_tabs]:
# for line in result.split('\n')[:num_tabs]:
# line = '%s%s' % (self._prefix, line)
# print(line)
lines.append(line)
return self.prefix_tabs(lines)

Expand Down Expand Up @@ -203,12 +206,12 @@ def get_words(self, tab_ids, match_regex, join_with):
'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)
'/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)
'/get_words?match_regex=%s&join_with=%s' % (match_regex, join_with)
).splitlines())

return sorted(list(words))
Expand All @@ -219,7 +222,7 @@ def get_text_or_html(self, command, args, delimiter_regex, replace_with):
num_tabs = int(args[0])

result = self._get(
'/%s/?delimiter_regex=%s&replace_with=%s' % (
'/%s?delimiter_regex=%s&replace_with=%s' % (
command,
encode_query(delimiter_regex),
encode_query(replace_with),
Expand Down Expand Up @@ -279,10 +282,6 @@ def ready_apis(self):
return [api for api in self._apis if api.ready]

def close_tabs(self, args):
# if len(args) == 0:
# print('Usage: brotab_client.py close_tabs <#tab ...>')
# return 2

for api in self._apis:
api.close_tabs(args)

Expand Down Expand Up @@ -373,7 +372,7 @@ def get_words(self, tab_ids, match_regex, join_with):
start = time.time()
words |= set(api.get_words(tab_ids, match_regex, join_with))
delta = time.time() - start
#print('DELTA', delta, file=sys.stderr)
# print('DELTA', delta, file=sys.stderr)
return sorted(list(words))

def _get_text_or_html(self, api, getter, args, delimiter_regex, replace_with):
Expand Down Expand Up @@ -407,4 +406,3 @@ def get_html(self, args, delimiter_regex, replace_with):
tabs.extend(self._get_text_or_html(api, api.get_html, args,
delimiter_regex, replace_with))
return tabs

20 changes: 11 additions & 9 deletions brotab/inout.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import io
import mimetypes
import os
import sys
import uuid
import select
import socket
import sys
import tempfile
import mimetypes
import uuid
from subprocess import CalledProcessError
from subprocess import check_call
from tempfile import NamedTemporaryFile
from subprocess import check_call, CalledProcessError
from typing import Iterable

from brotab.platform import get_editor
Expand Down Expand Up @@ -35,11 +36,11 @@ def get_mediator_ports() -> Iterable:
return range(MIN_MEDIATOR_PORT, MAX_MEDIATOR_PORT)


def get_free_tcp_port(start=1025, end=65536, host='127.0.0.1'):
def get_available_tcp_port(start=1025, end=65536, host='127.0.0.1'):
for port in range(start, end):
if not is_port_accepting_connections(port, host):
return port
return RuntimeError('Cannot find free port in range %d:%d' % (start, end))
return RuntimeError('Cannot find available port in range %d:%d' % (start, end))


def is_port_accepting_connections(port, host='127.0.0.1'):
Expand Down Expand Up @@ -82,6 +83,7 @@ def edit_tabs_in_editor(tabs_before):
except CalledProcessError:
return None


def read_stdin():
if select.select([sys.stdin, ], [], [], 1.0)[0]:
return sys.stdin.read()
Expand Down Expand Up @@ -118,8 +120,8 @@ def add_file(self, fieldname, filename, fileHandle,
body = fileHandle.read()
if mimetype is None:
mimetype = (
mimetypes.guess_type(filename)[0] or
'application/octet-stream'
mimetypes.guess_type(filename)[0] or
'application/octet-stream'
)
self.files.append((fieldname, filename, mimetype, body))
return
Expand All @@ -133,7 +135,7 @@ def _form_data(name):
def _attached_file(name, filename):
return ('Content-Disposition: file; '
'name="{}"; filename="{}"\r\n').format(
name, filename).encode('utf-8')
name, filename).encode('utf-8')

@staticmethod
def _content_type(ct):
Expand Down
Loading

0 comments on commit daa0c57

Please sign in to comment.