Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
[pycodestyle]
max-line-length = 119
ignore = E722,E402

[flake8]
max-line-length = 119
ignore = E722
ignore = E722,E402
# E402: pylint is preferred for wrong-import-position

# pylint
[MESSAGES CONTROL]
Expand Down
310 changes: 213 additions & 97 deletions src/api.py

Large diffs are not rendered by default.

112 changes: 67 additions & 45 deletions src/bitmessagemain.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,52 @@
#!/usr/bin/python2.7
# Copyright (c) 2012-2016 Jonathan Warren
# Copyright (c) 2012-2018 The Bitmessage developers
# Distributed under the MIT/X11 software license. See the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# pylint: disable=no-self-use,too-many-branches,too-many-statements,too-many-locals
"""
bitmessagemain.py
=================

# Right now, PyBitmessage only support connecting to stream 1. It doesn't
# yet contain logic to expand into further streams.
Copyright (c) 2012-2016 Jonathan Warren
Copyright (c) 2012-2018 The Bitmessage developers
Distributed under the MIT/X11 software license. See the accompanying
file COPYING or http://www.opensource.org/licenses/mit-license.php.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you moving copyrights to docstring?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multi-line comments are better done with a triple quoted string. In particular, Sphinx (or rather effective rST comments) requires triple quoted strings. However a triple-quoted string is flagged by linters as 'string statement has no effect'. Perhaps a Sphinx section on copyright would be the best place to put these notices? Being part of a module docstring made more sense to me than loose in the top level in module, though I don't feel a Python file is the right place anyway. So continued in PR#1270.


# The software version variable is now held in shared.py
Right now, PyBitmessage only support connecting to stream 1. It doesn't
yet contain logic to expand into further streams.

import os
import sys

app_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(app_dir)
sys.path.insert(0, app_dir)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will probably break script execution.

The software version variable is now held in shared.py

"""

import depends
depends.check_dependencies()
from __future__ import absolute_import

# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully.
import signal
# The next 3 are used for the API
from singleinstance import singleinstance
import ctypes
import errno
import getopt
import os
import signal
import socket
import ctypes
import sys
import threading
from random import randint
from struct import pack
from subprocess import call
from time import sleep
from random import randint
import getopt


# Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully.
# The next 3 are used for the API
from singleinstance import singleinstance

from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer
from helper_startup import (
isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections
)

import defaults
import depends
import shared
import knownnodes
import state
import shutdown
import threading

# Classes
from class_sqlThread import sqlThread
Expand Down Expand Up @@ -72,7 +75,12 @@
import helper_threading


depends.check_dependencies()


def connectToStream(streamNumber):
"""Connect to a stream"""

state.streamsInWhichIAmParticipating.append(streamNumber)
selfInitiatedConnections[streamNumber] = {}

Expand All @@ -93,10 +101,10 @@ def connectToStream(streamNumber):
with knownnodes.knownNodesLock:
if streamNumber not in knownnodes.knownNodes:
knownnodes.knownNodes[streamNumber] = {}
if streamNumber*2 not in knownnodes.knownNodes:
knownnodes.knownNodes[streamNumber*2] = {}
if streamNumber*2+1 not in knownnodes.knownNodes:
knownnodes.knownNodes[streamNumber*2+1] = {}
if streamNumber * 2 not in knownnodes.knownNodes:
knownnodes.knownNodes[streamNumber * 2] = {}
if streamNumber * 2 + 1 not in knownnodes.knownNodes:
knownnodes.knownNodes[streamNumber * 2 + 1] = {}

BMConnectionPool().connectToStream(streamNumber)

Expand All @@ -114,6 +122,8 @@ def _fixSocket():
addressToString = ctypes.windll.ws2_32.WSAAddressToStringA

def inet_ntop(family, host):
"""Convert IPv4 and IPv6 addresses from binary to text form"""

if family == socket.AF_INET:
if len(host) != 4:
raise ValueError("invalid IPv4 host")
Expand All @@ -135,6 +145,8 @@ def inet_ntop(family, host):
stringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA

def inet_pton(family, host):
"""Convert IPv4 and IPv6 addresses from text to binary form"""

