Compare commits

..

No commits in common. "main" and "v1.1.0" have entirely different histories.
main ... v1.1.0

8 changed files with 29 additions and 134 deletions

View file

@ -1,2 +0,0 @@
node_modules
npm-debug.log

View file

@ -1,13 +1,10 @@
# Compatiplural # Compatiplural
url_override="https://api.apparyllis.com" url_override="https://v2.apparyllis.com"
api_version="v1" api_version="v1"
socket="wss://api.apparyllis.com/v1/socket" socket="wss://v2.apparyllis.com/v1/socket"
pk_url="https://api.pluralkit.me/v2" pk_url="https://api.pluralkit.me/v2"
token="SIMPLYPLURAL_TOKEN" token="SIMPLYPLURAL_TOKEN"
userId="abcd1234" userId="abcd1234"
pk_token= "PLURALKIT_TOKEN" pk_token= "PLURALKIT_TOKEN"
heartbeat=4500000 heartbeat=4500000
max_workers=1 max_workers=1
silence_connections=true
full_swap=false
primary_tag="primary "

2
.gitignore vendored
View file

@ -5,5 +5,3 @@ config.json
package-lock.json package-lock.json
.env .env
.vercel .vercel
docker_build.bat
docker_run.bat

View file

@ -1,16 +0,0 @@
FROM node:18
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm ci --omit=dev
# Bundle app source
COPY . .
#EXPOSE 8080
CMD [ "node", "index.js" ]

View file

@ -9,14 +9,12 @@ This project already has a Procfile set up, so it's super easy to get started. O
These can be set either in the .env file, in terminal, or in the config vars section of Heroku. These can be set either in the .env file, in terminal, or in the config vars section of Heroku.
| Setting | Default | Description | | Setting | Default | Description |
| ---------| ------- | ------------------ | | ---------| ------- | ------------------ |
| url_override | https://api.apparyllis.com | The base URL for all SimplyPlural API requests. Unless you are running your own fork of Simply Plural, you shouldn't change this. | | url_override | https://v2.apparyllis.com | The base URL for all SimplyPlural API requests. Unless you are running your own fork of Simply Plural, you shouldn't change this. |
| api_version | v1 | The target SimplyPlural API version. Unless you are running your own fork of Simply Plural, you shouldn't change this. | | api_version | v1 | The target SimplyPlural API version. Unless you are running your own fork of Simply Plural, you shouldn't change this. |
| socket | wss://api.apparyllis.com/v1/socket | The socket URL for SimplyPlural. Unless you are running your own fork of Simply Plural, you shouldn't change this. | | socket | wss://v2.apparyllis.com/v1/socket | The socket URL for SimplyPlural. Unless you are running your own fork of Simply Plural, you shouldn't change this. |
| pk_url | https://api.pluralkit.me/v2 | The base URL for all PluralKit API requests. Unless you are running your own fork of PluralKit, you shouldn't change this. | | pk_url | https://api.pluralkit.me/v2 | The base URL for all PluralKit API requests. Unless you are running your own fork of PluralKit, you shouldn't change this. |
| token | token_here | Your SimplyPlural account token. As of now, the only permission necessary is the Read permission. | | token | token_here | Your SimplyPlural account token. As of now, the only permission necessary is the Read permission. |
| userId | user_id | Your SimplyPlural account/system ID. You can find it in account info near the bottom. | | userId | user_id | Your SimplyPlural account/system ID. You can find it in account info near the bottom. |
| pk_token | pluralkit_token_here | Your PluralKit token. Get it by using `pk;token`. | | pk_token | pluralkit_token_here | Your PluralKit token. Get it by using `pk;token`. |
| heartbeat | 4500000 | The time in miliseconds before the websocket client reconnects to the websocket server. | | heartbeat | 4500000 | The time in miliseconds before the websocket client reconnects to the websocket server. |
| max_workers | 1 | Max number of workers for processing enqueued tasks. This probably shouldn't be changed. | | max_workers | 1 | Max number of workers for processing enqueued tasks. This probably shouldn't be changed. |
| silence_connections | true | Whether or not to silence the websocket connection and authentication messages. |
| full_swap | false | Determines whether to completely overwrite PluralKit's front with SimplyPlural's. No individual changes. |

View file

