-
Notifications
You must be signed in to change notification settings - Fork 2
/
bot.py
185 lines (159 loc) · 6.33 KB
/
bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#!/usr/bin/env python3
from collections import OrderedDict
from logging.handlers import RotatingFileHandler
import logging
import random
import shutil
import sys
import threading
import time
import botfiles as files
import botledger as ledger
import botlnd as lnd
import botlnurl as lnurl
import botnostr as nostr
import botreports as reports
import botutils as utils
def processBots():
global enabledBots
global foundTracker
if len(enabledBots.keys()) > 0:
# next npub's config
npub, eventHex = enabledBots.popitem(last=False)
botConfig = nostr.getNpubConfigFile(npub)
# check outstanding payments status
d100 = random.randint(1,100)
percentCheckOutstandingPayments = 25
if d100 <= percentCheckOutstandingPayments:
nostr.processOutstandingPayments(npub, botConfig)
# get any new replies seen on relays
responseEvents = nostr.getEventReplies(eventHex)
newEventsCount = len(responseEvents)
logger.debug(f"Found {newEventsCount} replies to {eventHex} via common botRelayManager")
if (newEventsCount == 0):
responseEvents = nostr.getEventRepliesToNpub(npub, eventHex)
newEventsCount = len(responseEvents)
logger.debug(f"Found {newEventsCount} replies to {eventHex} via inbox for {npub}")
# process em!
newsince = nostr.processEvents(npub, responseEvents, botConfig)
# When all bots processed
if len(enabledBots.keys()) == 0:
# Repopulate the list of enabled bots
enabledBots = nostr.getEnabledBots()
def billForTime():
global startTime
global unitsBilled
currentTime, _ = utils.getTimes()
upTime = currentTime - startTime
unitsRan = int(upTime / 864)
if unitsBilled < unitsRan:
unitsToBill = unitsRan - unitsBilled
for npub in enabledBots.keys():
balance = ledger.getCreditBalance(npub)
if balance > 0:
secondsBilled = (unitsToBill * 864)
balance = ledger.recordEntry(npub, "SERVICE FEES", 0, -1 * feeTime864 * unitsToBill, f"{unitsToBill} time unit monitoring event for past {secondsBilled} seconds")
if balance < 0:
nostr.handleEnable(npub, False)
# if npub in foundTracker:
# del foundTracker[npub]
unitsBilled += unitsToBill
if __name__ == '__main__':
startTime, _ = utils.getTimes()
# Logging to systemd
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(fmt="%(asctime)s %(name)s.%(levelname)s: %(message)s", datefmt="%Y.%m.%d %H:%M:%S")
stdoutLoggingHandler = logging.StreamHandler(stream=sys.stdout)
stdoutLoggingHandler.setFormatter(formatter)
logging.Formatter.converter = time.gmtime
logger.addHandler(stdoutLoggingHandler)
logFile = f"{files.logFolder}bot.log"
fileLoggingHandler = RotatingFileHandler(logFile, mode='a', maxBytes=10*1024*1024,
backupCount=21, encoding=None, delay=0)
fileLoggingHandler.setFormatter(formatter)
logger.addHandler(fileLoggingHandler)
files.logger = logger
lnd.logger = logger
lnurl.logger = logger
nostr.logger = logger
reports.logger = logger
# Load server config
serverConfig = files.getConfig(f"{files.dataFolder}serverconfig.json")
if len(serverConfig.keys()) == 0:
shutil.copy("sample-serverconfig.json", f"{files.dataFolder}serverconfig.json")
logger.info(f"Copied sample-server.config.json to {files.dataFolder}serverconfig.json")
logger.info("You will need to modify this file to setup Bot private key and LND connection settings")
quit()
nostr.config = serverConfig["nostr"]
lnd.config = serverConfig["lnd"]
lnurl.config = serverConfig["lnurl"]
reports.config = serverConfig["reports"]
# Connect to relays
nostr.connectToRelays()
# Load Lightning ID cache
nostr.loadLightningIdCache()
# Build and upload reports
reports.makeAllReports()
lastReportTime = startTime
makeReportsInterval = (1 * 60 * 60)
# Update bot profile if changed
nostr.checkMainBotProfile()
# Get initial enabled bots
enabledBots = OrderedDict()
enabledBots = nostr.getEnabledBots()
sleepMin = 5
sleepMax = 15
sleepGrowth = 1.2
sleepTime = sleepMin
jan012020 = 1577836800
timeChunk = 2 * 60 * 60 # 2 hours
upTime = 0
unitsBilled = 0
feeTime864 = 1000
fees = None
if "fees" in nostr.config: fees = nostr.config["fees"]
if fees is not None and "time864" in fees: feeTime864 = fees["time864"]
lastRelayReconnectTime = startTime
relayReconnectInterval = (30 * 60)
botProcessTime = startTime
botProcessInterval = (2 * 60)
# Bot loop
while True:
loopStartTime, _ = utils.getTimes()
# process outstanding invoices
lnd.checkInvoices()
# process the next enabled bot
if botProcessTime + botProcessInterval < loopStartTime:
processBots()
botProcessTime, _ = utils.getTimes()
# look for command and control messages
newMessages = nostr.checkDirectMessages()
if len(newMessages) > 0:
sleepTime = sleepMin
nostr.processDirectMessages(newMessages)
else:
sleepTime = min(sleepTime * sleepGrowth, sleepMax)
# time billing
billForTime()
# process part of loop end time
loopEndTime, _ = utils.getTimes()
# make reports periodically
if lastReportTime + makeReportsInterval < loopEndTime:
reports.makeAllReports()
lastReportTime, _ = utils.getTimes()
# reconnect relays if periodically
if lastRelayReconnectTime + relayReconnectInterval < loopEndTime:
nostr.reconnectRelays()
lastRelayReconnectTime, _ = utils.getTimes()
# otherwise, sleep if possible
else:
noLaterThan = loopStartTime + sleepTime
if noLaterThan > loopEndTime:
time2sleep = noLaterThan - loopEndTime
if time2sleep > sleepMax: time2sleep = sleepMax
else:
time2sleep = 2 # force it to avoid relay throttle
if time2sleep > 0:
logger.debug(f"Sleeping {time2sleep} seconds")
time.sleep(time2sleep)