Esempio n. 1
0
async def display(ic, idx):
    field = ic.md.display_fields[idx]
    if 'fn' in field:
        source = display_fn(ic, {'fname': 'pprint', 'args': [field['fn']]})
    elif 'path' in field:
        source = display_fn(ic, {'fname': 'pprint', 'args': [field['path']]})

    async with core.streamcontext(source) as streamer:
        async for item in streamer:
            yield {'type': 'display', 'id': idx, 'val': item}
Esempio n. 2
0
async def display_fn(ic, field):
    try:
        m = getattr(fn, field['fname'])
        fnc = getattr(m, field['fname'])
        source = fnc(ic, field['args'])
    except AttributeError:
        source = docker(
            ic, [pathlib.Path("/lib") / field['fname'].replace('.', '/')] +
            field['args'])

    async with core.streamcontext(source) as streamer:
        async for item in streamer:
            yield item
Esempio n. 3
0
async def input(ic, name):
    field = ic.md.input_fields[name]

    owner = ic.user
    restart = field['can_read']

    while restart:
        restart = False
        src = [await arg_stream(ic, owner, pathlib.Path(field['name']))]

        if 'owner' in field['args']:
            src.append(await arg_stream(ic, ic.user, field['args']['owner']))

        s = stream.ziplatest(*src, partial=False)
        last = None

        async with core.streamcontext(s) as streamer:
            async for i in streamer:
                if 'owner' in field['args']:
                    if i[1] is None:
                        continue

                    o = i[1]['val']
                    if o.pk != owner.pk:
                        owner = o
                        restart = True
                        break

                out = dict(type='input', id=field['name'], disabled=True)
                out['owner'] = None if ic.user == owner else owner.username
                out['val'] = '' if i[0] is None or i[0]['val'] is None else str(
                    i[0]['val'])
                out['disabled'] = not (field['can_write'] is True or
                                       (field['can_write'] is None
                                        and out['owner'] is None))

                if last == out:
                    continue
                last = out

                if field['args']['type'] in ['file', 'files', 'select-user']:
                    out['val'] = None

                if i[0] is not None and field['args']['type'] != i[0]['type']:
                    logger.warning(
                        f"field type error: {field['args']['type']} != {i[0]['type']}"
                    )

                yield out
Esempio n. 4
0
async def docker(ic, args):
    if len(args) < 1:
        yield None
        return

    if not isinstance(args[0], pathlib.Path):
        yield ('err', "⚠ wrong first argument format ⚠")
        return

    docker_path = pathlib.Path(os.path.normpath(ic.path / args[0]))

    dapi = None
    try:
        dapi = aiodocker.Docker()
        con = await get_container(dapi, docker_path, ic.user)
        if con is None:
            return

        logger.info(f"{con['id'][:12]}: created")

        ain = dict()
        aout = dict()
        for n, arg in enumerate(args[1:]):
            ain[n + 1] = stream_enum(
                n + 1, await my_stream.arg_stream(ic, ic.user, arg))

        ws = await con.websocket(stdin=True,
                                 stdout=True,
                                 stderr=True,
                                 stream=True)
        await con.start()

        logger.debug(f"{con['id'][:12]}: started")

        msgs_n = 0
        msgs_ts = time.time()

        try:
            restart = True
            while restart:
                restart = False

                if ain:
                    s = stream.merge(*list(ain.values()), websocket_reader(ws))
                else:
                    s = stream.merge(websocket_reader(ws))

                    # if input is empty, send empty message to container
                    logger.debug(f"{con['id'][:12]}: < []")
                    await ws.send_str(json.dumps(list()) + "\n")

                out = list()
                async with core.streamcontext(s) as streamer:
                    async for item in streamer:
                        if item[0] == 'ws':
                            logger.debug(
                                f"{con['id'][:12]}: > {item[1][:120]}")

                            msgs_n += 1
                            tdiff = time.time() - msgs_ts

                            if tdiff > 20 and msgs_n > 1000 and msgs_n / tdiff > 20:
                                logger.info(
                                    f"{con['id'][:12]}: receiving too much messages {msgs_n} in {tdiff}s"
                                )
                                yield {
                                    'type':
                                    'error',
                                    'val':
                                    f"receiving too much messages {msgs_n} in {tdiff}s"
                                }
                                break

                            m = wi_native_re.match(item[1])
                            if m:
                                if m.group(1) == 'clear':
                                    out = list()
                                    yield {'type': None, 'val': ""}

                                elif m.group(1).startswith('progress'):
                                    yield {
                                        'type':
                                        'html',
                                        'val':
                                        '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" style="width: 50%"></div></div>'
                                    }

                                else:
                                    try:
                                        msg = json.loads(m.group(1))
                                        if msg.get('type') in ['getval']:
                                            mid = msg.get('id')
                                            mval = msg.get('val')
                                            muser = msg.get('user')
                                            if muser is None:
                                                muser = ic.user.pk

                                            if mid is None or mval is None:
                                                logger.warning(
                                                    f"{con['id'][:12]}: getval: broken msg: > {item[1][:120]}"
                                                )
                                                continue

                                            if mid in ain:
                                                continue

                                            try:
                                                u = User.objects.get(pk=muser)
                                            except User.DoesNotExist:
                                                logger.warning(
                                                    f"{con['id'][:12]}: getval: unknown user {muser}"
                                                )
                                                continue

                                            arg = pathlib.Path(mval)
                                            ain[mid] = stream_enum(
                                                mid, await
                                                my_stream.arg_stream(
                                                    ic, u, arg))

                                            restart = True
                                            break
                                        elif msg['type'] in ['error']:
                                            yield msg
                                            break
                                        else:
                                            yield msg
                                    except json.JSONDecodeError as e:
                                        logger.warning(
                                            f"{con['id'][:12]}: broken msg: {e!s}"
                                        )
                                        continue

                            else:
                                out.append(item[1])
                                yield {'type': 'stdout', 'val': "\n".join(out)}

                        elif item[0] == 'err':
                            logger.debug(f"{con['id'][:12]}: !! " +
                                         ' '.join(str(item[1]).split())[:120])
                            yield {'type': 'error', 'val': item[1]}
                            break

                        else:
                            await send_item(ws, con, aout, item)

        except GeneratorExit:
            pass

        finally:
            logger.debug(f"{con['id'][:12]}: delete")

            try:
                await con.kill()
                await con.delete()
                pass
            except Exception:
                pass

            ws.close()

    except MyException as e:
        yield {'type': 'error', 'val': f"⚠ {e!s} ⚠"}
    except aiodocker.exceptions.DockerError as e:
        yield {'type': 'error', 'val': f"⚠ {e!s} ⚠"}
    except Exception as e:
        logger.exception(e)
        yield {'type': 'error', 'val': f"⚠ {e!s} ⚠"}

    finally:
        if dapi:
            await dapi.close()