@ -7,7 +7,7 @@ function WebSocketClient(url) {
let connecting = false let connecting = false
let backoff = 250 let backoff = 250
const init = () => { const init = () => {
if (!process.env.silence_connections) console.error(`::SimplyWS:: [${timestamp()}] connecting`) console.error(`::SimplyWS:: [${timestamp()}] connecting`)
connecting = false connecting = false
if (client !== undefined) { if (client !== undefined) {
client.removeAllListeners() client.removeAllListeners()
@ -21,14 +21,14 @@ function WebSocketClient(url) {
timeout = setTimeout(() => client.terminate(), process.env.heartbeat || 350000) timeout = setTimeout(() => client.terminate(), process.env.heartbeat || 350000)
} }
client.on('ping', () => { client.on('ping', () => {
if (!process.env.silence_connections) console.log(`::SimplyWS:: [${timestamp()}] pinged`) console.log(`::SimplyWS:: [${timestamp()}] pinged`)
heartbeat() heartbeat()
}) })
client.on('open', (e) => { client.on('open', (e) => {
if (typeof this.onOpen === 'function') { if (typeof this.onOpen === 'function') {
this.onOpen() this.onOpen()
} else { } else {
if (!process.env.silence_connections) console.log(`::SimplyWS:: [${timestamp()}] opened`) console.log(`::SimplyWS:: [${timestamp()}] opened`)
console.log(e) console.log(e)
} }
heartbeat() heartbeat()
@ -37,7 +37,7 @@ function WebSocketClient(url) {
if (typeof this.onMessage === 'function') { if (typeof this.onMessage === 'function') {
this.onMessage(e) this.onMessage(e)
} else { } else {
if (!process.env.silence_connections) console.log(`::SimplyWS:: [${timestamp()}] messaged`) console.log(`::SimplyWS:: [${timestamp()}] messaged`)
} }
heartbeat() heartbeat()
}) })

View file

@ -50,9 +50,9 @@ async function findPrimary() {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
await Util.asyncForEach(fronters, async (fronter) => { await Util.asyncForEach(fronters, async (fronter) => {
if (fronter.content.customStatus) { if (fronter.content.customStatus) {
if (fronter.content.customStatus.toLowerCase().includes(Config.primary_tag)) { if (fronter.content.customStatus.toLowerCase().includes("primary")) {
let member = await system.getMemberById(fronter.content.member) let member = await system.getMemberById(fronter.content.member)
resolve({ name: member.content.name, pkId: member.content.pkId }) resolve(member.content.pkId)
found = true found = true
} }
} }
@ -106,82 +106,6 @@ async function determineAction(eventData, frontData = []) {
return action return action
} }
async function swapFront() {
let system = new System(Config)
let front = await system.getFronters()
// start forming new front list
let newFront = []
let frontNames = []
for (member of front) {
let m = await system.getMemberById(member.content.member)
if (m.content && m.content.pkId) {
// fronting member pkID has been found
newFront.push(m.content.pkId)
frontNames.push(m.content.name)
}
else {
console.warn('::SimplyWS:: System member not found, this may be a custom front which is unsupported.')
}
}
// shift primary fronter to first in list
let primary = await findPrimary()
let primaryPK = primary.pkId
let primaryName = primary.name
if (primaryPK) {
if (newFront.indexOf(primaryPK) > 0) {
newFront.splice(newFront.indexOf(primaryPK), 1)
newFront.unshift(primaryPK)
}
if (frontNames.indexOf(primaryName) > 0) {
frontNames.splice(frontNames.indexOf(primaryName), 1)
frontNames.unshift(primaryName)
}
}
// post the new switch
let url = `${pkUrl}/systems/@me/switches`
await axios.post(url, JSON.stringify({ "members": newFront }), {
headers: pkHeader
})
.then(async (res) => {
// check if current front equals the new front
let front = await getPKFronters()
var equal = (front.length == newFront.length) && front.every(function(element, index) {
return element === newFront[index];
})
if (!equal) {
console.log('::SimplyWS:: Failed to swap front: ' + newFront)
await swapFront()
return
} else {
let formattedNames = frontNames.toString().replace(',',', ')
console.log(`::SimplyWS:: SimplyPlural -> PluralKit: ${formattedNames}`)
}
})
.catch(async err => {
let status = err.status || err.toJSON().status
if (status == 400) {
// if the fronter is already in the front, do nothing
return
}
else if (status == 404) {
return
}
else if (status == 429) {
// Too many requests
console.warn("::SimplyWS:: Too many requests, waiting to try again.")
setTimeout(async function () {
await swapFront()
}, 1000)
return
}
})
}
async function insertFront(member) { async function insertFront(member) {
// get current fronters and add new fronter // get current fronters and add new fronter
let fronters = await getPKFronters() let fronters = await getPKFronters()
@ -193,7 +117,7 @@ async function insertFront(member) {
} }
// find the "primary" fronter to move to the first element in the list // find the "primary" fronter to move to the first element in the list
let primary = await findPrimary().pkId let primary = await findPrimary()
if (primary) { if (primary) {
if (fronters.indexOf(primary) > 0) { if (fronters.indexOf(primary) > 0) {
fronters.splice(fronters.indexOf(primary), 1) fronters.splice(fronters.indexOf(primary), 1)
@ -254,11 +178,11 @@ async function removeFront(member) {
} }
// find the "primary" fronter to move to the first element in the list // find the "primary" fronter to move to the first element in the list
let primary = await findPrimary().pkId let p = await findPrimary()
if (primary) { if (p) {
if (fronters.indexOf(primary) > 0) { if (fronters.indexOf(p) > 0) {
fronters.splice(fronters.indexOf(primary), 1) fronters.splice(fronters.indexOf(p), 1)
fronters.unshift(primary) fronters.unshift(p)
} }
} }
@ -297,9 +221,10 @@ async function removeFront(member) {
async function updateCustomStatus(member) { async function updateCustomStatus(member) {
// find the "primary" fronter to move to the first element in the list // find the "primary" fronter to move to the first element in the list
let system = new System(Config)
let fronters = await getPKFronters() let fronters = await getPKFronters()
let primary = await findPrimary().pkId let primary = await findPrimary()
if (primary && fronters.length > 1 && (member.content.pkId == primary)) { if (primary && fronters.length > 1) {
if (fronters.indexOf(primary) >= 0) { if (fronters.indexOf(primary) >= 0) {
fronters.splice(fronters.indexOf(primary), 1) fronters.splice(fronters.indexOf(primary), 1)
fronters.unshift(primary) fronters.unshift(primary)
@ -309,7 +234,9 @@ async function updateCustomStatus(member) {
headers: pkHeader headers: pkHeader
}) })
.catch(async err => { .catch(async err => {
if (err.toJSON().status == 429) if (err.toJSON().status == 400)
unknownError400()
else if (err.toJSON().status == 429)
//Too many requests //Too many requests
console.warn("::SimplyWS:: Too many requests, waiting to try again.") console.warn("::SimplyWS:: Too many requests, waiting to try again.")
setTimeout(function () { setTimeout(function () {
@ -351,9 +278,8 @@ module.exports = {
getPKFronters, getPKFronters,
findPrimary, findPrimary,
determineAction, determineAction,
swapFront,
insertFront, insertFront,
removeFront, removeFront,
updateCustomStatus, updateCustomStatus,
calculateDiff calculateDiff
} }

View file

@ -3,7 +3,7 @@ dotenv.config()
const { Config, System } = require('simplyapi') const { Config, System } = require('simplyapi')
const { Util } = require('simplyapi') const { Util } = require('simplyapi')
const { initializeCache, determineAction, swapFront, insertFront, removeFront, updateCustomStatus } = require('./dataManager') const { initializeCache, determineAction, insertFront, removeFront, updateCustomStatus } = require('./dataManager')
const { const {
isMainThread, isMainThread,
@ -39,7 +39,6 @@ initiateWorkerPool = () => {
bc.onmessage = (event) => { bc.onmessage = (event) => {
//console.log('::SimplyWS:: received message from worker') //console.log('::SimplyWS:: received message from worker')
queue.push(event.data, (error, task) => { queue.push(event.data, (error, task) => {
// task completed
if (error.status) { if (error.status) {
console.log(`An error occurred while processing task ${error.message}`) console.log(`An error occurred while processing task ${error.message}`)
} }
@ -60,7 +59,6 @@ openWebSocket = () => {
wss.onError = (e) => { console.log('SimplyWS/onError :: %s', e) } wss.onError = (e) => { console.log('SimplyWS/onError :: %s', e) }
const bc = new BroadcastChannel('plural') const bc = new BroadcastChannel('plural')
let first_auth = true
wss.onMessage = (raw) => { wss.onMessage = (raw) => {
e = raw e = raw
let data = JSON.parse(e) let data = JSON.parse(e)
@ -68,15 +66,15 @@ openWebSocket = () => {
switch (data.msg) { switch (data.msg) {
case "Successfully authenticated": case "Successfully authenticated":
if (!process.env.silence_connections || first_auth) console.log('::SimplyWS:: authenticated') console.log('::SimplyWS:: authenticated')
first_auth = false
// cache current front // cache current front
initializeCache() initializeCache()
break break
case "Authentication violation: Token is missing or invalid. Goodbye :)": case "Authentication violation: Token is missing or invalid. Goodbye :)":
console.error('::SimplyWS:: invalid token, exiting..') console.log('::SimplyWS:: invalid token, exiting..')
process.exit(1) process.exit(1)
case "update": case "update":
initializeCache()
bc.postMessage({data: data}) bc.postMessage({data: data})
break break
default: default:
@ -95,12 +93,8 @@ update = async (data) => {
await Util.asyncForEach(data.results, async (o) => { await Util.asyncForEach(data.results, async (o) => {
let system = new System(Config) let system = new System(Config)
let member = await system.getMemberById(o.content.member) let member = await system.getMemberById(o.content.member)
let swap = Config.full_swap
// insert // insert
if (swap) { if (o.operationType == "insert") {
swapFront()
}
else if (o.operationType == "insert") {
insertFront(member) insertFront(member)
} }
else { else {