1
1
import logging
2
2
import shlex
3
3
import traceback
4
- import os . path
4
+ from threading import Event
5
5
6
- from launcher .config import Config , ConfigLoader
7
- from launcher .shell import Shell
8
- from launcher .node import NodeManager , NodeNotFound
9
- from launcher .utils import ParallelExecutionError , ArgumentError
10
-
11
- from launcher .check_wallets import Action as CheckWalletsAction
12
6
from launcher .close_other_utils import Action as CloseOtherUtilsAction
13
- from launcher .auto_unlock import Action as AutoUnlockAction
14
- from launcher .warm_up import Action as WarmUpAction
15
- from launcher .errors import FatalError , ConfigError , ConfigErrorScope
7
+ from launcher .config import Config
8
+ from launcher .errors import FatalError , ConfigError , ConfigErrorScope , NoWaiting , ParallelError
9
+ from launcher .node import NodeManager , ServiceNotFound , ContainerNotFound
10
+ from launcher .utils import ArgumentError
11
+ import docker .errors
12
+ import os
16
13
14
+ logger = logging .getLogger (__name__ )
17
15
18
16
HELP = """\
19
17
Xucli shortcut commands
91
89
--inbound [inbound_balance] deposit from boltz (btc/ltc)
92
90
boltzcli <chain> withdraw
93
91
<amount> <address> withdraw from boltz channel
94
-
95
92
"""
96
93
97
-
98
- def init_logging ():
99
- fmt = "%(asctime)s.%(msecs)03d %(levelname)5s %(process)d --- [%(threadName)-15s] %(name)-30s: %(message)s"
100
- datefmt = "%Y-%m-%d %H:%M:%S"
101
- if os .path .exists ("/mnt/hostfs/tmp" ):
102
- logfile = "/mnt/hostfs/tmp/xud-docker.log"
103
- else :
104
- logfile = "xud-docker.log"
105
-
106
- logging .basicConfig (format = fmt , datefmt = datefmt , level = logging .INFO , filename = logfile , filemode = "w" )
107
-
108
- level_config = {
109
- "launcher" : logging .DEBUG ,
110
- }
111
-
112
- for logger , level in level_config .items ():
113
- logging .getLogger (logger ).setLevel (level )
114
-
115
-
116
- init_logging ()
94
+ REPORT = """Please click on https://github.com/ExchangeUnion/xud/issues/new?assignees=kilrau&labels=bug&template=bug-\
95
+ report.md&title=Short%2C+concise+description+of+the+bug, describe your issue, drag and drop the file "{network}.log" \
96
+ which is located in "{logs_dir}" into your browser window and submit your issue."""
117
97
118
98
119
99
class XudEnv :
120
- def __init__ (self , config , shell ):
121
- self .logger = logging .getLogger ("launcher.XudEnv" )
122
-
100
+ def __init__ (self , config : Config ):
123
101
self .config = config
124
- self .shell = shell
125
-
126
- self .node_manager = NodeManager (config , shell )
127
-
128
- def delegate_cmd_to_xucli (self , cmd ):
129
- self .node_manager .get_node ("xud" ).cli (cmd , self .shell )
130
-
131
- def command_report (self ):
132
- logs_dir = f"{ self .config .home_dir } /{ self .config .network } /logs"
133
- print (f"""Please click on https://github.com/ExchangeUnion/xud/issues/\
134
- new?assignees=kilrau&labels=bug&template=bug-report.md&title=Short%2C+concise+\
135
- description+of+the+bug, describe your issue, drag and drop the file "{ self .config .network } \
136
- .log" which is located in "{ logs_dir } " into your browser window and submit \
137
- your issue.""" )
138
-
139
- def handle_command (self , cmd ):
140
- try :
141
- args = shlex .split (cmd )
142
- arg0 = args [0 ]
102
+ self .node_manager = NodeManager (config )
103
+
104
+ def handle_command (self , cmd : str ) -> None :
105
+ args = shlex .split (cmd )
106
+ arg0 = args [0 ]
107
+ args = args [1 :]
108
+
109
+ if arg0 == "help" :
110
+ print (HELP )
111
+ elif arg0 == "status" :
112
+ self .node_manager .status ()
113
+ elif arg0 == "report" :
114
+ print (REPORT .format (self .config .network , self .config .logs_dir ))
115
+ elif arg0 == "logs" :
116
+ self .node_manager .cmd_logs .execute (* args )
117
+ elif arg0 == "start" :
118
+ self .node_manager .cmd_start .execute (* args )
119
+ elif arg0 == "stop" :
120
+ self .node_manager .cmd_stop .execute (* args )
121
+ elif arg0 == "restart" :
122
+ self .node_manager .cmd_restart .execute (* args )
123
+ elif arg0 == "_create" :
124
+ self .node_manager .cmd_create .execute (* args )
125
+ elif arg0 == "rm" :
126
+ self .node_manager .cmd_remove .execute (* args )
127
+ elif arg0 == "down" :
128
+ self .node_manager .down ()
129
+ elif arg0 == "up" :
130
+ self .node_manager .up ()
131
+ elif arg0 == "bitcoin-cli" :
132
+ bitcoind = self .node_manager .get_service ("bitcoind" )
133
+ bitcoind .cli (" " .join (args ))
134
+ elif arg0 == "litecoin-cli" :
135
+ litecoind = self .node_manager .get_service ("litecoind" )
136
+ litecoind .cli (" " .join (args ))
137
+ elif arg0 == "lndbtc-lncli" :
138
+ lndbtc = self .node_manager .get_service ("lndbtc" )
139
+ lndbtc .cli (" " .join (args ))
140
+ elif arg0 == "lndltc-lncli" :
141
+ lndltc = self .node_manager .get_service ("lndltc" )
142
+ lndltc .cli (" " .join (args ))
143
+ elif arg0 == "geth" :
144
+ geth = self .node_manager .get_service ("geth" )
145
+ geth .cli (" " .join (args ))
146
+ elif arg0 == "xucli" :
147
+ xud = self .node_manager .get_service ("xud" )
148
+ xud .cli (" " .join (args ))
149
+ elif arg0 == "boltzcli" :
150
+ boltz = self .node_manager .get_service ("boltz" )
151
+ boltz .cli (" " .join (args ))
152
+ elif arg0 == "deposit" :
153
+ boltz = self .node_manager .get_service ("boltz" )
154
+ if len (args ) == 0 :
155
+ print ("Missing chain" )
156
+ chain = args [0 ].lower ()
143
157
args = args [1 :]
144
- if arg0 == "status" :
145
- self .node_manager .status ()
146
- elif arg0 == "report" :
147
- self .command_report ()
148
- elif arg0 == "logs" :
149
- self .node_manager .logs (* args )
150
- elif arg0 == "start" :
151
- self .node_manager .start (* args )
152
- elif arg0 == "stop" :
153
- self .node_manager .stop (* args )
154
- elif arg0 == "restart" :
155
- self .node_manager .restart (* args )
156
- elif arg0 == "down" :
157
- self .node_manager .down ()
158
- elif arg0 == "up" :
159
- self .node_manager .up ()
160
- elif arg0 == "btcctl" :
161
- self .node_manager .cli ("btcd" , * args )
162
- elif arg0 == "ltcctl" :
163
- self .node_manager .cli ("ltcd" , * args )
164
- elif arg0 == "bitcoin-cli" :
165
- self .node_manager .cli ("bitcoind" , * args )
166
- elif arg0 == "litecoin-cli" :
167
- self .node_manager .cli ("litecoind" , * args )
168
- elif arg0 == "lndbtc-lncli" :
169
- self .node_manager .cli ("lndbtc" , * args )
170
- elif arg0 == "lndltc-lncli" :
171
- self .node_manager .cli ("lndltc" , * args )
172
- elif arg0 == "geth" :
173
- self .node_manager .cli ("geth" , * args )
174
- elif arg0 == "xucli" :
175
- self .node_manager .cli ("xud" , * args )
176
- elif arg0 == "boltzcli" :
177
- self .node_manager .cli ("boltz" , * args )
178
- elif arg0 == "deposit" :
179
- if len (args ) == 0 :
180
- print ("Missing chain" )
181
- chain = args [0 ].lower ()
182
- args = args [1 :]
183
- if chain == "btc" :
184
- self .node_manager .cli ("boltz" , "btc" , "deposit" , * args )
185
- elif chain == "ltc" :
186
- self .node_manager .cli ("boltz" , "ltc" , "deposit" , * args )
187
- else :
188
- self .node_manager .cli ("xud" , "walletdeposit" , chain , * args )
189
- elif arg0 == "withdraw" :
190
- if len (args ) == 0 :
191
- print ("Missing chain" )
192
- chain = args [0 ].lower ()
193
- args = args [1 :]
194
- if chain == "btc" :
195
- self .node_manager .cli ("boltz" , "btc" , "withdraw" , * args )
196
- elif chain == "ltc" :
197
- self .node_manager .cli ("boltz" , "ltc" , "withdraw" , * args )
198
- else :
199
- self .node_manager .cli ("xud" , "walletwithdraw" , chain , * args )
200
- elif arg0 == "help" :
201
- print (HELP )
158
+ if chain == "btc" :
159
+ boltz .cli ("btc deposit " + " " .join (args ))
160
+ elif chain == "ltc" :
161
+ boltz .cli ("ltc deposit " + " " .join (args ))
202
162
else :
203
- self .delegate_cmd_to_xucli (cmd )
204
-
205
- except NodeNotFound as e :
206
- if str (e ) == "boltz" and self .config .network == "simnet" :
207
- print ("Not available on simnet" )
208
- return
209
-
210
- print (f"Node not found: { e } " )
211
- except ArgumentError as e :
212
- print (e .usage )
213
- print (f"error: { e } " )
214
-
215
- def check_wallets (self ):
216
- CheckWalletsAction (self .node_manager ).execute ()
217
-
218
- def wait_for_channels (self ):
219
- # TODO wait for channels
220
- pass
221
-
222
- def auto_unlock (self ):
223
- AutoUnlockAction (self .node_manager ).execute ()
163
+ xud = self .node_manager .get_service ("xud" )
164
+ xud .cli ("walletdeposit %s %s" % (chain , " " .join (args )))
165
+ elif arg0 == "withdraw" :
166
+ boltz = self .node_manager .get_service ("boltz" )
167
+ if len (args ) == 0 :
168
+ print ("Missing chain" )
169
+ chain = args [0 ].lower ()
170
+ args = args [1 :]
171
+ if chain == "btc" :
172
+ boltz .cli ("btc withdraw " + " " .join (args ))
173
+ elif chain == "ltc" :
174
+ boltz .cli ("ltc withdraw " + " " .join (args ))
175
+ else :
176
+ xud = self .node_manager .get_service ("xud" )
177
+ xud .cli ("walletwithdraw %s %s" % (chain , " " .join (args )))
178
+ else :
179
+ xud = self .node_manager .get_service ("xud" )
180
+ xud .cli (cmd )
224
181
225
182
def close_other_utils (self ):
226
- CloseOtherUtilsAction (self .config .network , self .shell ).execute ()
227
-
228
- def warm_up (self ):
229
- WarmUpAction (self .node_manager ).execute ()
230
-
231
- def pre_start (self ):
232
- self .warm_up ()
233
- self .check_wallets ()
183
+ CloseOtherUtilsAction (self .config .network ).execute ()
234
184
235
- if self . config . network == "simnet" :
236
- self . wait_for_channels ( )
185
+ def pre_shell ( self ) :
186
+ print ( " \n 🏃 Warming up... \n " )
237
187
238
- self .auto_unlock ()
188
+ xud = self .node_manager .get_service ("xud" )
189
+ stop = Event ()
190
+ try :
191
+ # FIXME pty signal only works in main thread
192
+ xud .ensure_ready (stop )
193
+ except (KeyboardInterrupt , NoWaiting ):
194
+ stop .set ()
195
+ raise
239
196
240
197
self .close_other_utils ()
241
198
242
199
def start (self ):
243
- self .logger .info ("Start %s" , self .config .network )
244
-
245
- up_env = self .node_manager .update ()
246
-
247
- if up_env :
248
- self .node_manager .up ()
249
- self .pre_start ()
250
-
251
- self .logger .info ("Start shell" )
252
- self .shell .start (f"{ self .config .network } > " , self .handle_command )
200
+ logger .info ("Start %s" , self .config .network )
201
+
202
+ self .node_manager .update ()
203
+
204
+ self .node_manager .up ()
205
+
206
+ self .pre_shell ()
207
+
208
+ logger .info ("Start shell" )
209
+ banner_file = os .path .dirname (__file__ ) + "/banner.txt"
210
+ with open (banner_file ) as f :
211
+ print (f .read (), end = "" , flush = True )
212
+ prompt = f"{ self .config .network } > "
213
+ while True :
214
+ try :
215
+ cmd = input (prompt )
216
+ cmd = cmd .strip ()
217
+ if cmd == "" :
218
+ continue
219
+ if cmd == "exit" :
220
+ break
221
+ try :
222
+ self .handle_command (cmd )
223
+ except KeyboardInterrupt :
224
+ pass
225
+ except ServiceNotFound as e :
226
+ print ("Service not found: %s" % e )
227
+ except ContainerNotFound as e :
228
+ print ("Service not running: %s" % e )
229
+ except docker .errors .APIError as e :
230
+ print (e )
231
+ except ArgumentError as e :
232
+ print (e .usage )
233
+ print (f"Error: { e } " )
234
+ except :
235
+ logger .exception ("[Shell] Failed to execute command: %s" , cmd )
236
+ traceback .print_exc ()
237
+ except KeyboardInterrupt :
238
+ print ()
253
239
254
240
255
241
def print_config_error_cause (e : ConfigError ) -> None :
@@ -262,40 +248,25 @@ def print_config_error_cause(e: ConfigError) -> None:
262
248
263
249
264
250
class Launcher :
265
- def __init__ (self ):
266
- self .logger = logging .getLogger ("launcher.Launcher" )
267
- self .logfile = None
268
-
269
251
def launch (self ):
270
- shell = Shell ()
271
252
config = None
272
253
try :
273
- config = Config (ConfigLoader ())
274
- shell .set_network_dir (config .network_dir ) # will create shell history file in network_dir
275
- env = XudEnv (config , shell )
254
+ config = Config ()
255
+ env = XudEnv (config )
276
256
env .start ()
277
257
except KeyboardInterrupt :
278
258
print ()
279
- except ConfigError as e :
280
- if e .scope == ConfigErrorScope .COMMAND_LINE_ARGS :
281
- print ("Failed to parse command-line arguments, exiting." )
282
- print_config_error_cause (e )
283
- elif e .scope == ConfigErrorScope .GENERAL_CONF :
284
- print ("Failed to parse config file {}, exiting." .format (e .conf_file ))
285
- print_config_error_cause (e )
286
- elif e .scope == ConfigErrorScope .NETWORK_CONF :
287
- print ("Failed to parse config file {}, exiting." .format (e .conf_file ))
288
- print_config_error_cause (e )
259
+ exit (1 )
260
+ except NoWaiting :
261
+ exit (1 )
289
262
except FatalError as e :
290
- if config and config .logfile :
291
- print ("{}. For more details, see {}" .format (e , config .logfile ))
292
- else :
293
- traceback .print_exc ()
294
- except ParallelExecutionError :
295
- pass
296
- except Exception : # exclude system exceptions like SystemExit
297
- self .logger .exception ("Unexpected exception during launching" )
298
- traceback .print_exc ()
299
- finally :
300
- shell .stop ()
301
-
263
+ msg = "💀 %s." % str (e )
264
+ if config :
265
+ msg += " For more details, see %s" % config .host_logfile
266
+ print (msg )
267
+ exit (1 )
268
+ except ParallelError :
269
+ if config :
270
+ msg = "For more details, see %s" % config .host_logfile
271
+ print (msg )
272
+ exit (1 )
0 commit comments