Ported to Python 3

This commit is contained in:
emdee 2022-10-06 13:44:35 +00:00
parent 87638269c8
commit fc4548bbe5
10 changed files with 144 additions and 56 deletions

View File

@ -84,3 +84,7 @@ Users with write access can send files to bot.
Users with delete access can delete and rename files. Users with delete access can delete and rename files.
Example of settings is [here](/settings.json) Example of settings is [here](/settings.json)
## Hard Fork
https://git.plastiras.org/emdee/filebot

View File

@ -1,10 +1,19 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import random import random
global LOG
import logging
LOG = logging.getLogger(__name__)
iNUM_NODES = 6
class Node(object): class Node(object):
def __init__(self, ip, port, tox_key, rand): def __init__(self, ip, port, tox_key, rand=0):
self._ip, self._port, self._tox_key, self.rand = ip, port, tox_key, rand self._ip = ip
self._port = port
self._tox_key = tox_key
self.rand = rand
def get_data(self): def get_data(self):
return self._ip, self._port, self._tox_key return self._ip, self._port, self._tox_key
@ -12,6 +21,16 @@ class Node(object):
def node_generator(): def node_generator():
nodes = [] nodes = []
try:
from wrapper_tests.support_testing import generate_nodes
all = generate_nodes()
random.shuffle(all)
for elt in all[:iNUM_NODES]:
nodes.append(Node(*elt))
return nodes
except Exception as e:
LOG.warn(e)
# drop through
ips = [ ips = [
"144.76.60.215", "23.226.230.47", "195.154.119.113", "biribiri.org", "144.76.60.215", "23.226.230.47", "195.154.119.113", "biribiri.org",
"46.38.239.179", "178.62.250.138", "130.133.110.14", "104.167.101.29", "46.38.239.179", "178.62.250.138", "130.133.110.14", "104.167.101.29",
@ -76,8 +95,9 @@ def node_generator():
"5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802", "5625A62618CB4FCA70E147A71B29695F38CC65FF0CBD68AD46254585BE564802",
"31910C0497D347FF160D6F3A6C0E317BAFA71E8E03BC4CBB2A185C9D4FB8B31E" "31910C0497D347FF160D6F3A6C0E317BAFA71E8E03BC4CBB2A185C9D4FB8B31E"
] ]
for i in xrange(len(ips)): for i in range(len(ips)):
nodes.append(Node(ips[i], ports[i], ids[i], random.randint(0, 1000000))) nodes.append(Node(ips[i], ports[i], ids[i]) )
arr = sorted(nodes, key=lambda x: x.rand)[:4] arr = sorted(nodes)
for elem in arr: random.shuffle(arr)
for elem in arr[:iNUM_NODES]:
yield elem.get_data() yield elem.get_data()

53
bot.py
View File

@ -1,12 +1,16 @@
from tox import Tox # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
from wrapper.tox import Tox
import os import os
from settings import * from settings import *
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from ctypes import * from ctypes import *
from util import Singleton, folder_size from util import Singleton, folder_size
from file_transfers import * from file_transfers import *
from collections import defaultdict from collections import defaultdict
global LOG
import logging
LOG = logging.getLogger(__name__)
class Bot(Singleton): class Bot(Singleton):
@ -174,10 +178,10 @@ class Bot(Singleton):
fl = ' '.join(message.split(' ')[2:]) fl = ' '.join(message.split(' ')[2:])
try: try:
num = self._tox.friend_by_public_key(message.split(' ')[1][:TOX_PUBLIC_KEY_SIZE * 2]) num = self._tox.friend_by_public_key(message.split(' ')[1][:TOX_PUBLIC_KEY_SIZE * 2])
print num LOG.debug(num)
self.send_file(settings['folder'] + '/' + fl, num) self.send_file(settings['folder'] + '/' + fl, num)
except Exception as ex: except Exception as ex:
print ex LOG.warn(ex)
self.send_message(friend_num, 'Friend not found'.encode('utf-8')) self.send_message(friend_num, 'Friend not found'.encode('utf-8'))
else: else:
fl = ' '.join(message.split(' ')[2:]) fl = ' '.join(message.split(' ')[2:])
@ -289,7 +293,7 @@ class Bot(Singleton):
:param tox_id: tox id of contact :param tox_id: tox id of contact
:param message: message :param message: message
""" """
print 'Friend request:', message LOG.info('Friend request:' +message)
self._tox.friend_add_norequest(tox_id) self._tox.friend_add_norequest(tox_id)
settings = Settings.get_instance() settings = Settings.get_instance()
# give friend default rights # give friend default rights
@ -395,16 +399,28 @@ def tox_factory(data=None, settings=None):
:return: new tox instance :return: new tox instance
""" """
if settings is None: if settings is None:
settings = { if os.getenv('socks_proxy') != '':
'ipv6_enabled': True, settings = {
'udp_enabled': True, 'ipv6_enabled': False,
'proxy_type': 0, 'udp_enabled': False,
'proxy_host': '0', 'proxy_type': 2,
'proxy_port': 0, 'proxy_host': b'127.0.0.1',
'start_port': 0, 'proxy_port': 9050,
'end_port': 0, 'start_port': 0,
'tcp_port': 0 'end_port': 0,
} 'tcp_port': 0
}
else:
settings = {
'ipv6_enabled': True,
'udp_enabled': True,
'proxy_type': 0,
'proxy_host': '0',
'proxy_port': 0,
'start_port': 0,
'end_port': 0,
'tcp_port': 0
}
tox_options = Tox.options_new() tox_options = Tox.options_new()
tox_options.contents.udp_enabled = settings['udp_enabled'] tox_options.contents.udp_enabled = settings['udp_enabled']
tox_options.contents.proxy_type = settings['proxy_type'] tox_options.contents.proxy_type = settings['proxy_type']
@ -421,4 +437,11 @@ def tox_factory(data=None, settings=None):
tox_options.contents.savedata_type = TOX_SAVEDATA_TYPE['NONE'] tox_options.contents.savedata_type = TOX_SAVEDATA_TYPE['NONE']
tox_options.contents.savedata_data = None tox_options.contents.savedata_data = None
tox_options.contents.savedata_length = 0 tox_options.contents.savedata_length = 0
# overrides
tox_options.contents.local_discovery_enabled = False
tox_options.contents.ipv6_enabled = False
tox_options.contents.hole_punching_enabled = False
LOG.debug("wrapper.tox.Tox settings: " +repr(settings))
return Tox(tox_options) return Tox(tox_options)

View File

@ -1,8 +1,12 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
from settings import Settings from settings import Settings
from bot import Bot from bot import Bot
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
from tox import bin_to_string from wrapper.tox import bin_to_string
global LOG
import logging
LOG = logging.getLogger(__name__)
# ----------------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------------
# Callbacks - current user # Callbacks - current user
@ -14,7 +18,7 @@ def self_connection_status():
Current user changed connection status (offline, UDP, TCP) Current user changed connection status (offline, UDP, TCP)
""" """
def wrapped(tox, connection, user_data): def wrapped(tox, connection, user_data):
print 'Connection status: ', str(connection) LOG.debug('Connection status: ' + str(connection))
return wrapped return wrapped
@ -27,7 +31,7 @@ def friend_connection_status(tox, friend_num, new_status, user_data):
""" """
Check friend's connection status (offline, udp, tcp) Check friend's connection status (offline, udp, tcp)
""" """
print "Friend #{} connected! Friend's status: {}".format(friend_num, new_status) LOG.info("Friend #{} connected! Friend's status: {}".format(friend_num, new_status))
def friend_message(): def friend_message():
@ -35,7 +39,7 @@ def friend_message():
New message from friend New message from friend
""" """
def wrapped(tox, friend_number, message_type, message, size, user_data): def wrapped(tox, friend_number, message_type, message, size, user_data):
print message.decode('utf-8') LOG.info(message.decode('utf-8'))
Bot.get_instance().new_message(friend_number, message.decode('utf-8')) Bot.get_instance().new_message(friend_number, message.decode('utf-8'))
# parse message # parse message
return wrapped return wrapped
@ -62,7 +66,7 @@ def tox_file_recv(tox_link):
def wrapped(tox, friend_number, file_number, file_type, size, file_name, file_name_size, user_data): def wrapped(tox, friend_number, file_number, file_type, size, file_name, file_name_size, user_data):
profile = Bot.get_instance() profile = Bot.get_instance()
if file_type == TOX_FILE_KIND['DATA']: if file_type == TOX_FILE_KIND['DATA']:
print 'file' LOG.info('file')
file_name = unicode(file_name[:file_name_size].decode('utf-8')) file_name = unicode(file_name[:file_name_size].decode('utf-8'))
profile.incoming_file_transfer(friend_number, file_number, size, file_name) profile.incoming_file_transfer(friend_number, file_number, size, file_name)
else: # AVATAR else: # AVATAR
@ -109,13 +113,13 @@ def init_callbacks(tox):
Initialization of all callbacks. Initialization of all callbacks.
:param tox: tox instance :param tox: tox instance
""" """
tox.callback_self_connection_status(self_connection_status(), 0) tox.callback_self_connection_status(self_connection_status())
tox.callback_friend_message(friend_message(), 0) tox.callback_friend_message(friend_message())
tox.callback_friend_connection_status(friend_connection_status, 0) tox.callback_friend_connection_status(friend_connection_status)
tox.callback_friend_request(friend_request, 0) tox.callback_friend_request(friend_request)
tox.callback_file_recv(tox_file_recv(tox), 0) tox.callback_file_recv(tox_file_recv(tox))
tox.callback_file_recv_chunk(file_recv_chunk, 0) tox.callback_file_recv_chunk(file_recv_chunk)
tox.callback_file_chunk_request(file_chunk_request, 0) tox.callback_file_chunk_request(file_chunk_request)
tox.callback_file_recv_control(file_recv_control, 0) tox.callback_file_recv_control(file_recv_control)

View File

