235 lines
7.3 KiB
JavaScript
235 lines
7.3 KiB
JavaScript
const Twit = require("twit");
|
||
const config = require("config");
|
||
const winston = require("winston");
|
||
require("winston-daily-rotate-file");
|
||
const Client = require("bitcoin-core");
|
||
const lbry = new Client({
|
||
username: config.get("lbrycrd.username"),
|
||
password: config.get("lbrycrd.password"),
|
||
port: config.get("lbrycrd.port")
|
||
});
|
||
const logger = winston.createLogger({
|
||
level: "info",
|
||
format: winston.format.json(),
|
||
transports: [
|
||
new winston.transports.DailyRotateFile({
|
||
filename: "tipbot-%DATE%.log",
|
||
dirname: "./logs",
|
||
datePattern: "YYYY-MM-DD-HH",
|
||
zippedArchive: true,
|
||
maxSize: "20m",
|
||
maxFiles: "14d"
|
||
}),
|
||
new winston.transports.Console({
|
||
format: winston.format.simple(),
|
||
level: "debug"
|
||
})
|
||
]
|
||
});
|
||
|
||
const T = new Twit({
|
||
consumer_key: config.get("twitter.consumer_key"),
|
||
consumer_secret: config.get("twitter.consumer_secret"),
|
||
access_token: config.get("twitter.access_token"),
|
||
access_token_secret: config.get("twitter.access_token_secret"),
|
||
timeout_ms: 60 * 1000, // optional HTTP request timeout to apply to all requests.
|
||
strictSSL: true // optional - requires SSL certificates to be valid.
|
||
});
|
||
|
||
const stream = T.stream("statuses/filter", { track: config.get("bot.handle") });
|
||
logger.info("Started LBRY twitter tipbot.");
|
||
|
||
stream.on("tweet", function(tweet) {
|
||
if(tweet.user.screen_name === config.get("bot.handle").substring(1)) return;
|
||
let msg = checkTrunc(tweet);
|
||
msg = msg.replace(/[\n\\]/g, " ").slice(msg.lastIndexOf(config.get("bot.handle"))).split(" ");
|
||
if (msg.length >= 2) checkTweet(tweet, msg);
|
||
});
|
||
|
||
function checkTweet(tweet, msg) {
|
||
switch (msg[1]) {
|
||
case "help":
|
||
doHelp(tweet, msg);
|
||
break;
|
||
case "balance":
|
||
doBalance(tweet, msg);
|
||
break;
|
||
case "deposit":
|
||
doDeposit(tweet, msg);
|
||
break;
|
||
case "withdraw":
|
||
doWithdraw(tweet, msg);
|
||
break;
|
||
case "tip":
|
||
doTip(tweet, msg);
|
||
break;
|
||
case "terms":
|
||
doTerms(tweet, msg);
|
||
break;
|
||
case "lbryian":
|
||
logger.info("Got a command with the old format, handling it...");
|
||
checkTweet(tweet, msg.splice(1));
|
||
break;
|
||
}
|
||
}
|
||
|
||
async function doHelp(tweet, msg) {
|
||
try {
|
||
let post = await T.post("statuses/update", {
|
||
status:
|
||
`@${tweet.user.screen_name} `+
|
||
`Call commands with: ${config.get("bot.handle")} + \n` +
|
||
"help - Shows this command.\n" +
|
||
"balance - Get your balance.\n" +
|
||
"deposit - Get address for your deposits.\n" +
|
||
"withdraw ADDRESS AMOUNT - Withdraw AMOUNT credits to ADDRESS.\n" +
|
||
"tip USER AMOUNT - Tip USER AMOUNT.\n"+
|
||
"terms - Sends the TOS.",
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
logger.info(
|
||
`Sent help to ${tweet.user.screen_name}, tweet id: ${tweet.id_str}`
|
||
);
|
||
} catch (e) {
|
||
logger.error(e);
|
||
}
|
||
}
|
||
async function doTerms(tweet, msg){
|
||
// ADD terms
|
||
await T.post("statuses/update", {
|
||
status:
|
||
`@${tweet.user.screen_name} `+
|
||
"There are no fees to use this bot except the automatic daemon fee. \n"+
|
||
"Under no circumstances shall LBRY Inc. be held responsible for lost, stolen or misdirected funds.",
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
}
|
||
async function doBalance(tweet, msg) {
|
||
try {
|
||
const balance = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); // Amount of confirms before we can use it.
|
||
const post = await T.post("statuses/update", {
|
||
in_reply_to_status_id: tweet.id_str,
|
||
status: `@${tweet.user.screen_name} You have ${balance} LBC.`
|
||
});
|
||
logger.info(
|
||
`Sent balance command to ${tweet.user.screen_name}, tweet id: ${
|
||
tweet.id_str
|
||
}`
|
||
);
|
||
} catch (e) {
|
||
logger.error(e);
|
||
}
|
||
}
|
||
async function doDeposit(tweet, msg) {
|
||
try {
|
||
const post = await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} Your deposit address is ${await getAddress(id(tweet.user.id_str))}.`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
logger.info(
|
||
`Sent deposit address to ${tweet.user.screen_name}, tweet id: ${
|
||
tweet.id_str
|
||
}`
|
||
);
|
||
} catch (e) {
|
||
logger.error(e);
|
||
}
|
||
}
|
||
async function doWithdraw(tweet, msg) {
|
||
try {
|
||
if (msg.length < 4) return doHelp(tweet, msg);
|
||
let address = msg[2];
|
||
let amount = getValidatedAmount(msg[3]);
|
||
if (amount === null) {
|
||
return await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} I don´t know how to withdraw that many credits...`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
}
|
||
let txId = await lbry.sendFrom(id(tweet.user.id_str), address, amount);
|
||
await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
logger.info(
|
||
`User ${
|
||
tweet.user.screen_name
|
||
} withdraw ${amount} LBC to ${address}, tweet id: ${tweet.id_str}`
|
||
);
|
||
} catch (e) {
|
||
logger.error(e);
|
||
}
|
||
}
|
||
async function doTip(tweet, msg) {
|
||
try {
|
||
if (msg.length < 3) {
|
||
return doHelp(tweet, msg);
|
||
}
|
||
const amount = getValidatedAmount(msg[3]);
|
||
if (amount === null) {
|
||
return await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} I don´t know how to tip that many credits...`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
}
|
||
const userToTip = tweet.entities.user_mentions.find(u => `@${u.screen_name}` === msg[2]).id_str;
|
||
let tipToAddress = await getAddress(id(userToTip)) // Call this to ensure user has an account.
|
||
if (userToTip === null) {
|
||
return await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} I could not find that user...`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
}
|
||
const balanceFromUser = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms"));
|
||
if (balanceFromUser < amount) {
|
||
return await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} You tried tipping more than you have! You are ${amount-balanceFromUser} LBC short.`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
}
|
||
const txId = await lbry.sendFrom(id(tweet.user.id_str), tipToAddress, Number(amount), 1);
|
||
await T.post("statuses/update", {
|
||
status: `@${tweet.user.screen_name} Tipped ${
|
||
msg[2]
|
||
} ${amount} LBC! \nTransaction: ${txLink(txId)} \nSee https://lbry.io/faq/tipbot-twitter for more information.`,
|
||
in_reply_to_status_id: tweet.id_str
|
||
});
|
||
logger.info(
|
||
`@${tweet.user.screen_name}(${tweet.user.id_str}) tipped ${
|
||
msg[2]
|
||
}(${userToTip}) ${amount} LBC.`
|
||
);
|
||
} catch (e) {
|
||
logger.error(e);
|
||
}
|
||
}
|
||
|
||
async function getAddress(userId) {
|
||
try {
|
||
let uAddresses = await lbry.getAddressesByAccount(userId);
|
||
if (uAddresses.length > 0) return uAddresses[0];
|
||
let nAddress = await lbry.getNewAddress(userId);
|
||
return nAddress;
|
||
} catch (e) {
|
||
logger.error(e);
|
||
}
|
||
}
|
||
|
||
function getValidatedAmount(amount) {
|
||
amount = amount.trim();
|
||
if (amount.toLowerCase().endsWith("lbc")) {
|
||
amount = amount.substring(0, amount.length - 3);
|
||
}
|
||
return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null;
|
||
}
|
||
function txLink(txId) {
|
||
return `https://explorer.lbry.io/tx/${txId}`;
|
||
}
|
||
function checkTrunc(tweet) {
|
||
if (tweet.truncated) return tweet.extended_tweet.full_text;
|
||
return tweet.text;
|
||
}
|
||
|
||
function id(usrId){
|
||
return `t-${usrId}`;
|
||
}
|