Wrote some docstrings #6

Open
lee.miller wants to merge 5 commits from lee.miller/MiNode:doc into v0.3
6 changed files with 57 additions and 17 deletions

View File

@ -20,7 +20,7 @@ cd MiNode
It is worth noting that the `start.sh` script no longer tries to do a It is worth noting that the `start.sh` script no longer tries to do a
`git pull` in order to update to the latest version. `git pull` in order to update to the latest version.
Is is now done by the `update.sh` script. It is now done by the `update.sh` script.
## Command line ## Command line
``` ```

View File

@ -1,10 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Common reusable code for all the I2P entities"""
import base64 import base64
import hashlib import hashlib
import threading import threading
def receive_line(s): def receive_line(s):
"""Receive a line from the socket *s*"""
data = b'' data = b''
while b'\n' not in data: while b'\n' not in data:
d = s.recv(4096) d = s.recv(4096)
@ -36,6 +38,7 @@ class I2PThread(threading.Thread):
def pub_from_priv(priv): def pub_from_priv(priv):
"""Returns the public key for the private key *priv*"""
priv = base64.b64decode(priv, altchars=b'-~') priv = base64.b64decode(priv, altchars=b'-~')
# 256 for public key + 128 for signing key + 3 for certificate header # 256 for public key + 128 for signing key + 3 for certificate header
# + value of bytes priv[385:387] # + value of bytes priv[385:387]
@ -44,6 +47,7 @@ def pub_from_priv(priv):
def b32_from_pub(pub): def b32_from_pub(pub):
"""Converts the public key *pub* to base32 host name"""
return base64.b32encode( return base64.b32encode(
hashlib.sha256(base64.b64decode(pub, b'-~')).digest() hashlib.sha256(base64.b64decode(pub, b'-~')).digest()
).replace(b'=', b'').lower() + b'.b32.i2p' ).replace(b'=', b'').lower() + b'.b32.i2p'

View File

@ -62,6 +62,7 @@ class Manager(threading.Thread):
@staticmethod @staticmethod
def clean_objects(): def clean_objects():
"""Remove expired objects"""
for vector in set(shared.objects): for vector in set(shared.objects):
# FIXME: no need to check is_valid() here # FIXME: no need to check is_valid() here
if shared.objects[vector].is_expired(): if shared.objects[vector].is_expired():
@ -176,7 +177,7 @@ class Manager(threading.Thread):
@staticmethod @staticmethod
def load_data(): def load_data():
"""Loads initial nodes and data, stored in files between sessions""" """Load initial nodes and data, stored in files between sessions"""
try: try:
with open( with open(
os.path.join(shared.data_directory, 'objects.pickle'), 'br' os.path.join(shared.data_directory, 'objects.pickle'), 'br'
@ -229,6 +230,7 @@ class Manager(threading.Thread):
@staticmethod @staticmethod
def pickle_objects(): def pickle_objects():
"""Save objects into a file objects.pickle in the data directory"""
try: try:
with open( with open(
os.path.join(shared.data_directory, 'objects.pickle'), 'bw' os.path.join(shared.data_directory, 'objects.pickle'), 'bw'
@ -241,6 +243,7 @@ class Manager(threading.Thread):
@staticmethod @staticmethod
def pickle_nodes(): def pickle_nodes():
"""Save nodes into files in the data directory"""
if len(shared.node_pool) > 10000: if len(shared.node_pool) > 10000:
shared.node_pool = set(random.sample( shared.node_pool = set(random.sample(
tuple(shared.node_pool), 10000)) tuple(shared.node_pool), 10000))
@ -270,6 +273,7 @@ class Manager(threading.Thread):
@staticmethod @staticmethod
def publish_i2p_destination(): def publish_i2p_destination():
"""Make and publish a special object, containing the I2P destination"""
if shared.i2p_session_nick and not shared.i2p_transient: if shared.i2p_session_nick and not shared.i2p_transient:
logging.info('Publishing our I2P destination') logging.info('Publishing our I2P destination')
dest_pub_raw = base64.b64decode( dest_pub_raw = base64.b64decode(

View File

@ -4,11 +4,28 @@ import base64
import hashlib import hashlib
import struct import struct
import time import time
from abc import ABC, abstractmethod
from . import shared, structure from . import shared, structure
class Header(): class IMessage(ABC):
"""A base for typical message"""
@abstractmethod
def __repr__(self):
"""Make a printable form"""
@abstractmethod
def to_bytes(self):
"""Serialize to bytes the full message"""
@classmethod
@abstractmethod
def from_message(cls, m):
"""Parse from message"""
class Header(structure.IStructure):
"""Message header structure""" """Message header structure"""
def __init__(self, command, payload_length, payload_checksum): def __init__(self, command, payload_length, payload_checksum):
self.command = command self.command = command
@ -24,7 +41,6 @@ class Header():
base64.b16encode(self.payload_checksum).decode()) base64.b16encode(self.payload_checksum).decode())
def to_bytes(self): def to_bytes(self):
"""Serialize to bytes"""
b = b'' b = b''
b += shared.magic_bytes b += shared.magic_bytes
b += self.command.ljust(12, b'\x00') b += self.command.ljust(12, b'\x00')
@ -34,7 +50,6 @@ class Header():
@classmethod @classmethod
def from_bytes(cls, b): def from_bytes(cls, b):
"""Parse from bytes"""
magic_bytes, command, payload_length, payload_checksum = struct.unpack( magic_bytes, command, payload_length, payload_checksum = struct.unpack(
'>4s12sL4s', b) '>4s12sL4s', b)
@ -46,7 +61,7 @@ class Header():
return cls(command, payload_length, payload_checksum) return cls(command, payload_length, payload_checksum)
class Message(): class Message(structure.IStructure):
"""Common message structure""" """Common message structure"""
def __init__(self, command, payload): def __init__(self, command, payload):
self.command = command self.command = command
@ -61,7 +76,6 @@ class Message():
base64.b16encode(self.payload_checksum).decode()) base64.b16encode(self.payload_checksum).decode())
def to_bytes(self): def to_bytes(self):
"""Serialize to bytes"""
b = Header( b = Header(
self.command, self.payload_length, self.payload_checksum self.command, self.payload_length, self.payload_checksum
).to_bytes() ).to_bytes()
@ -70,7 +84,6 @@ class Message():
@classmethod @classmethod
def from_bytes(cls, b): def from_bytes(cls, b):
"""Parse from bytes"""
h = Header.from_bytes(b[:24]) h = Header.from_bytes(b[:24])
payload = b[24:] payload = b[24:]
@ -98,7 +111,7 @@ def _payload_read_int(data):
data[varint_length:]) data[varint_length:])
class Version(): class Version(IMessage):
"""The version message payload""" """The version message payload"""
def __init__( def __init__(
self, host, port, protocol_version=shared.protocol_version, self, host, port, protocol_version=shared.protocol_version,
@ -179,7 +192,7 @@ class Version():
host, port, protocol_version, services, nonce, user_agent, streams) host, port, protocol_version, services, nonce, user_agent, streams)
class Inv(): class Inv(IMessage):
"""The inv message payload""" """The inv message payload"""
def __init__(self, vectors): def __init__(self, vectors):
self.vectors = set(vectors) self.vectors = set(vectors)
@ -211,7 +224,7 @@ class Inv():
return cls(vectors) return cls(vectors)
class GetData(): class GetData(IMessage):
"""The getdata message payload""" """The getdata message payload"""
def __init__(self, vectors): def __init__(self, vectors):
self.vectors = set(vectors) self.vectors = set(vectors)
@ -243,7 +256,7 @@ class GetData():
return cls(vectors) return cls(vectors)
class Addr(): class Addr(IMessage):
"""The addr message payload""" """The addr message payload"""
def __init__(self, addresses): def __init__(self, addresses):
self.addresses = addresses self.addresses = addresses
@ -273,7 +286,7 @@ class Addr():
return cls(addresses) return cls(addresses)
class Error(): class Error(IMessage):
"""The error message payload""" """The error message payload"""
def __init__(self, error_text=b'', fatal=0, ban_time=0, vector=b''): def __init__(self, error_text=b'', fatal=0, ban_time=0, vector=b''):
self.error_text = error_text self.error_text = error_text

View File

@ -50,5 +50,10 @@ def _worker(obj):
def do_pow_and_publish(obj): def do_pow_and_publish(obj):
"""
Start a worker thread, doing PoW for the given object
and putting a new object and its vector into appropriate places in `shared`
to advertize to the network.
"""
t = threading.Thread(target=_worker, args=(obj, )) t = threading.Thread(target=_worker, args=(obj, ))
t.start() t.start()

View File

@ -6,11 +6,24 @@ import logging
import socket import socket
import struct import struct
import time import time
from abc import ABC, abstractmethod
from . import shared from . import shared
class VarInt(): class IStructure(ABC):
"""A base for typical structure"""
@abstractmethod
def to_bytes(self):
"""Serialize to bytes"""
@classmethod
@abstractmethod
def from_bytes(cls, b):
"""Parse from bytes"""
class VarInt(IStructure):
"""varint object""" """varint object"""
def __init__(self, n): def __init__(self, n):
self.n = n self.n = n
@ -29,6 +42,7 @@ class VarInt():
@staticmethod @staticmethod
def length(b): def length(b):
"""Get the varint length"""
if b == 0xfd: if b == 0xfd:
return 3 return 3
if b == 0xfe: if b == 0xfe:
@ -87,7 +101,7 @@ class Object():
nonce, expires_time, object_type, version, stream_number, payload) nonce, expires_time, object_type, version, stream_number, payload)
def to_bytes(self): def to_bytes(self):
"""Serialize to bytes""" """Serialize to bytes object payload"""
payload = b'' payload = b''
payload += self.nonce payload += self.nonce
payload += struct.pack('>QL', self.expires_time, self.object_type) payload += struct.pack('>QL', self.expires_time, self.object_type)
@ -151,7 +165,7 @@ class Object():
return hashlib.sha512(self.to_bytes()[8:]).digest() return hashlib.sha512(self.to_bytes()[8:]).digest()
class NetAddrNoPrefix(): class NetAddrNoPrefix(IStructure):
"""Network address""" """Network address"""
def __init__(self, services, host, port): def __init__(self, services, host, port):
self.services = services self.services = services
@ -199,7 +213,7 @@ class NetAddrNoPrefix():
return cls(services, host, port) return cls(services, host, port)
class NetAddr(): class NetAddr(IStructure):
"""Network address with time and stream""" """Network address with time and stream"""
def __init__(self, services, host, port, stream=shared.stream): def __init__(self, services, host, port, stream=shared.stream):
self.stream = stream self.stream = stream