buf = "\0" * 28
lengthBuf = pack("I", len(buf))
if stringToAddress(str(host),
Expand All @@ -158,13 +170,15 @@ def inet_pton(family, host):
socket.IPV6_V6ONLY = 27


# This thread, of which there is only one, runs the API.
class singleAPI(threading.Thread, helper_threading.StoppableThread):
"""This thread, of which there is only one, runs the API."""

def __init__(self):
threading.Thread.__init__(self, name="singleAPI")
self.initStop()

def stopThread(self):
"""Stop the API thread"""
super(singleAPI, self).stopThread()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
Expand All @@ -178,9 +192,10 @@ def stopThread(self):
pass

def run(self):
"""Run the API thread"""
port = BMConfigParser().getint('bitmessagesettings', 'apiport')
try:
from errno import WSAEADDRINUSE
from errno import WSAEADDRINUSE # pylint: disable=unused-variable
except (ImportError, AttributeError):
errno.WSAEADDRINUSE = errno.EADDRINUSE
for attempt in range(50):
Expand Down Expand Up @@ -215,23 +230,26 @@ def run(self):
defaults.networkDefaultPayloadLengthExtraBytes / 100)


class Main:
class Main(object):
"""The main app"""

def start(self):
"""Start the main app"""
_fixSocket()

daemon = BMConfigParser().safeGetBoolean(
'bitmessagesettings', 'daemon')

try:
opts, args = getopt.getopt(
opts, _ = getopt.getopt(
sys.argv[1:], "hcdt",
["help", "curses", "daemon", "test"])

except getopt.GetoptError:
self.usage()
sys.exit(2)

for opt, arg in opts:
for opt, _ in opts:
if opt in ("-h", "--help"):
self.usage()
sys.exit()
Expand All @@ -249,7 +267,7 @@ def start(self):

if daemon and not state.testmode:
with shared.printLock:
print('Running as a daemon. Send TERM signal to end.')
print 'Running as a daemon. Send TERM signal to end.'
self.daemonize()

self.setSignalHandler()
Expand Down Expand Up @@ -381,8 +399,7 @@ def start(self):
BMConfigParser().remove_option('bitmessagesettings', 'dontconnect')
elif daemon is False:
if state.curses:
# if depends.check_curses():
print('Running with curses')
print 'Running with curses'
import bitmessagecurses
bitmessagecurses.runwrapper()
elif depends.check_pyqt():
Expand Down Expand Up @@ -411,6 +428,7 @@ def start(self):
sleep(1)

def daemonize(self):
"""Daemonise"""
grandfatherPid = os.getpid()
parentPid = None
try:
Expand All @@ -420,7 +438,7 @@ def daemonize(self):
# wait until grandchild ready
while True:
sleep(1)
os._exit(0)
sys.exit(0)
except AttributeError:
# fork not implemented
pass
Expand All @@ -441,7 +459,7 @@ def daemonize(self):
# wait until child ready
while True:
sleep(1)
os._exit(0)
sys.exit(0)
except AttributeError:
# fork not implemented
pass
Expand All @@ -463,11 +481,13 @@ def daemonize(self):
os.kill(grandfatherPid, signal.SIGTERM)

def setSignalHandler(self):
"""Register signal handlers"""
signal.signal(signal.SIGINT, helper_generic.signal_handler)
signal.signal(signal.SIGTERM, helper_generic.signal_handler)
# signal.signal(signal.SIGINT, signal.SIG_DFL)

def usage(self):
"""Print usage message"""

print 'Usage: ' + sys.argv[0] + ' [OPTIONS]'
print '''
Options:
Expand All @@ -480,12 +500,18 @@ def usage(self):
'''

def stop(self):
"""Stop the daemon"""
with shared.printLock:
print('Stopping Bitmessage Deamon.')
print 'Stopping Bitmessage Daemon.'
shutdown.doCleanShutdown()

# TODO: nice function but no one is using this
def getApiAddress(self):
"""
Return the address and port the API is configured to use

.. todo:: nice function but no one is using this
"""

if not BMConfigParser().safeGetBoolean(
'bitmessagesettings', 'apienabled'):
return None
Expand All @@ -495,14 +521,10 @@ def getApiAddress(self):


def main():
"""Create and start the main app"""
mainprogram = Main()
mainprogram.start()


if __name__ == "__main__":
main()


# So far, the creation of and management of the Bitmessage protocol and this
# client is a one-man operation. Bitcoin tips are quite appreciated.
# 1H5XaDA6fYENLbknwZyjiYXYPQaFjjLX2u
Loading