added connectivity between SP and PK for fronting.
This commit is contained in:
commit
8a63bee22b
4 changed files with 239 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/SimplyAPI
|
||||
/test.js
|
||||
/node_modules
|
||||
/.vscode
|
||||
config.json
|
||||
package-lock.json
|
||||
77
WebsocketClient.js
Normal file
77
WebsocketClient.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
const WebSocket = require('ws');
|
||||
const timestamp = () => new Date().toISOString().replace('T', ' ').substr(0, 19);
|
||||
|
||||
function WebSocketClient(url) {
|
||||
let client;
|
||||
let timeout;
|
||||
let connecting = false;
|
||||
let backoff = 250;
|
||||
const init = () => {
|
||||
console.error(timestamp(), '::SimplyWS:: connecting');
|
||||
connecting = false;
|
||||
if (client !== undefined) {
|
||||
client.removeAllListeners();
|
||||
}
|
||||
client = new WebSocket(url);
|
||||
const heartbeat = () => {
|
||||
if (timeout !== undefined) {
|
||||
clearTimeout(timeout);
|
||||
timeout = undefined;
|
||||
}
|
||||
timeout = setTimeout(() => client.terminate(), 35000);
|
||||
};
|
||||
client.on('ping', () => {
|
||||
console.log(timestamp(), '::SimplyWS:: pinged');
|
||||
heartbeat();
|
||||
});
|
||||
client.on('open', (e) => {
|
||||
if (typeof this.onOpen === 'function') {
|
||||
this.onOpen();
|
||||
} else {
|
||||
console.log(timestamp(), '::SimplyWS:: opened');
|
||||
console.log(e);
|
||||
}
|
||||
heartbeat();
|
||||
});
|
||||
client.on('message', (e) => {
|
||||
if (typeof this.onMessage === 'function') {
|
||||
this.onMessage(e);
|
||||
} else {
|
||||
console.log(timestamp(), '::SimplyWS:: messaged');
|
||||
}
|
||||
heartbeat();
|
||||
});
|
||||
client.on('close', (e) => {
|
||||
if (e.code !== 1000) {
|
||||
if (connecting === false) { // abnormal closure
|
||||
backoff = backoff === 8000 ? 250 : backoff * 2;
|
||||
setTimeout(() => init(), backoff);
|
||||
connecting = true;
|
||||
}
|
||||
} else if (typeof this.onClose === 'function') {
|
||||
this.onClose();
|
||||
} else {
|
||||
console.error(timestamp(), '::SimplyWS:: closed');
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
client.on('error', (e) => {
|
||||
if (e.code === 'ECONREFUSED') {
|
||||
if (connecting === false) { // abnormal closure
|
||||
backoff = backoff === 8000 ? 250 : backoff * 2;
|
||||
setTimeout(() => init(), backoff);
|
||||
connecting = true;
|
||||
}
|
||||
} else if (typeof this.onError === 'function') {
|
||||
this.onError(e);
|
||||
} else {
|
||||
console.error(timestamp(), '::SimplyWS : errored');
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
this.send = client.send.bind(client);
|
||||
};
|
||||
init();
|
||||
}
|
||||
|
||||
module.exports = WebSocketClient;
|
||||
134
index.js
Normal file
134
index.js
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
const axios = require('axios')
|
||||
const config = require('./config.json')
|
||||
const SAPI = require('./SimplyAPI')
|
||||
const SimplyAPI = new SAPI(config)
|
||||
|
||||
const pkUrl = 'https://api.pluralkit.me/v2'
|
||||
const pkHeader = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': config.pk_token
|
||||
}
|
||||
|
||||
let e;
|
||||
main = async () => {
|
||||
openWebSocket()
|
||||
}
|
||||
|
||||
openWebSocket = async () => {
|
||||
const WebSocketClient = require('./WebSocketClient')
|
||||
const wss = new WebSocketClient(config.socket);
|
||||
let initialPacket = { "op": "authenticate", "token": config.token }
|
||||
wss.onOpen = (_) => { wss.send(JSON.stringify(initialPacket)); }
|
||||
wss.onClose = (e) => { console.log('SimplyWS/onClose :: %s', e); e = '' }
|
||||
wss.onError = (e) => { console.log('SimplyWS/onError :: %s', e) }
|
||||
|
||||
wss.onMessage = async (raw) => {
|
||||
e = raw
|
||||
let data = JSON.parse(e)
|
||||
if (Object.keys(data).length === 0) return
|
||||
|
||||
switch (data.msg) {
|
||||
case "Successfully authenticated":
|
||||
console.log('::SimplyWS:: authenticated')
|
||||
break;
|
||||
case "Authentication violation: Token is missing or invalid. Goodbye :)":
|
||||
console.log('::SimplyWS:: invalid token, exiting..')
|
||||
process.exit(1)
|
||||
case "update":
|
||||
let response = await generateResponse(data.target, data);
|
||||
if (response) console.log('::SimplyWS:: ' + response)
|
||||
break;
|
||||
default:
|
||||
unrecognizedMessage(data.msg)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateResponse = async (target, data) => {
|
||||
let response = ''
|
||||
switch (target) {
|
||||
case 'frontHistory':
|
||||
response += 'Front has changed!'
|
||||
await asyncForEach(data.results, async (o) => {
|
||||
await SimplyAPI.findMemberById(o.content.member)
|
||||
.then(async (member) => {
|
||||
if (o.operationType == "insert") {
|
||||
let fronters = await getPKFronters()
|
||||
fronters.push(member.pkId)
|
||||
|
||||
axios.post(`${pkUrl}/systems/${config.pk_system}/switches`, JSON.stringify({"members": fronters}), {
|
||||
headers: pkHeader
|
||||
})
|
||||
.catch(err => console.error(err.toJSON().message));
|
||||
|
||||
response += '\n' + member.name + ' was added to the front.'
|
||||
return
|
||||
}
|
||||
else {
|
||||
let fronters = await getPKFronters()
|
||||
let index = fronters.indexOf(member.pkId)
|
||||
fronters.splice(index, 1)
|
||||
|
||||
axios.post(`${pkUrl}/systems/${config.pk_system}/switches`, JSON.stringify({ "members": fronters }), {
|
||||
headers: pkHeader
|
||||
})
|
||||
.catch(err => console.error(err.message));
|
||||
|
||||
response += '\n' + member.name + ' was removed from the front.'
|
||||
return
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('::SimplyWS:: Error finding member: ' + err)
|
||||
})
|
||||
})
|
||||
break;
|
||||
default:
|
||||
unknownTarget(data.target)
|
||||
break;
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
unknownTarget = (target) => {
|
||||
console.log('::SimplyWS:: Unknown update target: ' + target + '\n::SimplyWS:: Full message: ' + e)
|
||||
}
|
||||
|
||||
unrecognizedMessage = (msg) => {
|
||||
console.log('::SimplyWS:: Unrecognized message: ' + msg + '\n::SimplyWS:: Full message: ' + e)
|
||||
}
|
||||
|
||||
findMember = (who) => {
|
||||
return new Promise(function (resolve, reject) {
|
||||
SimplyAPI.findMember(who, (member) => {
|
||||
if (member) {
|
||||
resolve(member)
|
||||
} else {
|
||||
reject({"name": "Unknown member"})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
getPKFronters = async () => {
|
||||
let members = []
|
||||
let fronters = await axios.get(`${pkUrl}/systems/${config.pk_system}/fronters`, {
|
||||
headers: pkHeader
|
||||
})
|
||||
.catch(err => console.error("An error occured while getting current fronters: " + err.message))
|
||||
|
||||
fronters.data.members.forEach((key, value) => {
|
||||
members.push(key.id)
|
||||
})
|
||||
|
||||
return members
|
||||
}
|
||||
|
||||
asyncForEach = async (array, callback) => {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
22
package.json
Normal file
22
package.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "sppk",
|
||||
"version": "1.0.0",
|
||||
"description": "A tool to automatically update PluralKit with SimplyPlural data.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node .",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "padlocks",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"ajv": "^8.10.0",
|
||||
"axios": "^0.26.0",
|
||||
"pkapi.js": "^3.1.0",
|
||||
"ws": "^8.5.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bufferutil": "^4.0.6",
|
||||
"utf-8-validate": "^5.0.8"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue