mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
telegram bot
This commit is contained in:
+2
-1
@@ -3,4 +3,5 @@ BITCOIN_RPC_USER=
|
|||||||
BITCOIN_RPC_PASSWORD=
|
BITCOIN_RPC_PASSWORD=
|
||||||
BITCOIN_RPC_PORT=8332
|
BITCOIN_RPC_PORT=8332
|
||||||
BITCOIN_RPC_TIMEOUT=10000
|
BITCOIN_RPC_TIMEOUT=10000
|
||||||
PORT=3333
|
PORT=3333
|
||||||
|
TELEGRAM_BOT_TOKEN=
|
||||||
Generated
+1252
-23
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
|||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"merkle-lib": "^2.0.10",
|
"merkle-lib": "^2.0.10",
|
||||||
|
"node-telegram-bot-api": "^0.61.0",
|
||||||
"promise-socket": "^7.0.0",
|
"promise-socket": "^7.0.0",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rpc-bitcoin": "^2.0.0",
|
"rpc-bitcoin": "^2.0.0",
|
||||||
@@ -49,6 +50,7 @@
|
|||||||
"@types/express": "^4.17.13",
|
"@types/express": "^4.17.13",
|
||||||
"@types/jest": "29.5.1",
|
"@types/jest": "29.5.1",
|
||||||
"@types/node": "18.16.12",
|
"@types/node": "18.16.12",
|
||||||
|
"@types/node-telegram-bot-api": "^0.61.6",
|
||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||||
"@typescript-eslint/parser": "^5.0.0",
|
"@typescript-eslint/parser": "^5.0.0",
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
import { TrackedEntity } from '../utils/TrackedEntity.entity';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class TelegramSubscriptionsEntity extends TrackedEntity {
|
||||||
|
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column({ length: 62, type: 'varchar' })
|
||||||
|
address: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
telegramChatId: number;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Global, Module } from '@nestjs/common';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
|
import { TelegramSubscriptionsEntity } from './telegram-subscriptions.entity';
|
||||||
|
import { TelegramSubscriptionsService } from './telegram-subscriptions.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
imports: [TypeOrmModule.forFeature([TelegramSubscriptionsEntity])],
|
||||||
|
providers: [TelegramSubscriptionsService],
|
||||||
|
exports: [TypeOrmModule, TelegramSubscriptionsService],
|
||||||
|
})
|
||||||
|
export class TelegramSubscriptionsModule { }
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
|
import { TelegramSubscriptionsEntity } from './telegram-subscriptions.entity';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TelegramSubscriptionsService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(TelegramSubscriptionsEntity)
|
||||||
|
private telegramSubscriptions: Repository<TelegramSubscriptionsEntity>
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSubscriptions(address: string) {
|
||||||
|
return await this.telegramSubscriptions.find({ where: { address } })
|
||||||
|
}
|
||||||
|
|
||||||
|
public async saveSubscription(chatId: number, address: string) {
|
||||||
|
return await this.telegramSubscriptions.save({
|
||||||
|
telegramChatId: chatId,
|
||||||
|
address
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -9,15 +9,18 @@ import { ClientController } from './controllers/client/client.controller';
|
|||||||
import { AddressSettingsModule } from './ORM/address-settings/address-settings.module';
|
import { AddressSettingsModule } from './ORM/address-settings/address-settings.module';
|
||||||
import { ClientStatisticsModule } from './ORM/client-statistics/client-statistics.module';
|
import { ClientStatisticsModule } from './ORM/client-statistics/client-statistics.module';
|
||||||
import { ClientModule } from './ORM/client/client.module';
|
import { ClientModule } from './ORM/client/client.module';
|
||||||
|
import { TelegramSubscriptionsModule } from './ORM/telegram-subscriptions/telegram-subscriptions.module';
|
||||||
import { BitcoinRpcService } from './services/bitcoin-rpc.service';
|
import { BitcoinRpcService } from './services/bitcoin-rpc.service';
|
||||||
import { BlockTemplateService } from './services/block-template.service';
|
import { BlockTemplateService } from './services/block-template.service';
|
||||||
import { CleanupService } from './services/cleanup.service';
|
import { CleanupService } from './services/cleanup.service';
|
||||||
import { StratumV1Service } from './services/stratum-v1.service';
|
import { StratumV1Service } from './services/stratum-v1.service';
|
||||||
|
import { TelegramService } from './services/telegram.service';
|
||||||
|
|
||||||
const ORMModules = [
|
const ORMModules = [
|
||||||
ClientStatisticsModule,
|
ClientStatisticsModule,
|
||||||
ClientModule,
|
ClientModule,
|
||||||
AddressSettingsModule
|
AddressSettingsModule,
|
||||||
|
TelegramSubscriptionsModule
|
||||||
]
|
]
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@@ -39,9 +42,9 @@ const ORMModules = [
|
|||||||
AddressController
|
AddressController
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
||||||
CleanupService,
|
CleanupService,
|
||||||
StratumV1Service,
|
StratumV1Service,
|
||||||
|
TelegramService,
|
||||||
BitcoinRpcService,
|
BitcoinRpcService,
|
||||||
BlockTemplateService
|
BlockTemplateService
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import * as crypto from 'crypto';
|
|||||||
import { Socket } from 'net';
|
import { Socket } from 'net';
|
||||||
import PromiseSocket from 'promise-socket';
|
import PromiseSocket from 'promise-socket';
|
||||||
import { combineLatest, firstValueFrom, interval, startWith, takeUntil } from 'rxjs';
|
import { combineLatest, firstValueFrom, interval, startWith, takeUntil } from 'rxjs';
|
||||||
|
import { TelegramService } from 'src/services/telegram.service';
|
||||||
|
|
||||||
import { ClientStatisticsService } from '../ORM/client-statistics/client-statistics.service';
|
import { ClientStatisticsService } from '../ORM/client-statistics/client-statistics.service';
|
||||||
import { ClientEntity } from '../ORM/client/client.entity';
|
import { ClientEntity } from '../ORM/client/client.entity';
|
||||||
@@ -47,7 +48,8 @@ export class StratumV1Client extends EasyUnsubscribe {
|
|||||||
private readonly blockTemplateService: BlockTemplateService,
|
private readonly blockTemplateService: BlockTemplateService,
|
||||||
private readonly bitcoinRpcService: BitcoinRpcService,
|
private readonly bitcoinRpcService: BitcoinRpcService,
|
||||||
private readonly clientService: ClientService,
|
private readonly clientService: ClientService,
|
||||||
private readonly clientStatisticsService: ClientStatisticsService
|
private readonly clientStatisticsService: ClientStatisticsService,
|
||||||
|
private readonly telegramService: TelegramService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -345,6 +347,7 @@ export class StratumV1Client extends EasyUnsubscribe {
|
|||||||
console.log('!!! BLOCK FOUND !!!');
|
console.log('!!! BLOCK FOUND !!!');
|
||||||
const blockHex = updatedJobBlock.toHex(false);
|
const blockHex = updatedJobBlock.toHex(false);
|
||||||
this.bitcoinRpcService.SUBMIT_BLOCK(blockHex);
|
this.bitcoinRpcService.SUBMIT_BLOCK(blockHex);
|
||||||
|
await this.telegramService.notifySubscribersBlockFound(this.clientAuthorization.address);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.statistics.addSubmission(this.entity, submissionHash, this.sessionDifficulty);
|
await this.statistics.addSubmission(this.entity, submissionHash, this.sessionDifficulty);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export class BitcoinRpcService {
|
|||||||
private _newBlock$: BehaviorSubject<IMiningInfo> = new BehaviorSubject(undefined);
|
private _newBlock$: BehaviorSubject<IMiningInfo> = new BehaviorSubject(undefined);
|
||||||
public newBlock$ = this._newBlock$.pipe(filter(block => block != null));
|
public newBlock$ = this._newBlock$.pipe(filter(block => block != null));
|
||||||
|
|
||||||
constructor(configService: ConfigService) {
|
constructor(private readonly configService: ConfigService) {
|
||||||
const url = configService.get('BITCOIN_RPC_URL');
|
const url = configService.get('BITCOIN_RPC_URL');
|
||||||
const user = configService.get('BITCOIN_RPC_USER');
|
const user = configService.get('BITCOIN_RPC_USER');
|
||||||
const pass = configService.get('BITCOIN_RPC_PASSWORD');
|
const pass = configService.get('BITCOIN_RPC_PASSWORD');
|
||||||
@@ -65,7 +65,6 @@ export class BitcoinRpcService {
|
|||||||
console.log(`BLOCK SUBMISSION RESPONSE: ${res}`);
|
console.log(`BLOCK SUBMISSION RESPONSE: ${res}`);
|
||||||
console.log(hexdata);
|
console.log(hexdata);
|
||||||
console.log(JSON.stringify(res));
|
console.log(JSON.stringify(res));
|
||||||
process.exit();
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(`BLOCK SUBMISSION RESPONSE ERROR: ${e}`);
|
console.log(`BLOCK SUBMISSION RESPONSE ERROR: ${e}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { ClientService } from '../ORM/client/client.service';
|
|||||||
import { BitcoinRpcService } from './bitcoin-rpc.service';
|
import { BitcoinRpcService } from './bitcoin-rpc.service';
|
||||||
import { BlockTemplateService } from './block-template.service';
|
import { BlockTemplateService } from './block-template.service';
|
||||||
import { StratumV1JobsService } from './stratum-v1-jobs.service';
|
import { StratumV1JobsService } from './stratum-v1-jobs.service';
|
||||||
|
import { TelegramService } from './telegram.service';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -17,7 +18,8 @@ export class StratumV1Service implements OnModuleInit {
|
|||||||
private readonly bitcoinRpcService: BitcoinRpcService,
|
private readonly bitcoinRpcService: BitcoinRpcService,
|
||||||
private readonly blockTemplateService: BlockTemplateService,
|
private readonly blockTemplateService: BlockTemplateService,
|
||||||
private readonly clientService: ClientService,
|
private readonly clientService: ClientService,
|
||||||
private readonly clientStatisticsService: ClientStatisticsService
|
private readonly clientStatisticsService: ClientStatisticsService,
|
||||||
|
private readonly telegramService: TelegramService
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +37,16 @@ export class StratumV1Service implements OnModuleInit {
|
|||||||
|
|
||||||
const promiseSocket = new PromiseSocket(s);
|
const promiseSocket = new PromiseSocket(s);
|
||||||
|
|
||||||
const client = new StratumV1Client(promiseSocket, new StratumV1JobsService(), this.blockTemplateService, this.bitcoinRpcService, this.clientService, this.clientStatisticsService);
|
const client = new StratumV1Client(
|
||||||
|
promiseSocket,
|
||||||
|
new StratumV1JobsService(),
|
||||||
|
this.blockTemplateService,
|
||||||
|
this.bitcoinRpcService,
|
||||||
|
this.clientService,
|
||||||
|
this.clientStatisticsService,
|
||||||
|
this.telegramService
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const clientCount = await this.clientService.connectedClientCount();
|
const clientCount = await this.clientService.connectedClientCount();
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { validate } from 'bitcoin-address-validation';
|
||||||
|
import * as TelegramBot from 'node-telegram-bot-api';
|
||||||
|
import { TelegramSubscriptionsService } from 'src/ORM/telegram-subscriptions/telegram-subscriptions.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TelegramService implements OnModuleInit {
|
||||||
|
|
||||||
|
private bot: TelegramBot;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
private readonly telegramSubscriptionsService: TelegramSubscriptionsService
|
||||||
|
) {
|
||||||
|
const token: string = this.configService.get('TELEGRAM_BOT_TOKEN');
|
||||||
|
if (token.length < 1) {
|
||||||
|
console.log('No Telegram token found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.bot = new TelegramBot(token, { polling: true });
|
||||||
|
console.log('Telegram bot init');
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async onModuleInit(): Promise<void> {
|
||||||
|
|
||||||
|
this.bot.onText(/\/subscribe/, async (msg) => {
|
||||||
|
const address = msg.text.split('/subscribe ')[1];
|
||||||
|
if (validate(address) == false) {
|
||||||
|
this.bot.sendMessage(msg.chat.id, "Invalid address.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.telegramSubscriptionsService.saveSubscription(msg.chat.id, address);
|
||||||
|
this.bot.sendMessage(msg.chat.id, "Subscribed!");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bot.onText(/\/start/, (msg) => {
|
||||||
|
this.bot.sendMessage(msg.chat.id, "Welcome to the public-pool bot. /subscribe <address> to get notified.");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bot.on('message', (msg) => {
|
||||||
|
console.log(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async notifySubscribersBlockFound(address: string) {
|
||||||
|
const subscribers = await this.telegramSubscriptionsService.getSubscriptions(address);
|
||||||
|
subscribers.forEach(subscriber => {
|
||||||
|
this.bot.sendMessage(subscriber.telegramChatId, 'You found a block!');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user