Esempio n. 5
0
async def stream_enum(n, s):
    async with core.streamcontext(s) as streamer:
        async for i in streamer:
            yield (n, i)
Esempio n. 6
0
async def html_escape(source, user, path):
    async with core.streamcontext(source) as streamer:
        async for item in streamer:
            s = " ".join([str(x) for x in item if x is not None])
            yield html.escape(s).replace('\n', "<br />")
Esempio n. 7
0
async def pprint(ic, args):
    a = [await my_stream.arg_stream(ic, ic.user, arg) for arg in args]
    source = stream.ziplatest(*a, partial=False)

    async with core.streamcontext(source) as streamer:
        async for item in streamer:
            keys = list()
            vals = dict()
            info = list()

            for i, val in enumerate(item):
                if val is None:
                    continue

                if val.get('pk') is not None:
                    info.append(await get_history(val['pk']))

                if val['type'] is None:
                    pass

                elif val['type'] in ['html']:
                    if None not in keys:
                        keys.insert(0, None)
                        vals[None] = [None] * len(item)

                    vals[None][i] = val['val']

                elif val['type'] in [
                        'int', 'float', 'str', 'text', 'textarea', 'files',
                        'stdout', 'error'
                ]:
                    if None not in keys:
                        keys.insert(0, None)
                        vals[None] = [None] * len(item)

                    vals[None][i] = render_to_string(
                        f"wiki/plugins/inputs/pprint.html", context=val)

                elif val['type'] == 'user-list':
                    for u, v in val['val'].items():
                        if u not in keys:
                            keys.append(u)
                            vals[u] = [None] * len(item)

                        vals[u][i] = render_to_string(
                            f"wiki/plugins/inputs/pprint.html", context=v)

                else:
                    logger.error(val)

            if len(keys) == 0:
                yield None
                continue

            if len(keys) == 1 and keys[0] is None:
                html = " ".join(vals[keys[0]])

            else:
                html = "<table>"

                for k in keys:
                    html += "<tr><th>"
                    if k is None:
                        html += "&nbsp;"
                    elif isinstance(k, User):
                        html += f"{k.first_name} {k.last_name}"
                    else:
                        html += str(k)
                    html += "</th>"

                    for v in vals[k]:
                        html += f"<td>{v!s}</td>"

                    html += "</tr>"
                html += "</table>"

            if info:
                html = render_to_string("wiki/plugins/inputs/pprint_full.html",
                                        context={
                                            'html': html,
                                            'info': "".join(info)
                                        })

            yield {'type': 'html', 'val': html}
Esempio n. 8
0
async def get(ic, args):
    if len(args) < 2:
        yield {
            'type': 'error',
            'val': "⚠ get() requires at least 2 arguments ⚠"
        }
        return

    if not isinstance(args[0], pathlib.Path):
        yield {'type': 'error', 'val': "⚠ get() first argument must be path ⚠"}
        return

    path = misc.normpath(ic, args[0])
    md = await misc.get_markdown_factory().get_markdown(path.parent, ic.user)
    if md is None:
        yield {
            'type': 'error',
            'val': f"⚠ get() article {path.parent} does not exist ⚠"
        }
        return

    field = md.input_fields.get(path.name)
    if field is None:
        yield {
            'type': 'error',
            'val': f"⚠ get() article {path.name} does not exist ⚠"
        }

    q = Q(article=md.article) & Q(name=field['name'])
    if field['can_write'] in [False, None]:
        q &= Q(owner=ic.user)

    users = set()

    while True:
        src = [my_stream.read_field(ic, x, path) for x in users]
        src += [await my_stream.arg_stream(ic, ic.user, x) for x in args[1:]]
        if len(users) == 0:
            src += [my_stream.read_field(ic, ic.user, path)]

        s = stream.ziplatest(*src, partial=False)
        async with core.streamcontext(s) as streamer:
            async for i in streamer:
                users_new, is_list = await db_get_input_users(
                    md, field, q, (i[len(users):])[:len(args[1:])])
                if users_new is None:
                    continue

                if set([u.pk for u in users]) != set([u.pk
                                                      for u in users_new]):
                    users = users_new
                    break

                if is_list:
                    yield {
                        'type':
                        'user-list',
                        'val':
                        dict(zip([u.username for u in users], i[:len(users)])),
                    }
                elif len(users) > 0:
                    yield i[0]
                else:
                    yield {'type': 'None', 'val': None}

            else:
                return