1
1
from __future__ import annotations
2
2
3
+ import contextlib
3
4
import json
4
5
import logging
5
6
import socket
6
7
from typing import Any
7
8
8
9
from luxos .api import logon_required
9
10
11
+ from .asyncops import TIMEOUT , parameters_to_list , validate_message
12
+ from .exceptions import MinerCommandSessionAlreadyActive
13
+
10
14
log = logging .getLogger (__name__ )
11
15
12
16
13
17
# internal_send_cgminer_command sends a command to the
14
18
# cgminer API server and returns the response.
15
19
def internal_send_cgminer_command (
16
- host : str , port : int , command : str , timeout_sec : int , verbose : bool
20
+ host : str , port : int , command : str , timeout : float | None
17
21
) -> dict [str , Any ]:
22
+ timeout_sec = TIMEOUT if timeout is None else timeout
18
23
# Create a socket connection to the server
19
24
with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as sock :
20
25
try :
21
26
# set timeout
22
- sock .settimeout (timeout_sec )
27
+ if timeout_sec is not None :
28
+ sock .settimeout (timeout )
23
29
24
30
# Connect to the server
25
31
sock .connect ((host , port ))
@@ -62,22 +68,23 @@ def internal_send_cgminer_command(
62
68
# send_cgminer_command sends a command to the cgminer API server and
63
69
# returns the response.
64
70
def send_cgminer_command (
65
- host : str , port : int , cmd : str , param : str , timeout : int , verbose : bool
71
+ host : str , port : int , cmd : str , param : str , timeout : float | None = None
66
72
) -> dict [str , Any ]:
73
+ timeout = TIMEOUT if timeout is None else timeout
67
74
req = str (f'{{"command": "{ cmd } ", "parameter": "{ param } "}}\n ' )
68
75
log .debug (f"Executing command: { cmd } with params: { param } to host: { host } " )
69
-
70
- return internal_send_cgminer_command (host , port , req , timeout , verbose )
76
+ return internal_send_cgminer_command (host , port , req , timeout )
71
77
72
78
73
79
# send_cgminer_simple_command sends a command with no params
74
80
# to the miner and returns the response.
75
81
def send_cgminer_simple_command (
76
- host : str , port : int , cmd : str , timeout : int , verbose : bool
82
+ host : str , port : int , cmd : str , timeout : float | None = None
77
83
) -> dict [str , Any ]:
84
+ timeout = TIMEOUT if timeout is None else timeout
78
85
req = str (f'{{"command": "{ cmd } "}}\n ' )
79
86
log .debug (f"Executing command: { cmd } to host: { host } " )
80
- return internal_send_cgminer_command (host , port , req , timeout , verbose )
87
+ return internal_send_cgminer_command (host , port , req , timeout )
81
88
82
89
83
90
# check_res_structure checks that the response has the expected structure.
@@ -128,28 +135,26 @@ def get_str_field(struct: dict[str, Any], name: str) -> str:
128
135
return s
129
136
130
137
131
- def logon (host : str , port : int , timeout : int , verbose : bool ) -> str :
138
+ def logon (host : str , port : int , timeout : float | None = None ) -> str :
132
139
# Send 'logon' command to cgminer and get the response
133
- res = send_cgminer_simple_command (host , port , "logon" , timeout , verbose )
134
-
140
+ timeout = TIMEOUT if timeout is None else timeout
141
+ res = send_cgminer_simple_command (host , port , "logon" , timeout )
142
+ if res ["STATUS" ][0 ]["STATUS" ] == "E" :
143
+ raise MinerCommandSessionAlreadyActive (host , port , res ["STATUS" ][0 ]["Msg" ])
135
144
# Check if the response has the expected structure
136
- check_res_structure (res , "SESSION" , 1 , 1 )
137
-
138
- # Extract the session data from the response
139
- session = res ["SESSION" ][0 ]
145
+ session = validate_message (host , port , res , "SESSION" )[0 ]
146
+ return str (session ["SessionID" ])
140
147
141
- # Get the 'SessionID' field from the session data
142
- s = get_str_field (session , "SessionID" )
143
148
144
- # If 'SessionID' is empty, raise an error indicating invalid session id
145
- if s == "" :
146
- raise ValueError ( "error: invalid session id" )
147
-
148
- # Return the extracted 'SessionID'
149
- return s
149
+ def logoff (
150
+ host : str , port : int , sid : str , timeout : float | None = None
151
+ ) -> dict [ str , Any ]:
152
+ timeout = TIMEOUT if timeout is None else timeout
153
+ res = send_cgminer_command ( host , port , "logoff" , sid , timeout )
154
+ return validate_message ( host , port , res )
150
155
151
156
152
- def add_session_id_parameter (session_id , parameters ):
157
+ def add_session_id_parameter (session_id , parameters ) -> list [ Any ] :
153
158
# Add the session id to the parameters
154
159
return [session_id , * parameters ]
155
160
@@ -160,40 +165,62 @@ def parameters_to_string(parameters):
160
165
161
166
162
167
def execute_command (
163
- host : str , port : int , timeout_sec : int , cmd : str , parameters : list , verbose : bool
168
+ host : str ,
169
+ port : int ,
170
+ timeout_sec : int | float | None ,
171
+ cmd : str ,
172
+ parameters : str | list [Any ] | dict [str , Any ] | None = None ,
173
+ verbose : bool = False ,
164
174
):
175
+ timeout_sec = TIMEOUT if timeout_sec is None else timeout_sec
165
176
# Check if logon is required for the command
166
177
logon_req = logon_required (cmd )
167
178
168
- try :
169
- if logon_req :
170
- # Get a SessionID
171
- sid = logon (host , port , timeout_sec , verbose )
172
- # Add the SessionID to the parameters list at the left.
173
- parameters = add_session_id_parameter (sid , parameters )
179
+ parameters = parameters_to_list (parameters )
180
+
181
+ if logon_req :
182
+ # Get a SessionID
183
+ sid = logon (host , port , timeout_sec )
184
+ # Add the SessionID to the parameters list at the left.
185
+ parameters = add_session_id_parameter (sid , parameters )
174
186
175
- log .debug ("Command requires a SessionID, logging in for host: %s" , host )
176
- log .info ("SessionID obtained for %s: %s" , host , sid )
187
+ log .debug ("SessionID obtained for %s: %s" , host , sid )
177
188
178
- # TODO verify this
179
- elif not logon_required : # type: ignore
180
- log .debug ("Logon not required for executing %s" , cmd )
189
+ # TODO verify this
190
+ elif not logon_req :
191
+ log .debug ("Logon not required for executing %s" , cmd )
181
192
182
- # convert the params to a string that LuxOS API accepts
183
- param_string = parameters_to_string (parameters )
193
+ # convert the params to a string that LuxOS API accepts
194
+ param_string = "," . join (parameters )
184
195
185
- log .debug ("%s on %s with parameters: %s" , cmd , host , param_string )
196
+ log .debug ("%s on %s with parameters: %s" , cmd , host , param_string )
186
197
187
- # Execute the API command
188
- res = send_cgminer_command (host , port , cmd , param_string , timeout_sec , verbose )
198
+ # Execute the API command
199
+ res = send_cgminer_command (host , port , cmd , param_string , timeout_sec )
189
200
190
- log .debug (res )
201
+ log .debug (res )
191
202
192
- # Log off to terminate the session
193
- if logon_req :
194
- send_cgminer_command (host , port , "logoff" , sid , timeout_sec , verbose )
203
+ # Log off to terminate the session
204
+ if logon_req :
205
+ logoff (host , port , sid , timeout_sec )
206
+
207
+ return res
208
+
209
+
210
+ def execute (
211
+ host : str ,
212
+ port : int ,
213
+ cmd : str ,
214
+ parameters : str | list [Any ] | dict [str , Any ] | None = None ,
215
+ timeout : float | None = None ,
216
+ ):
217
+ return execute_command (host , port , timeout , cmd , parameters )
195
218
196
- return res
197
219
198
- except Exception :
199
- log .exception ("Error executing %s on %s" , cmd , host )
220
+ @contextlib .contextmanager
221
+ def with_atm (host , port , enabled : bool , timeout : float | None = None ):
222
+ res = execute (host , port , "atm" , timeout = timeout )
223
+ current = validate_message (host , port , res , "ATM" )[0 ]["Enabled" ]
224
+ execute (host , port , "atmset" , {"enabled" : enabled }, timeout = timeout )
225
+ yield current
226
+ execute (host , port , "atmset" , {"enabled" : current }, timeout = timeout )
0 commit comments