parse basic markdown for sending images
This commit is contained in:
parent
91a71c79b2
commit
f110d03fdc
BIN
avatars/ca.png
Normal file
BIN
avatars/ca.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -26,8 +26,9 @@ app_service_config_files:
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit ecosystem.yml and set the path to the `ppfun-registration.yml` as REGISTRATION_YAML.
|
Edit ecosystem.yml and set the path to the `ppfun-registration.yml` as REGISTRATION_YAML.
|
||||||
Set the pixelplanet APISOCKET_KEY and APISOCKET_URL (like `https://pixelplanet.fun/mcws`) and PPFUN_UID to a user-id from pixelplanet that the bridge sends messages as (can be any number, but its better if its an existing user made for the bridge).
|
Set the pixelplanet APISOCKET_KEY and APISOCKET_URL (like `https://pixelplanet.fun/mcws`).
|
||||||
HOMESERVER_URL should be the local url to matrix-synapse like `http://localhost:8008` and HOMESERVER_DOMAIN its base_url / server_name like `pixelplanet.fun`
|
HOMESERVER_URL should be the local url to matrix-synapse like `http://localhost:8008` and HOMESERVER_DOMAIN its base_url / server_name like `pixelplanet.fun`
|
||||||
|
MEDIA_URL is the http[s] url from which the matrix server is reachable from the outside, which is usually the base_url, it is needed to send links
|
||||||
|
|
||||||
Now you can start the brige with pm2:
|
Now you can start the brige with pm2:
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,4 @@ apps:
|
||||||
REGISTRATION_YAML: "/etc/matrix-synapse/ppfun-registration.yaml"
|
REGISTRATION_YAML: "/etc/matrix-synapse/ppfun-registration.yaml"
|
||||||
HOMESERVER_URL: "http://localhost:8008"
|
HOMESERVER_URL: "http://localhost:8008"
|
||||||
HOMESERVER_DOMAIN: "pixelplanet.fun"
|
HOMESERVER_DOMAIN: "pixelplanet.fun"
|
||||||
|
MEDIA_URL: "https://matrix.pixelplanet.fun"
|
||||||
|
|
|
@ -8,19 +8,19 @@ import PPfunMatrixBridge from './src/ppfunMatrixBridge.js';
|
||||||
const PORT = parseInt(process.env.PORT, 10) || 8009;
|
const PORT = parseInt(process.env.PORT, 10) || 8009;
|
||||||
const APISOCKET_KEY = process.env.APISOCKET_KEY || '';
|
const APISOCKET_KEY = process.env.APISOCKET_KEY || '';
|
||||||
const APISOCKET_URL = process.env.APISOCKET_URL || 'wss://dev.pixelplanet.fun/mcws';
|
const APISOCKET_URL = process.env.APISOCKET_URL || 'wss://dev.pixelplanet.fun/mcws';
|
||||||
const PPFUN_UID = parseInt(process.env.PPFUN_UID, 10) || 1;
|
|
||||||
const REGISTRATION_YAML = process.env.REGISTRATION_YAML || '/etc/matrix-synapse/ppfun-registration.yaml';
|
const REGISTRATION_YAML = process.env.REGISTRATION_YAML || '/etc/matrix-synapse/ppfun-registration.yaml';
|
||||||
const HOMESERVER_URL = process.env.HOMESERVER_URL || 'http://localhost:8008';
|
const HOMESERVER_URL = process.env.HOMESERVER_URL || 'http://localhost:8008';
|
||||||
const HOMESERVER_DOMAIN = process.env.HOMESERVER_DOMAIN || 'pixelplanet.fun';
|
const HOMESERVER_DOMAIN = process.env.HOMESERVER_DOMAIN || 'pixelplanet.fun';
|
||||||
|
const MEDIA_URL = process.env.MEDIA_URL || `https://${HOMESERVER_DOMAIN}`;
|
||||||
|
|
||||||
const lmao = new PPfunMatrixBridge({
|
const lmao = new PPfunMatrixBridge({
|
||||||
apiSocketKey: APISOCKET_KEY,
|
apiSocketKey: APISOCKET_KEY,
|
||||||
apiSocketUrl: APISOCKET_URL,
|
apiSocketUrl: APISOCKET_URL,
|
||||||
ppfunId: PPFUN_UID,
|
|
||||||
homeserverUrl: HOMESERVER_URL,
|
homeserverUrl: HOMESERVER_URL,
|
||||||
domain: HOMESERVER_DOMAIN,
|
domain: HOMESERVER_DOMAIN,
|
||||||
registration: REGISTRATION_YAML,
|
registration: REGISTRATION_YAML,
|
||||||
port: PORT,
|
port: PORT,
|
||||||
|
mediaUrl: MEDIA_URL
|
||||||
});
|
});
|
||||||
|
|
||||||
lmao.run();
|
lmao.run();
|
||||||
|
|
204
ppfun-bridge/src/markdown/MString.js
Normal file
204
ppfun-bridge/src/markdown/MString.js
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/*
|
||||||
|
* class for string iterations
|
||||||
|
* that is used by MarkdownParser.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class MString {
|
||||||
|
constructor(text, start) {
|
||||||
|
this.txt = text;
|
||||||
|
this.iter = start || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
done() {
|
||||||
|
return (this.iter >= this.txt.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveForward() {
|
||||||
|
this.iter += 1;
|
||||||
|
return (this.iter < this.txt.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
setIter(iter) {
|
||||||
|
this.iter = iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
getChar() {
|
||||||
|
return this.txt[this.iter];
|
||||||
|
}
|
||||||
|
|
||||||
|
slice(start, end) {
|
||||||
|
return this.txt.slice(start, end || this.iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
has(str) {
|
||||||
|
return this.txt.startsWith(str, this.iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
move(cnt) {
|
||||||
|
this.iter += cnt;
|
||||||
|
return (this.iter < this.txt.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
static isWhiteSpace(chr) {
|
||||||
|
return (chr === ' ' || chr === '\t' || chr === '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check if the current '[' is part of a [y](z) enclosure
|
||||||
|
* returns [y, z] if it is enclosure, null otherwise
|
||||||
|
* moves iter to last closing braked if it is enclosure
|
||||||
|
*/
|
||||||
|
checkIfEnclosure(zIsLink) {
|
||||||
|
const yStart = this.iter + 1;
|
||||||
|
|
||||||
|
let yEnd = yStart;
|
||||||
|
while (this.txt[yEnd] !== ']') {
|
||||||
|
const chr = this.txt[yEnd];
|
||||||
|
if (yEnd >= this.txt.length
|
||||||
|
|| chr === '\n'
|
||||||
|
|| chr === '['
|
||||||
|
|| chr === '('
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
yEnd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let zStart = yEnd + 1;
|
||||||
|
if (this.txt[zStart] !== '(') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
zStart += 1;
|
||||||
|
|
||||||
|
let zEnd = zStart;
|
||||||
|
let z = null;
|
||||||
|
while (this.txt[zEnd] !== ')') {
|
||||||
|
const chr = this.txt[zEnd];
|
||||||
|
if (zEnd >= this.txt.length
|
||||||
|
|| chr === '\n'
|
||||||
|
|| chr === '['
|
||||||
|
|| chr === '('
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (zIsLink && chr === ':') {
|
||||||
|
// set this.iter temporarily to be able to use thischeckIfLink
|
||||||
|
const oldIter = this.iter;
|
||||||
|
this.iter = zEnd;
|
||||||
|
z = this.checkIfLink();
|
||||||
|
zEnd = this.iter;
|
||||||
|
this.iter = oldIter;
|
||||||
|
if (z === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
zEnd += 1;
|
||||||
|
}
|
||||||
|
if (zEnd < zStart + 1 || (!z && zIsLink)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zIsLink) {
|
||||||
|
z = this.txt.slice(zStart, zEnd);
|
||||||
|
}
|
||||||
|
const y = this.txt.slice(yStart, yEnd);
|
||||||
|
|
||||||
|
this.iter = zEnd;
|
||||||
|
return [y, z];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convoluted way to check if the current ':' is part of a link
|
||||||
|
* we do not check for a 'http' because we might support application links
|
||||||
|
* like tg://... or discord://..
|
||||||
|
* returns the link or false if there is none
|
||||||
|
* moves iter forward to after the link, if there's one
|
||||||
|
*/
|
||||||
|
checkIfLink() {
|
||||||
|
let cIter = this.iter;
|
||||||
|
if (!this.txt.startsWith('://', cIter) || cIter < 3) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let linkStart = cIter - 1;
|
||||||
|
for (; linkStart >= 0
|
||||||
|
&& !MString.isWhiteSpace(this.txt[linkStart])
|
||||||
|
&& this.txt[linkStart] !== '('; linkStart -= 1);
|
||||||
|
linkStart += 1;
|
||||||
|
|
||||||
|
cIter += 3;
|
||||||
|
for (; cIter < this.txt.length
|
||||||
|
&& !MString.isWhiteSpace(this.txt[cIter])
|
||||||
|
&& this.txt[cIter] !== ')'; cIter += 1
|
||||||
|
);
|
||||||
|
if (cIter < this.iter + 4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* special case where someone pasted a http link after a text
|
||||||
|
* without space in between
|
||||||
|
*/
|
||||||
|
let link = this.txt.slice(linkStart, cIter);
|
||||||
|
const httpOc = link.indexOf('http');
|
||||||
|
if (httpOc !== -1 && httpOc !== 0) {
|
||||||
|
linkStart += httpOc;
|
||||||
|
link = this.txt.slice(linkStart, cIter);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.iter = cIter;
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if current '#' is part of ppfun coordinates (example: #d,23,11,-10)
|
||||||
|
* @return null if not coords, otherwise the coords string
|
||||||
|
*/
|
||||||
|
checkIfCoords() {
|
||||||
|
let cIter = this.iter + 1;
|
||||||
|
while (cIter < this.txt.length) {
|
||||||
|
const chr = this.txt[cIter];
|
||||||
|
if (chr === ',') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (MString.isWhiteSpace(chr)
|
||||||
|
|| !Number.isNaN(Number(chr))
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cIter += 1;
|
||||||
|
}
|
||||||
|
if (cIter >= this.txt.length
|
||||||
|
|| cIter - this.iter > 12
|
||||||
|
|| cIter === this.iter
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cIter += 1;
|
||||||
|
const curChr = this.txt[cIter];
|
||||||
|
if (curChr !== '-' && Number.isNaN(curChr)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cIter += 1;
|
||||||
|
let sectCount = 1;
|
||||||
|
while (cIter < this.txt.length && !MString.isWhiteSpace(this.txt[cIter])) {
|
||||||
|
const chr = this.txt[cIter];
|
||||||
|
if (chr === ',') {
|
||||||
|
sectCount += 1;
|
||||||
|
} else if (chr !== '-' && Number.isNaN(Number(chr))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cIter += 1;
|
||||||
|
}
|
||||||
|
if (sectCount < 2
|
||||||
|
|| sectCount > 3
|
||||||
|
|| this.txt[cIter - 1] === ','
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coords = this.txt.slice(this.iter, cIter);
|
||||||
|
this.iter = cIter;
|
||||||
|
return coords;
|
||||||
|
}
|
||||||
|
}
|
104
ppfun-bridge/src/markdown/MarkdownParserLight.js
Normal file
104
ppfun-bridge/src/markdown/MarkdownParserLight.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* Markdown parsing
|
||||||
|
*
|
||||||
|
* Parses the very basics that are needed for the bridge
|
||||||
|
*/
|
||||||
|
|
||||||
|
import MString from './MString.js';
|
||||||
|
|
||||||
|
function parseMParagraph(text) {
|
||||||
|
const pArray = [];
|
||||||
|
let pStart = text.iter;
|
||||||
|
let chr = null;
|
||||||
|
while (!text.done()) {
|
||||||
|
chr = text.getChar();
|
||||||
|
|
||||||
|
if (chr === '\n') {
|
||||||
|
text.moveForward();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chr === '\\') {
|
||||||
|
/*
|
||||||
|
* escape character
|
||||||
|
*/
|
||||||
|
if (pStart !== text.iter) {
|
||||||
|
pArray.push(text.slice(pStart));
|
||||||
|
}
|
||||||
|
pStart = text.iter + 1;
|
||||||
|
text.moveForward();
|
||||||
|
} else if (chr === '#') {
|
||||||
|
/*
|
||||||
|
* ppfun coords #d,34,23,-10
|
||||||
|
*/
|
||||||
|
const oldPos = text.iter;
|
||||||
|
const coords = text.checkIfCoords();
|
||||||
|
if (coords) {
|
||||||
|
if (pStart !== oldPos) {
|
||||||
|
pArray.push(text.slice(pStart, oldPos));
|
||||||
|
}
|
||||||
|
pArray.push(['l', null, `https://pixelplanet.fun/${coords}`]);
|
||||||
|
pStart = text.iter;
|
||||||
|
}
|
||||||
|
} else if (chr === ':') {
|
||||||
|
/*
|
||||||
|
* pure link
|
||||||
|
*/
|
||||||
|
const link = text.checkIfLink();
|
||||||
|
if (link !== null) {
|
||||||
|
const startLink = text.iter - link.length;
|
||||||
|
if (pStart < startLink) {
|
||||||
|
pArray.push(text.slice(pStart, startLink));
|
||||||
|
}
|
||||||
|
pArray.push(['l', null, link]);
|
||||||
|
pStart = text.iter;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (chr === '[') {
|
||||||
|
/*
|
||||||
|
* x[y](z) enclosure
|
||||||
|
*/
|
||||||
|
let oldPos = text.iter;
|
||||||
|
let x = null;
|
||||||
|
if (text.iter > 0) {
|
||||||
|
text.move(-1);
|
||||||
|
x = text.getChar();
|
||||||
|
text.setIter(oldPos);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* x decides what element it is
|
||||||
|
* defaults to ordinary link
|
||||||
|
*/
|
||||||
|
let tag = 'l';
|
||||||
|
let zIsLink = true;
|
||||||
|
if (x === '!') {
|
||||||
|
tag = 'img';
|
||||||
|
oldPos -= 1;
|
||||||
|
} else if (x === '@') {
|
||||||
|
zIsLink = false;
|
||||||
|
tag = '@';
|
||||||
|
oldPos -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const encArr = text.checkIfEnclosure(zIsLink);
|
||||||
|
if (encArr !== null) {
|
||||||
|
if (pStart < oldPos) {
|
||||||
|
pArray.push(text.slice(pStart, oldPos));
|
||||||
|
}
|
||||||
|
pArray.push([tag, encArr[0], encArr[1]]);
|
||||||
|
pStart = text.iter + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
text.moveForward();
|
||||||
|
}
|
||||||
|
if (pStart !== text.iter) {
|
||||||
|
pArray.push(text.slice(pStart));
|
||||||
|
}
|
||||||
|
return pArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseParagraph(text,) {
|
||||||
|
const mText = new MString(text);
|
||||||
|
return parseMParagraph(mText);
|
||||||
|
}
|
28
ppfun-bridge/src/markdown/parse.js
Normal file
28
ppfun-bridge/src/markdown/parse.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { parseParagraph } from './MarkdownParserLight.js';
|
||||||
|
|
||||||
|
export default function parseMsg(msg) {
|
||||||
|
const pArray = parseParagraph(msg);
|
||||||
|
let output = '';
|
||||||
|
for (let i = 0; i < pArray.length; i += 1) {
|
||||||
|
const part = pArray[i];
|
||||||
|
if (!Array.isArray(part)) {
|
||||||
|
output += part;
|
||||||
|
} else {
|
||||||
|
const type = part[0];
|
||||||
|
switch (type) {
|
||||||
|
case '@': {
|
||||||
|
output += `@${part[1]}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'img':
|
||||||
|
case 'l': {
|
||||||
|
output += part[2];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
output += type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { Bridge } from 'matrix-appservice-bridge';
|
import { Bridge } from 'matrix-appservice-bridge';
|
||||||
|
|
||||||
|
import parseMsg from './markdown/parse.js'
|
||||||
import PPfunSocket from './ppfunsocket.js';
|
import PPfunSocket from './ppfunsocket.js';
|
||||||
import { parseCanvasLinks } from './pixelplanet/index.js';
|
import { parseCanvasLinks } from './pixelplanet/index.js';
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ class PPfunMatrixBridge {
|
||||||
apiSocketKey,
|
apiSocketKey,
|
||||||
apiSocketUrl,
|
apiSocketUrl,
|
||||||
homeserverUrl,
|
homeserverUrl,
|
||||||
|
mediaUrl,
|
||||||
domain,
|
domain,
|
||||||
registration,
|
registration,
|
||||||
port
|
port
|
||||||
|
@ -39,6 +41,7 @@ class PPfunMatrixBridge {
|
||||||
});
|
});
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.domain = domain;
|
this.domain = domain;
|
||||||
|
this.mediaUrl = mediaUrl;
|
||||||
this.prefix = 'pp';
|
this.prefix = 'pp';
|
||||||
|
|
||||||
this.ppfunSocket.on('chanList', this.connectRooms.bind(this));
|
this.ppfunSocket.on('chanList', this.connectRooms.bind(this));
|
||||||
|
@ -69,12 +72,13 @@ class PPfunMatrixBridge {
|
||||||
console.warn(`Dropping a message because channels aren't synced yet`);
|
console.warn(`Dropping a message because channels aren't synced yet`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const parsedMsg = parseMsg(msg);
|
||||||
this.echoSuppression.set(`${uid}:${cid}`, Date.now());
|
this.echoSuppression.set(`${uid}:${cid}`, Date.now());
|
||||||
console.log(`PPFUN ${name}: ${msg}`);
|
console.log(`PPFUN ${name}: ${parsedMsg}`);
|
||||||
this.sendMatrix(
|
this.sendMatrix(
|
||||||
name,
|
name,
|
||||||
`@${this.prefix}_${uid}:${this.domain}`,
|
`@${this.prefix}_${uid}:${this.domain}`,
|
||||||
msg,
|
parsedMsg,
|
||||||
matrixRoom,
|
matrixRoom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -112,16 +116,43 @@ class PPfunMatrixBridge {
|
||||||
|
|
||||||
async recMatrix(request, context) {
|
async recMatrix(request, context) {
|
||||||
const event = request.getData();
|
const event = request.getData();
|
||||||
if (event.type === "m.room.message"
|
// user joined or set displayname
|
||||||
|
if (event.type === "m.room.member"
|
||||||
|
&& event.user_id
|
||||||
&& event.content
|
&& event.content
|
||||||
&& event.content.msgtype === "m.text"
|
&& event.content.displayname
|
||||||
) {
|
) {
|
||||||
|
const name = event.content.displayname;
|
||||||
|
const userId = event.user_id;
|
||||||
|
console.log(`User ${userId} joined or set displayname to ${name}`);
|
||||||
|
this.idToNameMap.set(userId, name);
|
||||||
|
}
|
||||||
|
// Only room messages from bridged rooms past this point
|
||||||
|
if (event.type !== "m.room.message" || !event.content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const cid = this.mToProomMap.get(event.room_id);
|
const cid = this.mToProomMap.get(event.room_id);
|
||||||
if (!cid) {
|
if (!cid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const msg = event.content.body;
|
let msg;
|
||||||
|
// Media: send url as markdown
|
||||||
|
if ((event.content.msgtype === "m.image"
|
||||||
|
|| event.content.msgtype === "m.video")
|
||||||
|
&& event.content.url
|
||||||
|
) {
|
||||||
|
// adding a query parameter so that client can guess what it is
|
||||||
|
const url = `${this.mediaUrl}/_matrix/media/r0/download/${event.content.url.substring("mxc://".length)}?type=${event.content.msgtype.substring(2)}`
|
||||||
|
msg = `[${event.content.body}](${url})`;
|
||||||
|
// Text
|
||||||
|
} else if (event.content.msgtype === "m.text") {
|
||||||
|
msg = event.content.body;
|
||||||
this.sendCanvasSnapshotIfNeccessary(event.room_id, msg);
|
this.sendCanvasSnapshotIfNeccessary(event.room_id, msg);
|
||||||
|
}
|
||||||
|
if (!msg) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const userId = event.sender;
|
const userId = event.sender;
|
||||||
const uid = (userId.startsWith(`@${this.prefix}_`)
|
const uid = (userId.startsWith(`@${this.prefix}_`)
|
||||||
&& userId.endsWith(this.domain))
|
&& userId.endsWith(this.domain))
|
||||||
|
@ -139,17 +170,6 @@ class PPfunMatrixBridge {
|
||||||
this.sendPPfun(name, parseInt(uid, 10), msg, cid);
|
this.sendPPfun(name, parseInt(uid, 10), msg, cid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.type === "m.room.member"
|
|
||||||
&& event.user_id
|
|
||||||
&& event.content
|
|
||||||
&& event.content.displayname
|
|
||||||
) {
|
|
||||||
const name = event.content.displayname;
|
|
||||||
const userId = event.user_id;
|
|
||||||
console.log(`User ${userId} joined or set displayname to ${name}`);
|
|
||||||
this.idToNameMap.set(userId, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get displayname of matrix user
|
* get displayname of matrix user
|
||||||
|
|
Loading…
Reference in New Issue
Block a user