summaryrefslogtreecommitdiff
path: root/client/shell.py
blob: 07b74508f200c1f3b2f93caeece65531df42b206 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
'''
    Handles the running of commands in
    the terminal. Timeouts, encoding &
    returning the correct data.

    Verified: 2021 February 6
    * Follows PEP8
    * Tested Platforms
        * Windows 10
    * Third Party Modules
        * psutil
'''

from client.state import ClientStatic
from client.error import ClientError
from shared.state import Static
from shared.error import Error
from shared.data import Data

import subprocess
import threading
import psutil
import os


class Shell:

    @staticmethod
    @ClientError.general
    def run(data, disable_stderr=False):
        if Static.WINDOWS:
            data = f'chcp {ClientStatic.CODE_PAGE} > nul && {data}'

        process_timer = threading.Timer(ClientStatic.TIMEOUT,
                                        Shell.__timeout)
        process_timer.start()

        process = subprocess.run(data, shell=True,
                                 encoding=Static.ENCODING,
                                 errors=Static.ERRORS,
                                 stdin=subprocess.DEVNULL,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)

        if process_timer.is_alive():
            process_timer.cancel()

            if disable_stderr:
                if process.returncode == 0:
                    return process.stdout.strip('\r\n')
                else:
                    return ClientStatic.DEFAULT
            else:
                return Data.parse(''.join((
                    process.stdout,
                    process.stderr
                )).strip('\r\n'), raw=True)
        else:
            raise TimeoutError('Timeout Awaiting Shell Response')

    @staticmethod
    @Error.quiet
    def __timeout():
        # NOTE : Works well, only lists the
        # cmd.exe & the subprocess, for example
        # vim.exe. Does not disturb the other
        # threads the client is running
        for child in psutil.Process(
                os.getpid()).children(True):
            child.kill()