Skip to content

Commit 05b0159

Browse files
Merge pull request #27 from bitcap-co/feat-dragonball
support dragonball miners
2 parents b440904 + a881efc commit 05b0159

10 files changed

Lines changed: 152 additions & 3 deletions

File tree

resources/app/config.json.default

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"volcminer": false,
1313
"goldshell": false,
1414
"sealminer": false,
15-
"elphapex": false
15+
"elphapex": false,
16+
"dragonball": false
1617
}
1718
}
1819
},

src/ipr.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ def __init__(self):
135135
self.listenerConfig.addButton(self.checkListenGoldshell, 5)
136136
self.listenerConfig.addButton(self.checkListenSealminer, 6)
137137
self.listenerConfig.addButton(self.checkListenElphapex, 7)
138+
self.listenerConfig.addButton(self.checkListenDragonball, 8)
138139
self.listenerConfig.buttonClicked.connect(self.restart_listen)
139140
# listener signals
140141
self.actionIPRStart.clicked.connect(self.start_listen)
@@ -337,6 +338,9 @@ def read_settings(self):
337338
self.checkListenElphapex.setChecked(
338339
self.config["general"]["listenFor"]["additional"]["elphapex"]
339340
)
341+
self.checkListenDragonball.setChecked(
342+
self.config["general"]["listenFor"]["additional"]["dragonball"]
343+
)
340344

341345
# api
342346
self.lineBitmainPasswd.setText(
@@ -425,6 +429,7 @@ def update_settings(self):
425429
"goldshell": self.checkListenGoldshell.isChecked(),
426430
"sealminer": self.checkListenSealminer.isChecked(),
427431
"elphapex": self.checkListenElphapex.isChecked(),
432+
"dragonball": self.checkListenDragonball.isChecked(),
428433
},
429434
},
430435
},
@@ -793,7 +798,7 @@ def post_process_result(self, result: List[str]):
793798
ip, mac, type, sn = result
794799
logger.debug(f"process_result : got {ip},{mac},{sn},{type} from listener.")
795800
if type == "bitmain-common":
796-
bitmain_common_miners = [self.checkListenAntminer, self.checkListenVolcminer]
801+
bitmain_common_miners = [self.checkListenAntminer, self.checkListenVolcminer, self.checkListenDragonball]
797802
enabled_common_filter = [btn.text().lower() for btn in bitmain_common_miners if btn.isChecked()]
798803
for miner in bitmain_common_miners:
799804
match miner.text().lower():
@@ -811,6 +816,13 @@ def post_process_result(self, result: List[str]):
811816
type = "volcminer"
812817
self.api_client.close_client()
813818
break
819+
case "dragonball":
820+
self.api_client.create_dragonball_client(ip, None)
821+
if not self.api_client.client or not self.api_client.is_dragonball():
822+
continue
823+
type = "dragonball"
824+
self.api_client.close_client()
825+
break
814826
if type not in enabled_common_filter:
815827
logger.warning(f"process_result : recieved miner type {type} outside of filter: {enabled_common_filter}. Ignoring...")
816828
self.iprStatus.showMessage(f"Status :: Got miner type: {type.capitalize()} outside of listener configuration.", 8000)
@@ -879,6 +891,11 @@ def locate_miner(self, row: int, col: int):
879891
"Status :: Failed to locate miner: VolcMiner is currently not supported.",
880892
5000,
881893
)
894+
case "dragonball":
895+
return self.iprStatus.showMessage(
896+
"Status :: Failed to locate miner: Dragonball is currently not supported.",
897+
5000
898+
)
882899
case "iceriver":
883900
custom_auth = self.linePbfarmerKey.text()
884901
case "whatsminer":

src/mod/api/client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from mod.api.parser import Parser
1515

1616
from .miners.bitmain import BitmainHTTPClient, BitmainParser
17+
from .miners.dragonball import DragonballHTTPClient, DragonballParser
1718
from .miners.elphapex import ElphapexHTTPClient, ElphapexParser
1819
from .miners.goldshell import GoldshellHTTPClient, GoldshellParser
1920
from .miners.iceriver import IceriverHTTPClient, IceriverParser
@@ -82,6 +83,12 @@ def create_elphapex_client(self, ip_addr: str, passwd: str) -> None:
8283
except (FailedConnectionError, AuthenticationError) as err:
8384
logger.error(err)
8485

