Compare commits
No commits in common. "6df728dcc73b48bd2153dca12d17f4861e942a29" and "eee5b001bc8ce076fa33fbb6a67eec25cea7013a" have entirely different histories.
6df728dcc7
...
eee5b001bc
12 changed files with 14 additions and 81 deletions
|
@ -1,36 +0,0 @@
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
const assert = require("assert")
|
|
||||||
|
|
||||||
const passthrough = require("../../passthrough")
|
|
||||||
const { discord, sync, db } = passthrough
|
|
||||||
/** @type {import("../../matrix/api")} */
|
|
||||||
const api = sync.require("../../matrix/api")
|
|
||||||
/** @type {import("./register-user")} */
|
|
||||||
const registerUser = sync.require("./register-user")
|
|
||||||
/** @type {import("../actions/create-room")} */
|
|
||||||
const createRoom = sync.require("../actions/create-room")
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data
|
|
||||||
*/
|
|
||||||
async function addReaction(data) {
|
|
||||||
const user = data.member?.user
|
|
||||||
assert.ok(user && user.username)
|
|
||||||
// TODO: should add my own sent messages to event_message so they can be reacted to?
|
|
||||||
const parentID = db.prepare("SELECT event_id FROM event_message WHERE message_id = ? AND part = 0").pluck().get(data.message_id) // 0 = primary
|
|
||||||
if (!parentID) return // TODO: how to handle reactions for unbridged messages? is there anything I can do?
|
|
||||||
assert.equal(typeof parentID, "string")
|
|
||||||
const roomID = await createRoom.ensureRoom(data.channel_id)
|
|
||||||
const senderMxid = await registerUser.ensureSimJoined(user, roomID)
|
|
||||||
const eventID = api.sendEvent(roomID, "m.reaction", {
|
|
||||||
"m.relates_to": {
|
|
||||||
rel_type: "m.annotation",
|
|
||||||
event_id: parentID,
|
|
||||||
key: data.emoji.name
|
|
||||||
}
|
|
||||||
}, senderMxid)
|
|
||||||
return eventID
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.addReaction = addReaction
|
|
|
@ -24,25 +24,16 @@ async function createSim(user) {
|
||||||
const mxid = "@" + localpart + ":cadence.moe"
|
const mxid = "@" + localpart + ":cadence.moe"
|
||||||
|
|
||||||
// Save chosen name in the database forever
|
// Save chosen name in the database forever
|
||||||
// Making this database change right away so that in a concurrent registration, the 2nd registration will already have generated a different localpart because it can see this row when it generates
|
|
||||||
db.prepare("INSERT INTO sim (discord_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(user.id, simName, localpart, mxid)
|
db.prepare("INSERT INTO sim (discord_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(user.id, simName, localpart, mxid)
|
||||||
|
|
||||||
// Register matrix user with that name
|
// Register matrix user with that name
|
||||||
try {
|
|
||||||
await api.register(localpart)
|
await api.register(localpart)
|
||||||
} catch (e) {
|
|
||||||
// If user creation fails, manually undo the database change. Still isn't perfect, but should help.
|
|
||||||
// (A transaction would be preferable, but I don't think it's safe to leave transaction open across event loop ticks.)
|
|
||||||
db.prepare("DELETE FROM sim WHERE discord_id = ?").run(user.id)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
return mxid
|
return mxid
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure a sim is registered for the user.
|
* Ensure a sim is registered for the user.
|
||||||
* If there is already a sim, use that one. If there isn't one yet, register a new sim.
|
* If there is already a sim, use that one. If there isn't one yet, register a new sim.
|
||||||
* @param {import("discord-api-types/v10").APIUser} user
|
|
||||||
* @returns mxid
|
* @returns mxid
|
||||||
*/
|
*/
|
||||||
async function ensureSim(user) {
|
async function ensureSim(user) {
|
||||||
|
@ -58,7 +49,6 @@ async function ensureSim(user) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure a sim is registered for the user and is joined to the room.
|
* Ensure a sim is registered for the user and is joined to the room.
|
||||||
* @param {import("discord-api-types/v10").APIUser} user
|
|
||||||
* @returns mxid
|
* @returns mxid
|
||||||
*/
|
*/
|
||||||
async function ensureSimJoined(user, roomID) {
|
async function ensureSimJoined(user, roomID) {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
const fetch = require("node-fetch").default
|
||||||
|
const reg = require("../../matrix/read-registration.js")
|
||||||
|
|
||||||
const passthrough = require("../../passthrough")
|
const passthrough = require("../../passthrough")
|
||||||
const { discord, sync, db } = passthrough
|
const { discord, sync, db } = passthrough
|
||||||
/** @type {import("../converters/message-to-event")} */
|
/** @type {import("../converters/message-to-event")} */
|
||||||
|
@ -21,8 +24,7 @@ async function sendMessage(message) {
|
||||||
if (!message.webhook_id) {
|
if (!message.webhook_id) {
|
||||||
senderMxid = await registerUser.ensureSimJoined(message.author, roomID)
|
senderMxid = await registerUser.ensureSimJoined(message.author, roomID)
|
||||||
}
|
}
|
||||||
const eventID = await api.sendEvent(roomID, "m.room.message", event, senderMxid)
|
const eventID = api.sendEvent(roomID, "m.room.message", event, senderMxid)
|
||||||
db.prepare("INSERT INTO event_message (event_id, message_id, part) VALUES (?, ?, ?)").run(eventID, message.id, 0) // 0 is primary, 1 is supporting
|
|
||||||
return eventID
|
return eventID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ function* generateLocalpartAlternatives(preferences) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whole process for checking the database and generating the right sim name.
|
* Whole process for checking the database and generating the right sim name.
|
||||||
* It is very important this is not an async function: once the name has been chosen, the calling function should be able to immediately claim that name into the database in the same event loop tick.
|
|
||||||
* @param {import("discord-api-types/v10").APIUser} user
|
* @param {import("discord-api-types/v10").APIUser} user
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,7 +31,3 @@ test("user2name: adds number suffix if name is unavailable (new username format)
|
||||||
test("user2name: uses ID if name becomes too short", t => {
|
test("user2name: uses ID if name becomes too short", t => {
|
||||||
t.equal(userToSimName({username: "f***", discriminator: "0001", id: "9"}), "9")
|
t.equal(userToSimName({username: "f***", discriminator: "0001", id: "9"}), "9")
|
||||||
})
|
})
|
||||||
|
|
||||||
test("user2name: uses ID when name has only disallowed characters", t => {
|
|
||||||
t.equal(userToSimName({username: "!@#$%^&*", discriminator: "0001", id: "9"}), "9")
|
|
||||||
})
|
|
|
@ -6,16 +6,15 @@ const DiscordTypes = require("discord-api-types/v10")
|
||||||
const passthrough = require("../passthrough")
|
const passthrough = require("../passthrough")
|
||||||
const { sync } = passthrough
|
const { sync } = passthrough
|
||||||
|
|
||||||
|
/** @type {typeof import("./event-dispatcher")} */
|
||||||
|
const eventDispatcher = sync.require("./event-dispatcher")
|
||||||
|
|
||||||
const utils = {
|
const utils = {
|
||||||
/**
|
/**
|
||||||
* @param {import("./discord-client")} client
|
* @param {import("./discord-client")} client
|
||||||
* @param {import("cloudstorm").IGatewayMessage} message
|
* @param {import("cloudstorm").IGatewayMessage} message
|
||||||
*/
|
*/
|
||||||
onPacket(client, message) {
|
onPacket(client, message) {
|
||||||
// requiring this later so that the client is already constructed by the time event-dispatcher is loaded
|
|
||||||
/** @type {typeof import("./event-dispatcher")} */
|
|
||||||
const eventDispatcher = sync.require("./event-dispatcher")
|
|
||||||
|
|
||||||
if (message.t === "READY") {
|
if (message.t === "READY") {
|
||||||
if (client.ready) return
|
if (client.ready) return
|
||||||
client.ready = true
|
client.ready = true
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
|
|
||||||
const {sync} = require("../passthrough")
|
const {sync} = require("../passthrough")
|
||||||
|
|
||||||
|
/** @type {import("./actions/create-space")}) */
|
||||||
|
const createSpace = sync.require("./actions/create-space")
|
||||||
|
|
||||||
/** @type {import("./actions/send-message")}) */
|
/** @type {import("./actions/send-message")}) */
|
||||||
const sendMessage = sync.require("./actions/send-message")
|
const sendMessage = sync.require("./actions/send-message")
|
||||||
/** @type {import("./actions/add-reaction")}) */
|
|
||||||
const addReaction = sync.require("./actions/add-reaction")
|
|
||||||
|
|
||||||
// Grab Discord events we care about for the bridge, check them, and pass them on
|
// Grab Discord events we care about for the bridge, check them, and pass them on
|
||||||
|
|
||||||
|
@ -24,8 +25,7 @@ module.exports = {
|
||||||
* @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data
|
* @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data
|
||||||
*/
|
*/
|
||||||
onReactionAdd(client, data) {
|
onReactionAdd(client, data) {
|
||||||
if (data.emoji.id !== null) return // TOOD: image emoji reactions
|
|
||||||
console.log(data)
|
console.log(data)
|
||||||
addReaction.addReaction(data)
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
db/ooye.db
BIN
db/ooye.db
Binary file not shown.
|
@ -28,7 +28,6 @@ function path(p, mxid) {
|
||||||
* @returns {Promise<import("../types").R.Registered>}
|
* @returns {Promise<import("../types").R.Registered>}
|
||||||
*/
|
*/
|
||||||
function register(username) {
|
function register(username) {
|
||||||
console.log(`[api] register: ${username}`)
|
|
||||||
return mreq.mreq("POST", "/client/v3/register", {
|
return mreq.mreq("POST", "/client/v3/register", {
|
||||||
type: "m.login.application_service",
|
type: "m.login.application_service",
|
||||||
username
|
username
|
||||||
|
@ -39,7 +38,6 @@ function register(username) {
|
||||||
* @returns {Promise<string>} room ID
|
* @returns {Promise<string>} room ID
|
||||||
*/
|
*/
|
||||||
async function createRoom(content) {
|
async function createRoom(content) {
|
||||||
console.log(`[api] create room:`, content)
|
|
||||||
/** @type {import("../types").R.RoomCreated} */
|
/** @type {import("../types").R.RoomCreated} */
|
||||||
const root = await mreq.mreq("POST", "/client/v3/createRoom", content)
|
const root = await mreq.mreq("POST", "/client/v3/createRoom", content)
|
||||||
return root.room_id
|
return root.room_id
|
||||||
|
@ -76,7 +74,6 @@ function getAllState(roomID) {
|
||||||
* @returns {Promise<string>} event ID
|
* @returns {Promise<string>} event ID
|
||||||
*/
|
*/
|
||||||
async function sendState(roomID, type, stateKey, content, mxid) {
|
async function sendState(roomID, type, stateKey, content, mxid) {
|
||||||
console.log(`[api] state: ${roomID}: ${type}/${stateKey}`)
|
|
||||||
assert.ok(type)
|
assert.ok(type)
|
||||||
assert.ok(stateKey)
|
assert.ok(stateKey)
|
||||||
/** @type {import("../types").R.EventSent} */
|
/** @type {import("../types").R.EventSent} */
|
||||||
|
@ -85,7 +82,6 @@ async function sendState(roomID, type, stateKey, content, mxid) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendEvent(roomID, type, content, mxid) {
|
async function sendEvent(roomID, type, content, mxid) {
|
||||||
console.log(`[api] event to ${roomID} as ${mxid || "default sim"}`)
|
|
||||||
/** @type {import("../types").R.EventSent} */
|
/** @type {import("../types").R.EventSent} */
|
||||||
const root = await mreq.mreq("PUT", path(`/client/v3/rooms/${roomID}/send/${type}/${makeTxnId.makeTxnId()}`, mxid), content)
|
const root = await mreq.mreq("PUT", path(`/client/v3/rooms/${roomID}/send/${type}/${makeTxnId.makeTxnId()}`, mxid), content)
|
||||||
return root.event_id
|
return root.event_id
|
||||||
|
|
|
@ -11,12 +11,11 @@ const reg = sync.require("./read-registration.js")
|
||||||
const baseUrl = "https://matrix.cadence.moe/_matrix"
|
const baseUrl = "https://matrix.cadence.moe/_matrix"
|
||||||
|
|
||||||
class MatrixServerError extends Error {
|
class MatrixServerError extends Error {
|
||||||
constructor(data, opts) {
|
constructor(data) {
|
||||||
super(data.error || data.errcode)
|
super(data.error || data.errcode)
|
||||||
this.data = data
|
this.data = data
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
this.errcode = data.errcode
|
this.errcode = data.errcode
|
||||||
this.opts = opts
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ async function mreq(method, url, body, extra = {}) {
|
||||||
const res = await fetch(baseUrl + url, opts)
|
const res = await fetch(baseUrl + url, opts)
|
||||||
const root = await res.json()
|
const root = await res.json()
|
||||||
|
|
||||||
if (!res.ok || root.errcode) throw new MatrixServerError(root, opts)
|
if (!res.ok || root.errcode) throw new MatrixServerError(root)
|
||||||
return root
|
return root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
const {test} = require("supertape")
|
|
||||||
const assert = require("assert")
|
|
||||||
const reg = require("./read-registration")
|
|
||||||
|
|
||||||
test("reg: has necessary parameters", t => {
|
|
||||||
const propertiesToCheck = ["sender_localpart", "id", "as_token", "namespace_prefix"]
|
|
||||||
t.deepEqual(
|
|
||||||
propertiesToCheck.filter(p => p in reg),
|
|
||||||
propertiesToCheck
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -12,7 +12,6 @@ const sync = new HeatSync({watchFS: false})
|
||||||
|
|
||||||
Object.assign(passthrough, { config, sync, db })
|
Object.assign(passthrough, { config, sync, db })
|
||||||
|
|
||||||
require("../matrix/read-registration.test")
|
|
||||||
require("../d2m/actions/create-room.test")
|
require("../d2m/actions/create-room.test")
|
||||||
require("../d2m/converters/user-to-mxid.test")
|
require("../d2m/converters/user-to-mxid.test")
|
||||||
require("../matrix/api.test")
|
require("../matrix/api.test")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue