update
This commit is contained in:
parent
3ce822fc27
commit
7cebe9cd9f
12 changed files with 182 additions and 2441 deletions
|
@ -4,4 +4,5 @@ find * -name \*.py | xargs grep -l '[ ]*$' | xargs sed -i -e 's/[ ]*$//'
|
||||||
rsync "$@" -vax --include \*.py \
|
rsync "$@" -vax --include \*.py \
|
||||||
--exclude Toxygen.egg-info --exclude build \
|
--exclude Toxygen.egg-info --exclude build \
|
||||||
--exclude \*.pyc --exclude .pyl\* --exclude \*~ \
|
--exclude \*.pyc --exclude .pyl\* --exclude \*~ \
|
||||||
|
--exclude __pycache__ --exclude \*.egg-info --exclude \*.new \
|
||||||
./ ../toxygen.git/|grep -v /$
|
./ ../toxygen.git/|grep -v /$
|
||||||
|
|
53
pyproject.toml
Normal file
53
pyproject.toml
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
[project]
|
||||||
|
name = "toxygen"
|
||||||
|
description = "examples of using stem"
|
||||||
|
authors = [{ name = "emdee", email = "emdee@spm.plastiras.org" } ]
|
||||||
|
requires-python = ">=3.7"
|
||||||
|
keywords = ["stem", "python3", "tox"]
|
||||||
|
classifiers = [
|
||||||
|
# How mature is this project? Common values are
|
||||||
|
# 3 - Alpha
|
||||||
|
# 4 - Beta
|
||||||
|
# 5 - Production/Stable
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
|
||||||
|
# Indicate who your project is intended for
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
|
||||||
|
# Specify the Python versions you support here.
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"License :: OSI Approved",
|
||||||
|
"Operating System :: POSIX :: BSD :: FreeBSD",
|
||||||
|
"Operating System :: POSIX :: Linux",
|
||||||
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
|
]
|
||||||
|
#
|
||||||
|
dynamic = ["version", "readme", "dependencies"] # cannot be dynamic ['license']
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
toxygen = "toxygen.__main__:main"
|
||||||
|
|
||||||
|
#[project.license]
|
||||||
|
#file = "LICENSE.md"
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
repository = "https://git.plastiras.org/emdee/toxygen"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools >= 61.0"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[tool.setuptools.dynamic]
|
||||||
|
version = {attr = "toxygen.app.__version__"}
|
||||||
|
readme = {file = ["README.md", "ToDo.txt"]}
|
||||||
|
dependencies = {file = ["requirements.txt"]}
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
packages = ["toxygen"]
|
|
@ -1,11 +1,16 @@
|
||||||
PyQt5
|
# the versions are the current ones tested - may work with earlier versions
|
||||||
PyAudio
|
# choose one of PyQt5 PyQt6 PySide2 PySide6
|
||||||
numpy
|
PyAudio >= 0.2.13
|
||||||
opencv-python
|
numpy >= 1.26.1
|
||||||
pydenticon
|
opencv_python >= 4.8.0
|
||||||
cv2
|
pydenticon >= 0.3.1
|
||||||
gevent
|
pillow >= 10.2.0
|
||||||
greenlet
|
gevent >= 23.9.1
|
||||||
pydenticon
|
greenlet >= 2.0.2
|
||||||
pyqtconsole
|
# this is optional
|
||||||
toxygen_wrapper
|
coloredlogs >= 15.0.1
|
||||||
|
# this is optional
|
||||||
|
# qtconsole >= 5.4.3
|
||||||
|
# this is not on pypi yet - get it from
|
||||||
|
# https://git.plastiras.org/emdee/toxygen_wrapper
|
||||||
|
# toxygen_wrapper == 1.0.0
|
||||||
|
|
54
setup.cfg
Normal file
54
setup.cfg
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
[metadata]
|
||||||
|
classifiers =
|
||||||
|
License :: OSI Approved
|
||||||
|
License :: OSI Approved :: BSD 1-clause
|
||||||
|
Intended Audience :: Web Developers
|
||||||
|
Operating System :: Microsoft :: Windows
|
||||||
|
Operating System :: POSIX :: BSD :: FreeBSD
|
||||||
|
Operating System :: POSIX :: Linux
|
||||||
|
Programming Language :: Python :: 3 :: Only
|
||||||
|
Programming Language :: Python :: 3.6
|
||||||
|
Programming Language :: Python :: 3.7
|
||||||
|
Programming Language :: Python :: 3.8
|
||||||
|
Programming Language :: Python :: 3.9
|
||||||
|
Programming Language :: Python :: 3.10
|
||||||
|
Programming Language :: Python :: 3.11
|
||||||
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
|
|
||||||
|
[options]
|
||||||
|
zip_safe = false
|
||||||
|
python_requires = ~=3.6
|
||||||
|
include_package_data =
|
||||||
|
"*" = ["*.ui", "*.txt"]
|
||||||
|
|
||||||
|
[options.entry_points]
|
||||||
|
console_scripts =
|
||||||
|
toxygen = toxygen.__main__:iMain
|
||||||
|
|
||||||
|
[easy_install]
|
||||||
|
zip_ok = false
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
jobs = 1
|
||||||
|
max-line-length = 88
|
||||||
|
ignore =
|
||||||
|
E111
|
||||||
|
E114
|
||||||
|
E128
|
||||||
|
E225
|
||||||
|
E261
|
||||||
|
E302
|
||||||
|
E305
|
||||||
|
E402
|
||||||
|
E501
|
||||||
|
E502
|
||||||
|
E541
|
||||||
|
E701
|
||||||
|
E702
|
||||||
|
E704
|
||||||
|
E722
|
||||||
|
E741
|
||||||
|
F508
|
||||||
|
F541
|
||||||
|
W503
|
||||||
|
W601
|
53
setup.py.dst
Normal file
53
setup.py.dst
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from setuptools import setup
|
||||||
|
from setuptools.command.install import install
|
||||||
|
|
||||||
|
version = '1.0.0'
|
||||||
|
|
||||||
|
MODULES = open('requirements.txt', 'rt').readlines()
|
||||||
|
|
||||||
|
def get_packages():
|
||||||
|
directory = os.path.join(os.path.dirname(__file__), 'tox_wrapper')
|
||||||
|
for root, dirs, files in os.walk(directory):
|
||||||
|
packages = map(lambda d: 'toxygen.' + d, dirs)
|
||||||
|
packages = ['toxygen'] + list(packages)
|
||||||
|
return packages
|
||||||
|
|
||||||
|
class InstallScript(install):
|
||||||
|
"""This class configures Toxygen after installation"""
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
install.run(self)
|
||||||
|
|
||||||
|
setup(name='Toxygen',
|
||||||
|
version=version,
|
||||||
|
description='Toxygen - Tox client',
|
||||||
|
long_description='Toxygen is powerful Tox client written in Python3',
|
||||||
|
url='https://git.plastiras.org/emdee/toxygen/',
|
||||||
|
keywords='toxygen Tox messenger',
|
||||||
|
author='Ingvar',
|
||||||
|
maintainer='',
|
||||||
|
license='GPL3',
|
||||||
|
packages=get_packages(),
|
||||||
|
install_requires=MODULES,
|
||||||
|
include_package_data=True,
|
||||||
|
classifiers=[
|
||||||
|
'Programming Language :: Python :: 3 :: Only',
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Programming Language :: Python :: 3.10",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
'Programming Language :: Python :: 3.11',
|
||||||
|
],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': ['toxygen=toxygen.main:main']
|
||||||
|
},
|
||||||
|
package_data={"": ["*.ui"],},
|
||||||
|
cmdclass={
|
||||||
|
'install': InstallScript,
|
||||||
|
},
|
||||||
|
zip_safe=False
|
||||||
|
)
|
|
@ -4,6 +4,7 @@ import os
|
||||||
import app
|
import app
|
||||||
import logging
|
import logging
|
||||||
import signal
|
import signal
|
||||||
|
import time
|
||||||
|
|
||||||
import faulthandler
|
import faulthandler
|
||||||
faulthandler.enable()
|
faulthandler.enable()
|
||||||
|
@ -11,7 +12,6 @@ faulthandler.enable()
|
||||||
import warnings
|
import warnings
|
||||||
warnings.filterwarnings('ignore')
|
warnings.filterwarnings('ignore')
|
||||||
|
|
||||||
import tox_wrapper.tests.support_testing as ts
|
|
||||||
try:
|
try:
|
||||||
from trepan.interfaces import server as Mserver
|
from trepan.interfaces import server as Mserver
|
||||||
from trepan.api import debug
|
from trepan.api import debug
|
||||||
|
@ -28,13 +28,13 @@ from user_data.settings import *
|
||||||
from user_data.settings import Settings
|
from user_data.settings import Settings
|
||||||
from user_data import settings
|
from user_data import settings
|
||||||
import utils.util as util
|
import utils.util as util
|
||||||
|
import tox_wrapper.tests.support_testing as ts
|
||||||
with ts.ignoreStderr():
|
with ts.ignoreStderr():
|
||||||
import pyaudio
|
import pyaudio
|
||||||
|
|
||||||
__maintainer__ = 'Ingvar'
|
__maintainer__ = 'Ingvar'
|
||||||
__version__ = '0.5.0+'
|
__version__ = '0.5.0+'
|
||||||
|
|
||||||
import time
|
|
||||||
sleep = time.sleep
|
sleep = time.sleep
|
||||||
|
|
||||||
def reset():
|
def reset():
|
|
@ -14,6 +14,8 @@ from PyQt5 import QtWidgets, QtGui, QtCore
|
||||||
from qtpy.QtCore import QTimer
|
from qtpy.QtCore import QTimer
|
||||||
from qtpy.QtWidgets import QApplication
|
from qtpy.QtWidgets import QApplication
|
||||||
|
|
||||||
|
__version__ = "1.0.0"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import coloredlogs
|
import coloredlogs
|
||||||
if 'COLOREDLOGS_LEVEL_STYLES' not in os.environ:
|
if 'COLOREDLOGS_LEVEL_STYLES' not in os.environ:
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
# toxygen_wrapper
|
|
||||||
|
|
||||||
[ctypes](https://docs.python.org/3/library/ctypes.html)
|
|
||||||
wrapping of [Tox](https://tox.chat/)
|
|
||||||
[```libtoxcore```](https://github.com/TokTok/c-toxcore) into Python.
|
|
||||||
Taken from the ```wrapper``` directory of the now abandoned
|
|
||||||
<https://github.com/toxygen-project/toxygen> ```next_gen``` branch
|
|
||||||
by Ingvar.
|
|
||||||
|
|
||||||
The basics of NGC groups are supported, as well as AV and toxencryptsave.
|
|
||||||
There is no coverage of conferences as they are not used in ```toxygen```
|
|
||||||
and the list of still unwrapped calls as of Sept. 2022 can be found in
|
|
||||||
```tox.c-toxcore.missing```. The code still needs double-checking
|
|
||||||
that every call in ```tox.py``` has the right signature, but it runs
|
|
||||||
```toxygen``` with no apparent issues.
|
|
||||||
|
|
||||||
It has been tested with UDP and TCP proxy (Tor). It has ***not*** been
|
|
||||||
tested on Windows, and there may be some minor breakage, which should be
|
|
||||||
easy to fix. There is a good coverage integration testsuite in ```wrapper_tests```.
|
|
||||||
Change to that directory and run ```tests_wrapper.py --help```; the test
|
|
||||||
suite gives a good set of examples of usage.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
Put the parent of the wrapper directory on your PYTHONPATH and
|
|
||||||
touch a file called `__init__.py` in its parent directory.
|
|
||||||
|
|
||||||
Then you need a ```libs``` directory beside the `wrapper` directory
|
|
||||||
and you need to link your ```libtoxcore.so``` and ```libtoxav.so```
|
|
||||||
and ```libtoxencryptsave.so``` into it. Link all 3 filenames
|
|
||||||
to ```libtoxcore.so``` if you have only ```libtoxcore.so```
|
|
||||||
(which is usually the case if you built ```c-toxcore``` with ```cmake```
|
|
||||||
rather than ```autogen/configure```). If you want to be different,
|
|
||||||
the environment variable TOXCORE_LIBS overrides the location of ```libs```.
|
|
||||||
|
|
||||||
As is, the code in ```tox.py``` is very verbose. Edit the file to change
|
|
||||||
```
|
|
||||||
def LOG_ERROR(a): print('EROR> '+a)
|
|
||||||
def LOG_WARN(a): print('WARN> '+a)
|
|
||||||
def LOG_INFO(a): print('INFO> '+a)
|
|
||||||
def LOG_DEBUG(a): print('DBUG> '+a)
|
|
||||||
def LOG_TRACE(a): pass # print('TRAC> '+a)
|
|
||||||
```
|
|
||||||
to all ```pass #``` or use ```logging.logger``` to suite your tastes.
|
|
||||||
```logging.logger``` can be dangerous in callbacks in ```Qt``` applications,
|
|
||||||
so we use simple print statements as default. The same applies to
|
|
||||||
```wrapper/tests_wrapper.py```.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
No prerequisites in Python3.
|
|
||||||
|
|
||||||
## Other wrappers
|
|
||||||
|
|
||||||
There are a number of other wrappings into Python of Tox core.
|
|
||||||
This one uses [ctypes](https://docs.python.org/3/library/ctypes.html)
|
|
||||||
which has its merits - there is no need to recompile anything as with
|
|
||||||
Cython - change the Python file and it's done. And you can follow things
|
|
||||||
in a Python debugger, or with the utterly stupendous Python feature of
|
|
||||||
```gdb``` (```gdb -ex r --args /usr/bin/python3.9 <pyfile>```).
|
|
||||||
|
|
||||||
CTYPES code can be brittle, segfaulting if you've got things wrong,
|
|
||||||
but if your wrapping is right, it is very efficient and easy to work on.
|
|
||||||
The [faulthandler](https://docs.python.org/3/library/faulthandler.html)
|
|
||||||
module can be helpful in debugging crashes
|
|
||||||
(e.g. from segmentation faults produced by erroneous C library wrapping).
|
|
||||||
|
|
||||||
Others include:
|
|
||||||
|
|
||||||
* <https://github.com/TokTok/py-toxcore-c> Cython bindings.
|
|
||||||
Incomplete and not really actively supported. Maybe it will get
|
|
||||||
worked on in the future, but TokTok seems to be working on
|
|
||||||
java, rust, scalla, go, etc. bindings instead.
|
|
||||||
No support for NGC groups or toxencryptsave.
|
|
||||||
|
|
||||||
* <https://github.com/oxij/PyTox>
|
|
||||||
forked from https://github.com/aitjcize/PyTox
|
|
||||||
by Wei-Ning Huang <aitjcize@gmail.com>.
|
|
||||||
Hardcore C wrapping which is not easy to keep up to date.
|
|
||||||
No support for NGC or toxencryptsave. Abandonned.
|
|
||||||
This was the basis for the TokTok/py-toxcore-c code until recently.
|
|
||||||
|
|
||||||
To our point of view, the ability of CTYPEs to follow code in the
|
|
||||||
debugger is a crucial advantage.
|
|
||||||
|
|
||||||
Work on this project is suspended until the
|
|
||||||
[MultiDevice](https://git.plastiras.org/emdee/tox_profile/wiki/MultiDevice-Announcements-POC) problem is solved. Fork me!
|
|
1
toxygen/tests/README.txt
Normal file
1
toxygen/tests/README.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
unused
|
|
@ -1,439 +0,0 @@
|
||||||
#!/var/local/bin/python3.bash
|
|
||||||
#
|
|
||||||
""" echo.py features
|
|
||||||
- accept friend request
|
|
||||||
- echo back friend message
|
|
||||||
- accept and answer friend call request
|
|
||||||
- send back friend audio/video data
|
|
||||||
- send back files friend sent
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import random
|
|
||||||
from ctypes import *
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
import time
|
|
||||||
from os.path import exists
|
|
||||||
|
|
||||||
# LOG=util.log
|
|
||||||
global LOG
|
|
||||||
import logging
|
|
||||||
# log = lambda x: LOG.info(x)
|
|
||||||
LOG = logging.getLogger('app')
|
|
||||||
def LOG_error(a): print('EROR_ '+a)
|
|
||||||
def LOG_warn(a): print('WARN_ '+a)
|
|
||||||
def LOG_info(a): print('INFO_ '+a)
|
|
||||||
def LOG_debug(a): print('DBUG_ '+a)
|
|
||||||
def LOG_trace(a): pass # print('TRAC_ '+a)
|
|
||||||
|
|
||||||
from middleware.tox_factory import tox_factory
|
|
||||||
import tox_wrapper
|
|
||||||
import tox_wrapper.toxcore_enums_and_consts as enums
|
|
||||||
from tox_wrapper.toxcore_enums_and_consts import TOX_CONNECTION, TOX_USER_STATUS, \
|
|
||||||
TOX_MESSAGE_TYPE, TOX_PUBLIC_KEY_SIZE, TOX_FILE_CONTROL
|
|
||||||
import user_data
|
|
||||||
from tox_wrapper.libtox import LibToxCore
|
|
||||||
import tox_wrapper.tests.support_testing as ts
|
|
||||||
from tox_wrapper.tests.support_testing import oMainArgparser
|
|
||||||
from tox_wrapper.tests.support_testing import logging_toxygen_echo
|
|
||||||
|
|
||||||
def sleep(fSec):
|
|
||||||
if 'QtCore' in globals():
|
|
||||||
if fSec > .000001: globals['QtCore'].QThread.msleep(fSec)
|
|
||||||
globals['QtCore'].QCoreApplication.processEvents()
|
|
||||||
else:
|
|
||||||
time.sleep(fSec)
|
|
||||||
|
|
||||||
try:
|
|
||||||
import coloredlogs
|
|
||||||
if 'COLOREDLOGS_LEVEL_STYLES' not in os.environ:
|
|
||||||
os.environ['COLOREDLOGS_LEVEL_STYLES'] = 'spam=22;debug=28;verbose=34;notice=220;warning=202;success=118,bold;error=124;critical=background=red'
|
|
||||||
except ImportError as e:
|
|
||||||
# logging.log(logging.DEBUG, f"coloredlogs not available: {e}")
|
|
||||||
coloredlogs = None
|
|
||||||
|
|
||||||
import tox_wrapper.tests.support_testing as ts
|
|
||||||
if 'USER' in os.environ:
|
|
||||||
sDATA_FILE = '/tmp/logging_toxygen_' +os.environ['USER'] +'.tox'
|
|
||||||
elif 'USERNAME' in os.environ:
|
|
||||||
sDATA_FILE = '/tmp/logging_toxygen_' +os.environ['USERNAME'] +'.tox'
|
|
||||||
else:
|
|
||||||
sDATA_FILE = '/tmp/logging_toxygen_' +'data' +'.tox'
|
|
||||||
|
|
||||||
bHAVE_AV = True
|
|
||||||
iDHT_TRIES = 100
|
|
||||||
iDHT_TRY = 0
|
|
||||||
|
|
||||||
#?SERVER = lLOCAL[-1]
|
|
||||||
|
|
||||||
class AV(tox_wrapper.tox.ToxAV):
|
|
||||||
def __init__(self, core):
|
|
||||||
super(AV, self).__init__(core)
|
|
||||||
self.core = self.get_tox()
|
|
||||||
|
|
||||||
def on_call(self, fid, audio_enabled, video_enabled):
|
|
||||||
LOG.info("Incoming %s call from %d:%s ..." % (
|
|
||||||
"video" if video_enabled else "audio", fid,
|
|
||||||
self.core.friend_get_name(fid)))
|
|
||||||
bret = self.answer(fid, 48, 64)
|
|
||||||
LOG.info(f"Answered, in call... {bret!s}")
|
|
||||||
|
|
||||||
def on_call_state(self, fid, state):
|
|
||||||
LOG.info('call state:fn=%d, state=%d' % (fid, state))
|
|
||||||
|
|
||||||
def on_audio_bit_rate(self, fid, audio_bit_rate):
|
|
||||||
LOG.info('audio bit rate status: fn=%d, abr=%d' %
|
|
||||||
(fid, audio_bit_rate))
|
|
||||||
|
|
||||||
def on_video_bit_rate(self, fid, video_bit_rate):
|
|
||||||
LOG.info('video bit rate status: fn=%d, vbr=%d' %
|
|
||||||
(fid, video_bit_rate))
|
|
||||||
|
|
||||||
def on_audio_receive_frame(self, fid, pcm, sample_count,
|
|
||||||
channels, sampling_rate):
|
|
||||||
# LOG.info('audio frame: %d, %d, %d, %d' %
|
|
||||||
# (fid, sample_count, channels, sampling_rate))
|
|
||||||
# LOG.info('pcm len:%d, %s' % (len(pcm), str(type(pcm))))
|
|
||||||
sys.stdout.write('.')
|
|
||||||
sys.stdout.flush()
|
|
||||||
bret = self.audio_send_frame(fid, pcm, sample_count,
|
|
||||||
channels, sampling_rate)
|
|
||||||
if bret is False:
|
|
||||||
LOG.error('on_audio_receive_frame error.')
|
|
||||||
|
|
||||||
def on_video_receive_frame(self, fid, width, height, frame, u, v):
|
|
||||||
LOG.info('video frame: %d, %d, %d, ' % (fid, width, height))
|
|
||||||
sys.stdout.write('*')
|
|
||||||
sys.stdout.flush()
|
|
||||||
bret = self.video_send_frame(fid, width, height, frame, u, v)
|
|
||||||
if bret is False:
|
|
||||||
LOG.error('on_video_receive_frame error.')
|
|
||||||
|
|
||||||
def witerate(self):
|
|
||||||
self.iterate()
|
|
||||||
|
|
||||||
|
|
||||||
def save_to_file(tox, fname):
|
|
||||||
data = tox.get_savedata()
|
|
||||||
with open(fname, 'wb') as f:
|
|
||||||
f.write(data)
|
|
||||||
|
|
||||||
def load_from_file(fname):
|
|
||||||
assert os.path.exists(fname)
|
|
||||||
return open(fname, 'rb').read()
|
|
||||||
|
|
||||||
class EchoBot():
|
|
||||||
def __init__(self, oTox):
|
|
||||||
self._tox = oTox
|
|
||||||
self._tox.self_set_name("EchoBot")
|
|
||||||
LOG.info('ID: %s' % self._tox.self_get_address())
|
|
||||||
|
|
||||||
self.files = {}
|
|
||||||
self.av = None
|
|
||||||
self.on_connection_status = None
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
self.connect()
|
|
||||||
if bHAVE_AV:
|
|
||||||
# RuntimeError: Attempted to create a second session for the same Tox instance.
|
|
||||||
|
|
||||||
self.av = True # AV(self._tox_pointer)
|
|
||||||
def bobs_on_friend_request(iTox,
|
|
||||||
public_key,
|
|
||||||
message_data,
|
|
||||||
message_data_size,
|
|
||||||
*largs):
|
|
||||||
key = ''.join(chr(x) for x in public_key[:TOX_PUBLIC_KEY_SIZE])
|
|
||||||
sPk = tox_wrapper.tox.bin_to_string(key, TOX_PUBLIC_KEY_SIZE)
|
|
||||||
sMd = str(message_data, 'UTF-8')
|
|
||||||
LOG.debug('on_friend_request ' +sPk +' ' +sMd)
|
|
||||||
self.on_friend_request(sPk, sMd)
|
|
||||||
LOG.info('setting bobs_on_friend_request')
|
|
||||||
self._tox.callback_friend_request(bobs_on_friend_request)
|
|
||||||
|
|
||||||
def bobs_on_friend_message(iTox,
|
|
||||||
iFriendNum,
|
|
||||||
iMessageType,
|
|
||||||
message_data,
|
|
||||||
message_data_size,
|
|
||||||
*largs):
|
|
||||||
sMd = str(message_data, 'UTF-8')
|
|
||||||
LOG_debug(f"on_friend_message {iFriendNum}" +' ' +sMd)
|
|
||||||
self.on_friend_message(iFriendNum, iMessageType, sMd)
|
|
||||||
LOG.info('setting bobs_on_friend_message')
|
|
||||||
self._tox.callback_friend_message(bobs_on_friend_message)
|
|
||||||
|
|
||||||
def bobs_on_file_chunk_request(iTox, fid, filenumber, position, length, *largs):
|
|
||||||
if length == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
data = self.files[(fid, filenumber)]['f'][position:(position + length)]
|
|
||||||
self._tox.file_send_chunk(fid, filenumber, position, data)
|
|
||||||
self._tox.callback_file_chunk_request(bobs_on_file_chunk_request)
|
|
||||||
|
|
||||||
def bobs_on_file_recv(iTox, fid, filenumber, kind, size, filename, *largs):
|
|
||||||
LOG_info(f"on_file_recv {fid!s} {filenumber!s} {kind!s} {size!s} {filename}")
|
|
||||||
if size == 0:
|
|
||||||
return
|
|
||||||
self.files[(fid, filenumber)] = {
|
|
||||||
'f': bytes(),
|
|
||||||
'filename': filename,
|
|
||||||
'size': size
|
|
||||||
}
|
|
||||||
self._tox.file_control(fid, filenumber, TOX_FILE_CONTROL['RESUME'])
|
|
||||||
|
|
||||||
|
|
||||||
def connect(self):
|
|
||||||
if not self.on_connection_status:
|
|
||||||
def on_connection_status(iTox, iCon, *largs):
|
|
||||||
LOG_info('ON_CONNECTION_STATUS - CONNECTED ' + repr(iCon))
|
|
||||||
self._tox.callback_self_connection_status(on_connection_status)
|
|
||||||
LOG.info('setting on_connection_status callback ')
|
|
||||||
self.on_connection_status = on_connection_status
|
|
||||||
if self._oargs.network in ['newlocal', 'local']:
|
|
||||||
LOG.info('connecting on the new network ')
|
|
||||||
sNet = 'newlocal'
|
|
||||||
elif self._oargs.network == 'new':
|
|
||||||
LOG.info('connecting on the new network ')
|
|
||||||
sNet = 'new'
|
|
||||||
else: # main old
|
|
||||||
LOG.info('connecting on the old network ')
|
|
||||||
sNet = 'old'
|
|
||||||
sFile = self._oargs.nodes_json
|
|
||||||
lNodes = generate_nodes_from_file(sFile)
|
|
||||||
lElts = lNodes
|
|
||||||
random.shuffle(lElts)
|
|
||||||
for lElt in lElts[:10]:
|
|
||||||
status = self._tox.self_get_connection_status()
|
|
||||||
try:
|
|
||||||
if self._tox.bootstrap(*lElt):
|
|
||||||
LOG.info('connected to ' + lElt[0]+' '+repr(status))
|
|
||||||
else:
|
|
||||||
LOG.warn('failed connecting to ' + lElt[0])
|
|
||||||
except Exception as e:
|
|
||||||
LOG.warn('error connecting to ' + lElt[0])
|
|
||||||
|
|
||||||
if self._oargs.proxy_type > 0:
|
|
||||||
random.shuffle(ts.lRELAYS)
|
|
||||||
for lElt in ts.lRELAYS[:10]:
|
|
||||||
status = self._tox.self_get_connection_status()
|
|
||||||
try:
|
|
||||||
if self._tox.add_tcp_relay(*lElt):
|
|
||||||
LOG.info('relayed to ' + lElt[0] +' '+repr(status))
|
|
||||||
else:
|
|
||||||
LOG.warn('failed relay to ' + lElt[0])
|
|
||||||
except Exception as e:
|
|
||||||
LOG.warn('error relay to ' + lElt[0])
|
|
||||||
|
|
||||||
def loop(self):
|
|
||||||
if not self.av:
|
|
||||||
self.start()
|
|
||||||
checked = False
|
|
||||||
save_to_file(self._tox, sDATA_FILE)
|
|
||||||
|
|
||||||
LOG.info('Starting loop.')
|
|
||||||
while True:
|
|
||||||
|
|
||||||
status = self._tox.self_get_connection_status()
|
|
||||||
if not checked and status:
|
|
||||||
LOG.info('Connected to DHT.')
|
|
||||||
checked = True
|
|
||||||
if not checked and not status:
|
|
||||||
global iDHT_TRY
|
|
||||||
iDHT_TRY += 10
|
|
||||||
self.connect()
|
|
||||||
self.iterate(100)
|
|
||||||
if iDHT_TRY >= iDHT_TRIES:
|
|
||||||
raise RuntimeError("Failed to connect to the DHT.")
|
|
||||||
LOG.warn(f"NOT Connected to DHT. {iDHT_TRY}")
|
|
||||||
checked = True
|
|
||||||
if checked and not status:
|
|
||||||
LOG.info('Disconnected from DHT.')
|
|
||||||
self.connect()
|
|
||||||
checked = False
|
|
||||||
|
|
||||||
if bHAVE_AV:
|
|
||||||
True # self.av.witerate()
|
|
||||||
self.iterate(100)
|
|
||||||
|
|
||||||
LOG.info('Ending loop.')
|
|
||||||
|
|
||||||
def iterate(self, n=100):
|
|
||||||
interval = self._tox.iteration_interval()
|
|
||||||
for i in range(n):
|
|
||||||
self._tox.iterate()
|
|
||||||
sleep(interval / 1000.0)
|
|
||||||
self._tox.iterate()
|
|
||||||
|
|
||||||
def on_friend_request(self, pk, message):
|
|
||||||
LOG.debug('Friend request from %s: %s' % (pk, message))
|
|
||||||
self._tox.friend_add_norequest(pk)
|
|
||||||
LOG.info('on_friend_request Accepted.')
|
|
||||||
save_to_file(self._tox, sDATA_FILE)
|
|
||||||
|
|
||||||
def on_friend_message(self, friendId, type, message):
|
|
||||||
name = self._tox.friend_get_name(friendId)
|
|
||||||
LOG.debug('%s: %s' % (name, message))
|
|
||||||
yMessage = bytes(message, 'UTF-8')
|
|
||||||
self._tox.friend_send_message(friendId, TOX_MESSAGE_TYPE['NORMAL'], yMessage)
|
|
||||||
LOG.info('EchoBot sent: %s' % message)
|
|
||||||
|
|
||||||
def on_file_recv_chunk(self, fid, filenumber, position, data):
|
|
||||||
filename = self.files[(fid, filenumber)]['filename']
|
|
||||||
size = self.files[(fid, filenumber)]['size']
|
|
||||||
LOG.debug(f"on_file_recv_chunk {fid!s} {filenumber!s} {filename} {position/float(size)*100!s}")
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
msg = "I got '{}', sending it back right away!".format(filename)
|
|
||||||
self._tox.friend_send_message(fid, TOX_MESSAGE_TYPE['NORMAL'], msg)
|
|
||||||
|
|
||||||
self.files[(fid, 0)] = self.files[(fid, filenumber)]
|
|
||||||
|
|
||||||
length = self.files[(fid, filenumber)]['size']
|
|
||||||
self.file_send(fid, 0, length, filename, filename)
|
|
||||||
|
|
||||||
del self.files[(fid, filenumber)]
|
|
||||||
return
|
|
||||||
|
|
||||||
self.files[(fid, filenumber)]['f'] += data
|
|
||||||
|
|
||||||
def iMain(oArgs):
|
|
||||||
global sDATA_FILE
|
|
||||||
# oTOX_OPTIONS = ToxOptions()
|
|
||||||
global oTOX_OPTIONS
|
|
||||||
oTOX_OPTIONS = oToxygenToxOptions(oArgs)
|
|
||||||
opts = oTOX_OPTIONS
|
|
||||||
if coloredlogs:
|
|
||||||
coloredlogs.install(
|
|
||||||
level=oArgs.loglevel,
|
|
||||||
logger=LOG,
|
|
||||||
# %(asctime)s,%(msecs)03d %(hostname)s [%(process)d]
|
|
||||||
fmt='%(name)s %(levelname)s %(message)s'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if 'logfile' in oArgs:
|
|
||||||
logging.basicConfig(filename=oArgs.logfile,
|
|
||||||
level=oArgs.loglevel,
|
|
||||||
format='%(levelname)-8s %(message)s')
|
|
||||||
else:
|
|
||||||
logging.basicConfig(level=oArgs.loglevel,
|
|
||||||
format='%(levelname)-8s %(message)s')
|
|
||||||
|
|
||||||
iRet = 0
|
|
||||||
if hasattr(oArgs,'profile') and oArgs.profile and os.path.isfile(oArgs.profile):
|
|
||||||
sDATA_FILE = oArgs.profile
|
|
||||||
LOG.info(f"loading from {sDATA_FILE}")
|
|
||||||
opts.savedata_data = load_from_file(sDATA_FILE)
|
|
||||||
opts.savedata_length = len(opts.savedata_data)
|
|
||||||
opts.savedata_type = enums.TOX_SAVEDATA_TYPE['TOX_SAVE']
|
|
||||||
else:
|
|
||||||
opts.savedata_data = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
if False:
|
|
||||||
oTox = tox_factory(data=opts.savedata_data,
|
|
||||||
settings=opts, args=oArgs, app=None)
|
|
||||||
else:
|
|
||||||
oTox = tox_wrapper.tox.Tox(opts)
|
|
||||||
t = EchoBot(oTox)
|
|
||||||
t._oargs = oArgs
|
|
||||||
t.start()
|
|
||||||
t.loop()
|
|
||||||
save_to_file(t._tox, sDATA_FILE)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
save_to_file(t._tox, sDATA_FILE)
|
|
||||||
except RuntimeError as e:
|
|
||||||
LOG.error(f"exiting with {e}")
|
|
||||||
iRet = 1
|
|
||||||
except Exception as e:
|
|
||||||
LOG.error(f"exiting with {e}")
|
|
||||||
LOG.warn(' iMain(): ' \
|
|
||||||
+'\n' + traceback.format_exc())
|
|
||||||
iRet = 1
|
|
||||||
return iRet
|
|
||||||
|
|
||||||
def oToxygenToxOptions(oArgs, data=None):
|
|
||||||
tox_options = tox_wrapper.tox.Tox.options_new()
|
|
||||||
|
|
||||||
tox_options.contents.local_discovery_enabled = False
|
|
||||||
tox_options.contents.dht_announcements_enabled = False
|
|
||||||
tox_options.contents.hole_punching_enabled = False
|
|
||||||
tox_options.contents.experimental_thread_safety = False
|
|
||||||
tox_options.contents.ipv6_enabled = False
|
|
||||||
tox_options.contents.tcp_port = 3390
|
|
||||||
|
|
||||||
if oArgs.proxy_type > 0:
|
|
||||||
tox_options.contents.proxy_type = int(oArgs.proxy_type)
|
|
||||||
tox_options.contents.proxy_host = bytes(oArgs.proxy_host, 'UTF-8')
|
|
||||||
tox_options.contents.proxy_port = int(oArgs.proxy_port)
|
|
||||||
tox_options.contents.udp_enabled = False
|
|
||||||
LOG.debug('setting oArgs.proxy_host = ' +oArgs.proxy_host)
|
|
||||||
else:
|
|
||||||
tox_options.contents.udp_enabled = True
|
|
||||||
|
|
||||||
if data: # load existing profile
|
|
||||||
tox_options.contents.savedata_type = enums.TOX_SAVEDATA_TYPE['TOX_SAVE']
|
|
||||||
tox_options.contents.savedata_data = c_char_p(data)
|
|
||||||
tox_options.contents.savedata_length = len(data)
|
|
||||||
else: # create new profile
|
|
||||||
tox_options.contents.savedata_type = enums.TOX_SAVEDATA_TYPE['NONE']
|
|
||||||
tox_options.contents.savedata_data = None
|
|
||||||
tox_options.contents.savedata_length = 0
|
|
||||||
|
|
||||||
if tox_options._options_pointer:
|
|
||||||
ts.vAddLoggerCallback(tox_options, ts.on_log)
|
|
||||||
else:
|
|
||||||
logging.warn("No tox_options._options_pointer " +repr(tox_options._options_pointer))
|
|
||||||
|
|
||||||
return tox_options
|
|
||||||
|
|
||||||
def oArgparse(lArgv):
|
|
||||||
parser = ts.oMainArgparser()
|
|
||||||
parser.add_argument('profile', type=str, nargs='?',
|
|
||||||
default=sDATA_FILE,
|
|
||||||
help='Path to Tox profile to save')
|
|
||||||
oArgs = parser.parse_args(lArgv)
|
|
||||||
if hasattr(oArgs, 'sleep') and oArgs.sleep == 'qt':
|
|
||||||
pass # broken
|
|
||||||
else:
|
|
||||||
oArgs.sleep = 'time'
|
|
||||||
for key in ts.lBOOLEANS:
|
|
||||||
if key not in oArgs: continue
|
|
||||||
val = getattr(oArgs, key)
|
|
||||||
if val in ['False', 'false', 0]:
|
|
||||||
setattr(oArgs, key, False)
|
|
||||||
else:
|
|
||||||
setattr(oArgs, key, True)
|
|
||||||
if not os.path.exists('/proc/sys/net/ipv6') and oArgs.ipv6_enabled:
|
|
||||||
LOG.warn('setting oArgs.ipv6_enabled = False')
|
|
||||||
oArgs.ipv6_enabled = False
|
|
||||||
return oArgs
|
|
||||||
|
|
||||||
def main(largs=None):
|
|
||||||
if largs is None: largs = []
|
|
||||||
oArgs = oArgparse(largs)
|
|
||||||
global oTOX_OARGS
|
|
||||||
oTOX_OARGS = oArgs
|
|
||||||
print(oArgs)
|
|
||||||
|
|
||||||
if coloredlogs:
|
|
||||||
logger = logging.getLogger()
|
|
||||||
# https://pypi.org/project/coloredlogs/
|
|
||||||
coloredlogs.install(level=oArgs.loglevel,
|
|
||||||
logger=logger,
|
|
||||||
# %(asctime)s,%(msecs)03d %(hostname)s [%(process)d]
|
|
||||||
fmt='%(name)s %(levelname)s %(message)s'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logging.basicConfig(level=oArgs.loglevel) # logging.INFO
|
|
||||||
|
|
||||||
return iMain(oArgs)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main(sys.argv[1:]))
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,17 +0,0 @@
|
||||||
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
|
||||||
|
|
||||||
from notifications import sound
|
|
||||||
from notifications.sound import SOUND_NOTIFICATION
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
if True:
|
|
||||||
def test_sound_notification(self):
|
|
||||||
"""
|
|
||||||
Plays sound notification
|
|
||||||
:param type of notification
|
|
||||||
"""
|
|
||||||
sound.sound_notification( SOUND_NOTIFICATION['MESSAGE'] )
|
|
||||||
sleep(10)
|
|
||||||
sound.sound_notification( SOUND_NOTIFICATION['FILE_TRANSFER'] )
|
|
||||||
sleep(10)
|
|
||||||
sound.sound_notification( None )
|
|
Loading…
Reference in a new issue