globals.py 4.28 KB
Newer Older
1
from sbws.lib.pastlylogger import PastlyLogger
Matt Traudt's avatar
Matt Traudt committed
2
import os
3
import time
4
from filelock import FileLock
Matt Traudt's avatar
Matt Traudt committed
5
6
7
8


G_PKG_DIR = os.path.abspath(os.path.dirname(__file__))
G_INIT_FILE_MAP = [
9
10
11
12
13
14
15
16
    # Specified as:
    #     (source, destination, type)
    # Where:
    #     - source is relative to the sbws/ directory
    #     - destination is relative to $HOME/.sbws/ directory (or whatever the
    #     user specified as their directory with --directory)
    #     - type is 'file', and ideally type 'dir' will be supported in the
    #     future as needed
Matt Traudt's avatar
Matt Traudt committed
17
18
]

19
20
21
# Minimum and maximum number of bytes a client is allowed to request from a
# server. If these are changed, a WIRE_PROTO_VER bump is required, which also
# happens to require an sbws major version bump.
22
23
24
25
26
27
28
29
#
# Note for smart people and people who pull out Wireshark: Even if the client
# requests 1 byte, that request and the 1 byte response will each be carried
# over the Internet in 514 byte Tor cells. Theoretically we could bump the
# minimum request size up to ~498 bytes, but I see no reason why we should.
# Trying to hit the maximum cell size just makes sbws server send more, us read
# more, and it runs the risk of standards changing underneath us and sbws
# suddenly creating more than one cell.
30
MIN_REQ_BYTES = 1
31
MAX_REQ_BYTES = 1 * 1024 * 1024 * 1024  # 1 GiB
32
SOCKET_TIMEOUT = 60  # seconds
33

Matt Traudt's avatar
Matt Traudt committed
34
35

def is_initted(d):
36
    if not os.path.isdir(d):
Matt Traudt's avatar
Matt Traudt committed
37
38
        return False
    for _, fname, _ in G_INIT_FILE_MAP:
39
        fname = os.path.join(d, fname)
Matt Traudt's avatar
Matt Traudt committed
40
41
        if not os.path.exists(fname):
            return False
42
43
44
    conf_fname = os.path.join(d, 'config.ini')
    if not os.path.exists(conf_fname):
        return False
Matt Traudt's avatar
Matt Traudt committed
45
    return True
46
47


Matt Traudt's avatar
Matt Traudt committed
48
def fail_hard(*s, log=None):
49
50
51
    ''' Optionally log something to stdout ... and then exit as fast as
    possible '''
    if s:
Matt Traudt's avatar
Matt Traudt committed
52
53
54
55
        if log:
            log.error(*s)
        else:
            print(*s)
56
    exit(1)
Matt Traudt's avatar
Matt Traudt committed
57
58


59
60
61
62
63
64
65
66
67
68
def time_now():
    '''
    Return the current time in seconds since 1970. This function exists to
    make testing easier

    :returns: Unix timestamp as a float
    '''
    return time.time()


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
def _log_level_string_to_int(s):
    if s == 'debug':
        return 4
    elif s == 'info':
        return 3
    elif s == 'notice':
        return 2
    elif s == 'warn':
        return 1
    elif s == 'error':
        return 0
    fail_hard('Unknown log level:', s)


def _log_level_int_to_string(i):
    if i >= 4:
        return 'debug'
    elif i == 3:
        return 'info'
    elif i == 2:
        return 'notice'
    elif i == 1:
        return 'warn'
    else:
        return 'error'

Matt Traudt's avatar
Matt Traudt committed
95

96
97
def make_logger(args, conf):
    def get_logger(level, default):
Matt Traudt's avatar
Matt Traudt committed
98
        def_file = '/dev/stdout'
99
        common_kwargs = {'log_threads': True, 'default': default}
Matt Traudt's avatar
Matt Traudt committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        if level == 'debug':
            return PastlyLogger(debug=def_file, overwrite=['debug'],
                                **common_kwargs)
        if level == 'info':
            return PastlyLogger(info=def_file, overwrite=['info'],
                                **common_kwargs)
        if level == 'notice':
            return PastlyLogger(notice=def_file, overwrite=['notice'],
                                **common_kwargs)
        if level == 'warn':
            return PastlyLogger(warn=def_file, overwrite=['warn'],
                                **common_kwargs)
        if level == 'error':
            return PastlyLogger(error=def_file, overwrite=['error'],
                                **common_kwargs)
        else:
            fail_hard('Unknown log level', level)
117
118
119
120
121
122
    level_str = conf.get('general', 'log_level')
    default_level_str = level_str
    level = _log_level_string_to_int(level_str)
    level = level + args.verbose - args.quiet
    level_str = _log_level_int_to_string(level)
    return get_logger(level_str, default_level_str)
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138


def lock_directory(dname):
    '''
    Holds a lock on a file in **dname** so that other sbws processes/threads
    won't try to read/write while we are reading/writing in this directory.

    >>> with lock_directory(dname):
    >>>     # do things while you have the lock
    >>> # no longer have lock

    :param str dname: Name of directory we want to obtain a lock for
    :retrurns: the FileLock context manager for you to use in a with statement
    '''
    assert os.path.isdir(dname)
    return FileLock(os.path.join(dname, 'lockfile'))