86+
def create_dragonball_client(self, ip_addr: str, passwd: str) -> None:
87+
try:
88+
self.client = DragonballHTTPClient(ip_addr, passwd)
89+
except (FailedConnectionError, AuthenticationError) as err:
90+
logger.error(err)
91+
8592
def create_client_from_type(
8693
self, miner_type: str, ip_addr: str, auth: str, custom_auth: str
8794
) -> None:
@@ -100,6 +107,8 @@ def create_client_from_type(
100107
self.create_sealminer_client(ip_addr, auth)
101108
case "elphapex":
102109
self.create_elphapex_client(ip_addr, auth)
110+
case "dragonball":
111+
self.create_dragonball_client(ip_addr, auth)
103112

104113
def locate_miner(self, miner_type: str) -> None:
105114
self.locate = QTimer(self.parent)
@@ -152,6 +161,12 @@ def is_volcminer(self) -> bool:
152161
return True
153162
return False
154163

164+
def is_dragonball(self) -> bool:
165+
miner_type = self.get_common_miner_type()
166+
if miner_type and miner_type == "miner":
167+
return True
168+
return False
169+
155170
def get_target_info(self, parser: Parser) -> Dict[str, str]:
156171
result = parser.get_target()
157172
if not self.client:
@@ -186,6 +201,8 @@ def get_target_info(self, parser: Parser) -> Dict[str, str]:
186201
parser.parse_system_info(sys)
187202
info = self.client.get_miner_info()
188203
parser.parse_platform(info)
204+
elif isinstance(parser, DragonballParser):
205+
parser.parse_system_info(sys)
189206
return parser.get_target()
190207

191208
def get_target_data_from_type(self, miner_type: str) -> Dict[str, str]:
@@ -204,6 +221,8 @@ def get_target_data_from_type(self, miner_type: str) -> Dict[str, str]:
204221
return self.get_target_info(SealminerParser(self.target_info))
205222
case "elphapex":
206223
return self.get_target_info(ElphapexParser(self.target_info))
224+
case "dragonball":
225+
return self.get_target_info(DragonballParser(self.target_info))
207226
case _:
208227
return self.target_info
209228

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .client import DragonballHTTPClient
2+
from .parser import DragonballParser
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from string import Template
2+
from typing import Any, Dict, Optional
3+
4+
import requests
5+
6+
from mod.api import settings
7+
from mod.api.http import BaseHTTPClient
8+
9+
10+
class DragonballHTTPClient(BaseHTTPClient):
11+
"""Dragonball HTTP Client"""
12+
13+
def __init__(self, ip_addr: str, passwd: str, port: int = 16666):
14+
super().__init__(ip_addr, port)
15+
self.url = f"http://{self.ip}:{self.port}/"
16+
self.passwds = [passwd, settings.get("default_dragonball_passwd")]
17+
self.command_format = Template("cgi-bin/${cmd}.cgi")
18+
19+
self._initialize_session()
20+
21+
def _initialize_session(self) -> None:
22+
return super()._initialize_session()
23+
24+
def _authenticate_session(self) -> None:
25+
return super()._authenticate_session()
26+
27+
def run_command(
28+
self,
29+
method: str,
30+
command: str,
31+
params: Optional[Dict[str, str]] = None,
32+
payload: Optional[Dict[str, Any]] = None,
33+
data: Optional[Dict[str, Any]] = None
34+
) -> Any:
35+
path = self.command_format.substitute(cmd=command)
36+
res = self._do_http(method, path, params=params, payload=payload, data=data)
37+
try:
38+
resj = res.json()
39+
except requests.exceptions.JSONDecodeError:
40+
resj = {}
41+
return resj
42+
43+
def get_mac_addr(self) -> str:
44+
return super().get_mac_addr()
45+
46+
def get_system_info(self) -> dict:
47+
return self.run_command("GET", "get_system_info")
48+
49+
def get_blink_status(self) -> bool:
50+
return super().get_blink_status()
51+
52+
def blink(self, enabled: bool) -> None:
53+
return super().blink(enabled)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from typing import Dict, Any
2+
3+
from ...parser import Parser
4+
5+
class DragonballParser(Parser):
6+
def __init__(self, target: Dict[str, str]):
7+
super().__init__(target)
8+
9+
def parse_serial(self, obj: Dict[str, Any]) -> None:
10+
if "number" in obj:
11+
self.target["serial"] = obj["number"]
12+
13+
def parse_subtype(self, obj: Dict[str, Any]) -> None:
14+
if "miner_model" in obj:
15+
self.target["subtype"] = obj["miner_model"]
16+
17+
def parse_algorithm(self, obj: Dict[str, Any]) -> None:
18+
return super().parse_algorithm(obj)
19+
20+
def parse_firmware(self, obj: Dict[str, Any]) -> None:
21+
if "swv" in obj:
22+
self.target["firmware"] = obj["swv"]
23+
24+
def parse_platform(self, obj: Dict[str, Any]) -> None:
25+
return super().parse_platform(obj)
26+
27+
def parse_system_info(self, obj: Dict[str, Any]) -> None:
28+
self.parse_serial(obj)
29+
self.parse_subtype(obj)
30+
self.parse_firmware(obj)

src/mod/api/settings/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"default_volcminer_passwd": "ltc@dog",
1818
"default_sealminer_passwd": "seal",
1919
"default_elphapex_passwd": "root",
20+
"default_dragonball_passwd": "dragonball",
2021
}
2122