@ -1,8 +1,9 @@
from toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
from wrapper.toxcore_enums_and_consts import TOX_FILE_KIND, TOX_FILE_CONTROL
from os.path import basename, getsize from os.path import basename, getsize
from os import remove from os import remove
from time import time from time import time
from tox import Tox from wrapper.tox import Tox
TOX_FILE_TRANSFER_STATE = { TOX_FILE_TRANSFER_STATE = {

50
main.py
View File

@ -1,9 +1,40 @@
from bootstrap import node_generator # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
from bot import *
from callbacks import init_callbacks """
help - list of commands\n
rights - get access rights\n
files - show list of files (get access)\n
id - get bot's id (get access)\n
share <ToxID> <file_name> - send file to friend (get access)\n
share --all <file_name> - send file to all friends (get access)\n
size <file_name> - get size of file (get access)\n
get <file_name> - get file with specified filename (get access)\n
get --all - get all files (get access)\n
stats - show statistics (write access)\n
del <file_name> - remove file with specified filename (delete access)\n
rename <file_name> --new <new_file_name> - rename file (delete access)\n
user <ToxID> <rights> - new rights (example: rwdm) for user (masters only)\n
status <new_status> - new status message (masters only)\n
name <new_name> - new name (masters only)\n
message <ToxID> <message_text> - send message to friend (masters only)\n
message --all <message_text> - send message to all friends (masters only)\n
stop - stop bot (masters only)\n
fsize <folder_size_in_MB> - set folder size in MB (masters only)\n
Users with write access can send files to bot.
"""
import time import time
import sys import sys
from bootstrap import node_generator
from bot import Bot, tox_factory, ProfileHelper
from callbacks import init_callbacks
from settings import Settings
global LOG
import logging
logging.basicConfig(level=10)
LOG = logging.getLogger(__name__)
class FileBot(object): class FileBot(object):
@ -13,7 +44,7 @@ class FileBot(object):
self.stop = False self.stop = False
self.profile = None self.profile = None
self.path = path self.path = path
print 'FileBot v0.1.2' LOG.info('FileBot v0.1.2+')
def main(self): def main(self):
self.tox = tox_factory(ProfileHelper.open_profile(self.path)) self.tox = tox_factory(ProfileHelper.open_profile(self.path))
@ -23,7 +54,7 @@ class FileBot(object):
self.tox.bootstrap(*data) self.tox.bootstrap(*data)
settings = Settings() settings = Settings()
self.profile = Bot(self.tox) self.profile = Bot(self.tox)
print 'Iterate' LOG.debug('Iterate')
try: try:
while not self.stop: while not self.stop:
self.tox.iterate() self.tox.iterate()
@ -36,10 +67,9 @@ class FileBot(object):
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) > 1: if len(sys.argv) <= 1:
path = sys.argv[1]
bot = FileBot(path)
bot.main()
else:
raise IOError('Path to save file not found') raise IOError('Path to save file not found')
path = sys.argv[1]
bot = FileBot(path)
bot.main()

View File

@ -1,24 +1,28 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import json import json
import os import os
import locale import locale
from util import Singleton, curr_directory from util import Singleton, curr_directory
from toxcore_enums_and_consts import * from wrapper.toxcore_enums_and_consts import *
global LOG
import logging
LOG = logging.getLogger(__name__)
class Settings(Singleton, dict): class Settings(Singleton, dict):
def __init__(self): def __init__(self):
self.path = curr_directory() + '/settings.json' self.path = os.path.join(curr_directory(), 'settings.json')
if os.path.isfile(self.path): if os.path.isfile(self.path):
with open(self.path) as fl: with open(self.path) as fl:
data = fl.read() data = fl.read()
super(self.__class__, self).__init__(json.loads(data)) super(self.__class__, self).__init__(json.loads(data))
else: else:
super(self.__class__, self).__init__(Settings.get_default_settings()) super(self.__class__, self).__init__(Settings.get_default_settings())
self['read'] = map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['read'])) self['read'] = list(map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['read'])))
self['write'] = map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['write'])) self['write'] = list(map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['write'])))
self['delete'] = map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['delete'])) self['delete'] = list(map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['delete'])))
self['master'] = map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['master'])) self['master'] = list(map(lambda x: x[:TOX_PUBLIC_KEY_SIZE * 2], set(self['master'])))
if self['folder'][-1] == '/' or self['folder'][-1] == '\\': if self['folder'][-1] == '/' or self['folder'][-1] == '\\':
self['folder'] = self['folder'][:-1] self['folder'] = self['folder'][:-1]
self.save() self.save()
@ -31,12 +35,13 @@ class Settings(Singleton, dict):
'delete': [], 'delete': [],
'master': [], 'master': [],
'folder': curr_directory(), 'folder': curr_directory(),
'folder_save': curr_directory(),
'auto_rights': 'r', 'auto_rights': 'r',
'size': 500 'size': 500
} }
def save(self): def save(self):
print 'Saving' LOG.debug('Saving')
text = json.dumps(self) text = json.dumps(self)
with open(self.path, 'w') as fl: with open(self.path, 'w') as fl:
fl.write(text) fl.write(text)
@ -49,7 +54,6 @@ class ProfileHelper(object):
@staticmethod @staticmethod
def open_profile(path): def open_profile(path):
path = path.decode(locale.getpreferredencoding())
ProfileHelper._path = path ProfileHelper._path = path
with open(ProfileHelper._path, 'rb') as fl: with open(ProfileHelper._path, 'rb') as fl:
data = fl.read() data = fl.read()

View File

View File

@ -1,3 +1,5 @@
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
import os import os
@ -23,7 +25,7 @@ class Singleton(object):
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'): if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance return cls._instance
@classmethod @classmethod