improve error-checking and add username to some responses

Previously clippy was left in an unresponsive state if an authentication error occured, or in some cases if the remote server dropped the connection without sending a close() message. Clippy now terminates the socket connection on every connection error or authentication error, waits 5 seconds, and tries again.

Also added username to the response function, and added a couple of extra responses.
This commit is contained in:
Hugh Rundle 2021-07-09 18:48:15 +10:00
parent 0ba65f833c
commit e5728006bc

View file

@ -26,8 +26,14 @@ const headers = {
'Authorization' : `Bearer ${access_token}` 'Authorization' : `Bearer ${access_token}`
} }
function resetConnection(socket) {
terminate(socket)
console.log(`waiting after error`)
setTimeout( function() { listen() }, 5000)
}
// set up bot account with correct settings // set up bot account with correct settings
function initiateSettings() { function initiateSettings(socket) {
let account = { let account = {
locked: false, locked: false,
@ -40,37 +46,42 @@ function initiateSettings() {
return axios.patch(`https://${domain}/api/v1/accounts/update_credentials`, account, { headers: headers }) return axios.patch(`https://${domain}/api/v1/accounts/update_credentials`, account, { headers: headers })
.catch( err => { .catch( err => {
console.error('ERROR applying bot user settings: ', err.message) console.error('ERROR applying bot user settings: ', err.message)
terminate(socket)
}) })
} }
// return random suggestion string // return random suggestion string
function suggestion() { function suggestion(username) {
const n = crypto.randomInt(6) const n = crypto.randomInt(8)
switch(n) { switch(n) {
case 0: case 0:
return 'How about logging off instead?'; return 'How about logging off instead?';
case 1: case 1:
return 'Would you like to delete your toot?'; return `Would you like to delete your toot, ${username}?`;
case 2: case 2:
return 'Can I help you take a walk outside?'; return 'Can I help you take a walk outside?';
case 3: case 3:
return 'You may like to reconsider your life choices.'; return 'You may like to reconsider your life choices.';
case 4: case 4:
return 'Why not try looking at #CatsOfInstagram instead?'; return 'Why not try looking at #CatsOfMastodon instead?';
case 5: case 5:
return `You're better than this, come on.`; return `Come on ${username}, we've talked about this.`;
case 6:
return `You should go look at some trees. Trees are calming`;
case 7:
return `I'm not angry. I'm just very disappointed.`;
} }
} }
// send a message when someone toots about the topic // send a message when someone toots about the topic
function sendResponse(rip, user) { function sendResponse(rid, user, username) {
let payload = { let payload = {
'status' : `@${user} It looks like you're posting about '${topic}'. ${suggestion()}`, 'status' : `@${user} It looks like you're posting about '${topic}'. ${suggestion(username)}`,
'spoiler_text' : topic, 'spoiler_text' : topic,
'in_reply_to_id' : rip, 'in_reply_to_id' : rid,
} }
axios.post(`https://${domain}/api/v1/statuses`, payload, { headers: headers }) axios.post(`https://${domain}/api/v1/statuses`, payload, { headers: headers })
@ -108,14 +119,25 @@ function filterMentions(text, mentions) {
// STREAMING USER TIMELINE // STREAMING USER TIMELINE
// This is where the action is! // This is where the action is!
// *********************** // ***********************
function terminate(socket) {
console.error(`Terminating connection...`)
socket.terminate()
console.log(`Terminated`)
}
function listen() {
console.log(`Listening...`)
const ws = new WebSocket(`wss://${domain}/api/v1/streaming?access_token=${access_token}&stream=user`) const ws = new WebSocket(`wss://${domain}/api/v1/streaming?access_token=${access_token}&stream=user`)
// make sure bot is set up correctly each time it starts // make sure bot is set up correctly each time it starts
initiateSettings() initiateSettings(ws)
// errors // errors
ws.on('error', err => { ws.on('error', err => {
console.error(`WebSocket error: ${err.message}`) console.error(`WebSocket error: ${err.message}`)
resetConnection(ws)
}) })
// check updates and notifications in the stream // check updates and notifications in the stream
@ -149,25 +171,28 @@ ws.on('message', msg => {
// updates (posts) // updates (posts)
if (packet.event == 'update') { if (packet.event == 'update') {
let rip = data.id let rid = data.id
let user = data.account.acct let user = data.account.acct
let username = data.account.username
// get just the account names (@name@domain.tld) // get just the account names (@name@domain.tld)
let mentions = data.mentions.map( mention => mention.acct) let mentions = data.mentions.map( mention => mention.acct)
// exclude own toots and @mentions to avoid an infinite loops // exclude own toots and @mentions to avoid an infinite loops
if (data.account.username !== clippy && !mentions.includes(clippy)) { if (username !== clippy && !mentions.includes(clippy)) {
// get rid of mentions in case topic is within a username // get rid of mentions in case topic is within a username
let text = filterMentions(data.content, mentions) let text = filterMentions(data.content, mentions)
if ( text.toLowerCase().includes(topic) ) { if ( text.toLowerCase().includes(topic) ) {
sendResponse(rip, user) sendResponse(rid, user, username)
} }
else if (data.spoiler_text.toLowerCase().includes(topic)) { else if (data.spoiler_text.toLowerCase().includes(topic)) {
sendResponse(rip, user) sendResponse(rid, user, username)
} }
else if (data.tags.map(tag => tag.name.toLowerCase()).includes(topic)) { else if (data.tags.map(tag => tag.name.toLowerCase()).includes(topic)) {
sendResponse(rip, user) sendResponse(rid, user, username)
} }
} }
} }
}) })
}
// let's go
listen()