2223

src/mod/lm/listenermanager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def append_listener(self, port: int):
2828
def start_listeners(self, conf: QButtonGroup):
2929
for listenFor in conf.buttons():
3030
match conf.id(listenFor):
31-
case 1 | 4: # antminer | volcminer
31+
case 1 | 4 | 8: # antminer | volcminer / dragonball
3232
if listenFor.isChecked():
3333
self.append_listener(14235)
3434
case 2: # iceriver

src/ui/MainWindow.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ def setupUi(self, MainWindow):
345345

346346
self.gridLayout.addWidget(self.checkListenSealminer, 0, 2, 1, 1)
347347

348+
self.checkListenDragonball = QCheckBox(self.groupAdditional)
349+
self.checkListenDragonball.setObjectName(u"checkListenDragonball")
350+
self.checkListenDragonball.setMaximumSize(QSize(100, 22))
351+
352+
self.gridLayout.addWidget(self.checkListenDragonball, 1, 1, 1, 1)
353+
348354

349355
self.verticalLayout_11.addWidget(self.groupAdditional)
350356

@@ -926,6 +932,10 @@ def retranslateUi(self, MainWindow):
926932
self.checkListenSealminer.setToolTip(QCoreApplication.translate("MainWindow", u"Enable listening for Sealminers", None))
927933
#endif // QT_CONFIG(tooltip)
928934
self.checkListenSealminer.setText(QCoreApplication.translate("MainWindow", u"Sealminer", None))
935+
#if QT_CONFIG(tooltip)
936+
self.checkListenDragonball.setToolTip(QCoreApplication.translate("MainWindow", u"Enable listening for Dragonball miners", None))
937+
#endif // QT_CONFIG(tooltip)
938+
self.checkListenDragonball.setText(QCoreApplication.translate("MainWindow", u"Dragonball", None))
929939
self.configTabs.setTabText(self.configTabs.indexOf(self.tabGeneral), QCoreApplication.translate("MainWindow", u"General", None))
930940
#if QT_CONFIG(tooltip)
931941
self.configTabs.setTabToolTip(self.configTabs.indexOf(self.tabGeneral), QCoreApplication.translate("MainWindow", u"General Settings", None))

src/ui/forms/mainwindow.ui

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,22 @@
773773
</property>
774774
</widget>
775775
</item>
776+
<item row="1" column="1">
777+
<widget class="QCheckBox" name="checkListenDragonball">
778+
<property name="maximumSize">
779+
<size>
780+
<width>100</width>
781+
<height>22</height>
782+
</size>
783+
</property>
784+
<property name="toolTip">
785+
<string>Enable listening for Dragonball miners</string>
786+
</property>
787+
<property name="text">
788+
<string>Dragonball</string>
789+
</property>
790+
</widget>
791+
</item>
776792
</layout>
777793
</widget>
778794
</item>

0 commit comments

Comments
 (0)