Skip to content

Commit dba19ef

Browse files
committed
Various changes for usability and easier setup
1. The bot now uses a configuration file instead of parsing command line arguments. 2. The bot has a wizard to auto-create the configuration if it doesn't exist. 3. Instead of saying "Bot ready" to the owner, the message is printed on the console.
1 parent 77b002a commit dba19ef

File tree

5 files changed

+144
-8
lines changed

5 files changed

+144
-8
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
/config.json
12
node_modules/
23
npm-debug.log

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ To start the bot:
3939
node server
4040
~~~
4141

42-
If you receive a `Bot ready.` message, it's up and running.
42+
The first time you run it, it will ask you some questions and create
43+
the configuration file automatically: `config.json`. You can also
44+
write it manually, see `config.example.json`.
45+
46+
When started it will print a `Bot ready.` message when it's up and running.
4347
For convenience, you might want to talk to the BotFather and set the
4448
command list to the contents of `commands.txt`.
4549

config.example.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"authToken": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11",
3+
"owner": 34509246,
4+
}

lib/wizard.js

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
var readline = require("readline");
2+
var botgram = require("botgram");
3+
var fs = require("fs");
4+
var util = require("util");
5+
6+
// Wizard functions
7+
8+
function stepAuthToken(rl, config) {
9+
return question(rl, "First, enter your bot API token: ")
10+
.then(function (token) {
11+
token = token.trim();
12+
//if (!/^\d{5,}:[a-zA-Z0-9_+/-]{20,}$/.test(token))
13+
// throw new Error();
14+
config.authToken = token;
15+
return createBot(token);
16+
}).catch(function (err) {
17+
console.error("Invalid token was entered, please try again.\n%s\n", err);
18+
return stepAuthToken(rl, config);
19+
});
20+
}
21+
22+
function stepOwner(rl, config, getNextMessage) {
23+
console.log("Waiting for a message...");
24+
return getNextMessage().then(function (msg) {
25+
var prompt = util.format("Should %s «%s» (%s) be the bot's owner? [y/n]: ", msg.chat.type, msg.chat.name, msg.chat.id);
26+
return question(rl, prompt)
27+
.then(function (answer) {
28+
console.log();
29+
answer = answer.trim().toLowerCase();
30+
if (answer === "y" || answer === "yes")
31+
config.owner = msg.chat.id;
32+
else
33+
return stepOwner(rl, config, getNextMessage);
34+
});
35+
});
36+
}
37+
38+
function configWizard(options) {
39+
var rl = readline.createInterface({
40+
input: process.stdin,
41+
output: process.stdout,
42+
});
43+
var config = {};
44+
var bot = null;
45+
46+
return Promise.resolve()
47+
.then(function () {
48+
return stepAuthToken(rl, config);
49+
})
50+
.then(function (bot_) {
51+
bot = bot_;
52+
console.log("\nNow, talk to me so I can discover your Telegram user:\n%s\n", bot.link());
53+
})
54+
.then(function () {
55+
var getNextMessage = getPromiseFactory(bot);
56+
return stepOwner(rl, config, getNextMessage);
57+
})
58+
.then(function () {
59+
console.log("All done, writing the configuration...");
60+
var contents = JSON.stringify(config, null, 4) + "\n";
61+
return writeFile(options.configFile, contents);
62+
})
63+
64+
.catch(function (err) {
65+
console.error("Error, wizard crashed:\n%s", err.stack);
66+
process.exit(1);
67+
})
68+
.then(function () {
69+
rl.close();
70+
if (bot) bot.stop();
71+
process.exit(0);
72+
});
73+
}
74+
75+
// Promise utilities
76+
77+
function question(interface, query) {
78+
return new Promise(function (resolve, reject) {
79+
interface.question(query, resolve);
80+
});
81+
}
82+
83+
function writeFile(file, contents) {
84+
return new Promise(function (resolve, reject) {
85+
fs.writeFile(file, contents, "utf-8", function (err) {
86+
if (err) reject(err);
87+
else resolve();
88+
});
89+
});
90+
}
91+
92+
function createBot(token) {
93+
return new Promise(function (resolve, reject) {
94+
var bot = botgram(token);
95+
bot.on("error", function (err) {
96+
bot.stop();
97+
reject(err);
98+
});
99+
bot.on("ready", resolve.bind(this, bot));
100+
});
101+
}
102+
103+
function getPromiseFactory(bot) {
104+
var resolveCbs = [];
105+
bot.message(function (msg, reply, next) {
106+
if (!msg.queued) {
107+
resolveCbs.forEach(function (resolve) {
108+
resolve(msg);
109+
});
110+
resolveCbs = [];
111+
}
112+
next();
113+
});
114+
return function () {
115+
return new Promise(function (resolve, reject) {
116+
resolveCbs.push(resolve);
117+
});
118+
};
119+
}
120+
121+
122+
123+
exports.configWizard = configWizard;

server.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,17 @@ var utils = require("./lib/utils");
1212
var Command = require("./lib/command").Command;
1313
var Editor = require("./lib/editor").Editor;
1414

15-
if (process.argv.length !== 4) {
16-
console.error("Usage: " + process.argv.slice(0,2).join(" ") + " <auth token> <ID>");
17-
process.exit(1);
15+
var CONFIG_FILE = path.join(__dirname, "config.json");
16+
try {
17+
var config = require(CONFIG_FILE);
18+
} catch (e) {
19+
console.error("Couldn't load the configuration file, starting the wizard.\n");
20+
require("./lib/wizard").configWizard({ configFile: CONFIG_FILE });
21+
return;
1822
}
1923

20-
var bot = botgram(process.argv[2]);
21-
var owner = parseInt(process.argv[3]);
24+
var bot = botgram(config.authToken);
25+
var owner = config.owner;
2226
var tokens = {};
2327
var granted = {};
2428
var contexts = {};
@@ -30,8 +34,8 @@ bot.on("updateError", function (err) {
3034
console.error("Error when updating:", err);
3135
});
3236

33-
bot.on("ready", function () {
34-
bot.reply(owner).silent().text("Bot ready.");
37+
bot.on("synced", function () {
38+
console.log("Bot ready.");
3539
});
3640

3741

0 commit comments

Comments
 (0)