summaryrefslogtreecommitdiff
path: root/day4/task4/client.py
blob: bc4a40f13dbf9c10e599f1b88427b5eddd59d3b4 (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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import socket
from time import sleep
import struct
import json
import shelve

try:
    from tqdm import tqdm
    TQDM = True
except ImportError:
    print('Для вывода прогресса загрузки файлов установите библиотеку tqdm')
    TQDM = False


def pack_data(data):
    encoded = data.encode()
    return struct.pack('I', len(encoded)) + encoded


def handle_input(data):
    cmd, args = data.split(' ', maxsplit=1)

    if cmd == 'get':
        make_get_request(args)

    elif cmd == 'cp':
        paths = args.split()
        if len(paths) != 2:
            raise ValueError('Неверное количество путей в параметрах.')

        src, dest = paths

        # Если файл не присутствует в БД, то предварительно его загружаем
        status = 0
        if src not in db:
            status = make_get_request(src)

        if status == 0:
            with open(dest, 'wb') as f:
                f.write(db[src])

    else:
        raise ValueError('Команда не распознана')


def make_get_request(path):
    packet = pack_data(json.dumps({'method': 'get', 'path': path}))
    sock.sendall(packet)
    response = get_response()
    return handle_response(response)


def parse_response(data):
    return json.loads(data.decode())


def get_response():
    buffer = b''
    while len(buffer) < DATATYPE_SIZE:
        data = sock.recv(DATATYPE_SIZE - len(buffer))
        if not data:
            raise ConnectionError('Connection was closed')

        buffer += data

    size_packed, buffer = buffer[:DATATYPE_SIZE], buffer[DATATYPE_SIZE:]
    if not size_packed:
        raise ConnectionError('Connection was closed')

    (size,) = struct.unpack('I', size_packed)
    data = sock.recv(size - len(buffer))
    return parse_response(buffer + data)


def download_file(filesize):
    data = b''

    if TQDM:
        for count in tqdm(range(0, filesize, CHUNK_SIZE)):
            (size,) = struct.unpack('I', sock.recv(DATATYPE_SIZE))
            data += sock.recv(size)
    else:
        count = 0
        while count < filesize:
            (size,) = struct.unpack('I', sock.recv(DATATYPE_SIZE))
            data += sock.recv(size)
            count += size

    return data


def handle_response(data):
    if data['status'] == 0:
        print(f'Загружаем файл размером {data["size"]} байт...')
        file_data = download_file(data['size'])
        db[data['path']] = file_data
        print('Загрузка завершена')

    elif data['status'] == 1:
        print(data['reason'])

    elif data['status'] == 2:
        print('Неизвестная ошибка:')
        print(data['reason'])

    return data['status']


def try_connect():
    cnt = 0
    sock = socket.socket()
    while cnt < 10:
        try:
            cnt += 1
            sock.connect(ADDR)

        except ConnectionRefusedError:
            print('Не удалось подключиться к серверу. Следующая попытка через 3 секунды...')
            sleep(3)

        else:
            return sock

    else:
        print('Не удалось подключиться к серверу через 10 попыток.\nОстанавливаемся...')
        sock.close()
        return


HOST, PORT = ADDR = 'localhost', 6000
DATATYPE_SIZE = 4  # int
CHUNK_SIZE = 4096000

sock = try_connect()
if sock is None:
    quit()


db = shelve.open('backdoor.db')

while True:
    try:
        data = input('Введите команду:\n')
        handle_input(data)

    except KeyboardInterrupt:
        break

sock.close()