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