mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-04-21 05:25:51 +03:00
* Add syntax & type check for Node.js example on CI Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org> * Fix quotes --------- Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org> Co-authored-by: Florian Duros <florianduros@element.io>
397 lines
13 KiB
JavaScript
397 lines
13 KiB
JavaScript
import clc from "cli-color";
|
|
import fs from "fs";
|
|
import readline from "readline";
|
|
import sdk, { ClientEvent, EventType, MsgType, RoomEvent } from "matrix-js-sdk";
|
|
import { KnownMembership } from "matrix-js-sdk/lib/@types/membership.js";
|
|
|
|
var myHomeServer = "http://localhost:8008";
|
|
var myUserId = "@example:localhost";
|
|
var myAccessToken = "QGV4YW1wbGU6bG9jYWxob3N0.qPEvLuYfNBjxikiCjP";
|
|
|
|
var matrixClient = sdk.createClient({
|
|
baseUrl: myHomeServer,
|
|
accessToken: myAccessToken,
|
|
userId: myUserId,
|
|
});
|
|
|
|
// Data structures
|
|
var roomList = [];
|
|
var viewingRoom = null;
|
|
var numMessagesToShow = 20;
|
|
|
|
// Reading from stdin
|
|
var CLEAR_CONSOLE = "\x1B[2J";
|
|
var rl = readline.createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout,
|
|
completer: completer,
|
|
});
|
|
rl.setPrompt("$ ");
|
|
rl.on("line", function (line) {
|
|
if (line.trim().length === 0) {
|
|
rl.prompt();
|
|
return;
|
|
}
|
|
if (line === "/help") {
|
|
printHelp();
|
|
rl.prompt();
|
|
return;
|
|
}
|
|
|
|
if (viewingRoom) {
|
|
if (line === "/exit") {
|
|
viewingRoom = null;
|
|
printRoomList();
|
|
} else if (line === "/members") {
|
|
printMemberList(viewingRoom);
|
|
} else if (line === "/roominfo") {
|
|
printRoomInfo(viewingRoom);
|
|
} else if (line === "/resend") {
|
|
// get the oldest not sent event.
|
|
var notSentEvent;
|
|
for (var i = 0; i < viewingRoom.timeline.length; i++) {
|
|
if (viewingRoom.timeline[i].status == sdk.EventStatus.NOT_SENT) {
|
|
notSentEvent = viewingRoom.timeline[i];
|
|
break;
|
|
}
|
|
}
|
|
if (notSentEvent) {
|
|
matrixClient.resendEvent(notSentEvent, viewingRoom).then(
|
|
function () {
|
|
printMessages();
|
|
rl.prompt();
|
|
},
|
|
function (err) {
|
|
printMessages();
|
|
print("/resend Error: %s", err);
|
|
rl.prompt();
|
|
},
|
|
);
|
|
printMessages();
|
|
rl.prompt();
|
|
}
|
|
} else if (line.indexOf("/more ") === 0) {
|
|
var amount = parseInt(line.split(" ")[1]) || 20;
|
|
matrixClient.scrollback(viewingRoom, amount).then(
|
|
function (room) {
|
|
printMessages();
|
|
rl.prompt();
|
|
},
|
|
function (err) {
|
|
print("/more Error: %s", err);
|
|
},
|
|
);
|
|
} else if (line.indexOf("/invite ") === 0) {
|
|
var userId = line.split(" ")[1].trim();
|
|
matrixClient.invite(viewingRoom.roomId, userId).then(
|
|
function () {
|
|
printMessages();
|
|
rl.prompt();
|
|
},
|
|
function (err) {
|
|
print("/invite Error: %s", err);
|
|
},
|
|
);
|
|
} else if (line.indexOf("/file ") === 0) {
|
|
var filename = line.split(" ")[1].trim();
|
|
let buffer = fs.readFileSync("./your_file_name");
|
|
matrixClient.uploadContent(new Blob([buffer])).then(function (response) {
|
|
matrixClient.sendMessage(viewingRoom.roomId, {
|
|
msgtype: MsgType.File,
|
|
body: filename,
|
|
url: response.content_uri,
|
|
});
|
|
});
|
|
} else {
|
|
matrixClient.sendTextMessage(viewingRoom.roomId, line).finally(function () {
|
|
printMessages();
|
|
rl.prompt();
|
|
});
|
|
// print local echo immediately
|
|
printMessages();
|
|
}
|
|
} else {
|
|
if (line.indexOf("/join ") === 0) {
|
|
var roomIndex = line.split(" ")[1];
|
|
viewingRoom = roomList[roomIndex];
|
|
if (viewingRoom.getMember(myUserId).membership === KnownMembership.Invite) {
|
|
// join the room first
|
|
matrixClient.joinRoom(viewingRoom.roomId).then(
|
|
function (room) {
|
|
setRoomList();
|
|
viewingRoom = room;
|
|
printMessages();
|
|
rl.prompt();
|
|
},
|
|
function (err) {
|
|
print("/join Error: %s", err);
|
|
},
|
|
);
|
|
} else {
|
|
printMessages();
|
|
}
|
|
}
|
|
}
|
|
rl.prompt();
|
|
});
|
|
// ==== END User input
|
|
|
|
// show the room list after syncing.
|
|
matrixClient.on(ClientEvent.Sync, function (state, prevState, data) {
|
|
switch (state) {
|
|
case "PREPARED":
|
|
setRoomList();
|
|
printRoomList();
|
|
printHelp();
|
|
rl.prompt();
|
|
break;
|
|
}
|
|
});
|
|
|
|
matrixClient.on(ClientEvent.Room, function () {
|
|
setRoomList();
|
|
if (!viewingRoom) {
|
|
printRoomList();
|
|
rl.prompt();
|
|
}
|
|
});
|
|
|
|
// print incoming messages.
|
|
matrixClient.on(RoomEvent.Timeline, function (event, room, toStartOfTimeline) {
|
|
if (toStartOfTimeline) {
|
|
return; // don't print paginated results
|
|
}
|
|
if (!viewingRoom || viewingRoom.roomId !== room?.roomId) {
|
|
return; // not viewing a room or viewing the wrong room.
|
|
}
|
|
printLine(event);
|
|
});
|
|
|
|
function setRoomList() {
|
|
roomList = matrixClient.getRooms();
|
|
roomList.sort(function (a, b) {
|
|
// < 0 = a comes first (lower index) - we want high indexes = newer
|
|
var aMsg = a.timeline[a.timeline.length - 1];
|
|
if (!aMsg) {
|
|
return -1;
|
|
}
|
|
var bMsg = b.timeline[b.timeline.length - 1];
|
|
if (!bMsg) {
|
|
return 1;
|
|
}
|
|
if (aMsg.getTs() > bMsg.getTs()) {
|
|
return 1;
|
|
} else if (aMsg.getTs() < bMsg.getTs()) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
});
|
|
}
|
|
|
|
function printRoomList() {
|
|
print(CLEAR_CONSOLE);
|
|
print("Room List:");
|
|
var fmts = {
|
|
invite: clc.cyanBright,
|
|
leave: clc.blackBright,
|
|
};
|
|
for (var i = 0; i < roomList.length; i++) {
|
|
var msg = roomList[i].timeline[roomList[i].timeline.length - 1];
|
|
var dateStr = "---";
|
|
var fmt;
|
|
if (msg) {
|
|
dateStr = new Date(msg.getTs()).toISOString().replace(/T/, " ").replace(/\..+/, "");
|
|
}
|
|
var myMembership = roomList[i].getMyMembership();
|
|
if (myMembership) {
|
|
fmt = fmts[myMembership];
|
|
}
|
|
var roomName = fixWidth(roomList[i].name, 25);
|
|
print(
|
|
"[%s] %s (%s members) %s",
|
|
i,
|
|
fmt ? fmt(roomName) : roomName,
|
|
roomList[i].getJoinedMembers().length,
|
|
dateStr,
|
|
);
|
|
}
|
|
}
|
|
|
|
function printHelp() {
|
|
var hlp = clc.italic.white;
|
|
print("Global commands:", hlp);
|
|
print(" '/help' : Show this help.", clc.white);
|
|
print("Room list index commands:", hlp);
|
|
print(" '/join <index>' Join a room, e.g. '/join 5'", clc.white);
|
|
print("Room commands:", hlp);
|
|
print(" '/exit' Return to the room list index.", clc.white);
|
|
print(" '/members' Show the room member list.", clc.white);
|
|
print(" '/invite @foo:bar' Invite @foo:bar to the room.", clc.white);
|
|
print(" '/more 15' Scrollback 15 events", clc.white);
|
|
print(" '/resend' Resend the oldest event which failed to send.", clc.white);
|
|
print(" '/roominfo' Display room info e.g. name, topic.", clc.white);
|
|
}
|
|
|
|
function completer(line) {
|
|
var completions = ["/help", "/join ", "/exit", "/members", "/more ", "/resend", "/invite"];
|
|
var hits = completions.filter(function (c) {
|
|
return c.indexOf(line) == 0;
|
|
});
|
|
// show all completions if none found
|
|
return [hits.length ? hits : completions, line];
|
|
}
|
|
|
|
function printMessages() {
|
|
if (!viewingRoom) {
|
|
printRoomList();
|
|
return;
|
|
}
|
|
print(CLEAR_CONSOLE);
|
|
var mostRecentMessages = viewingRoom.timeline;
|
|
for (var i = 0; i < mostRecentMessages.length; i++) {
|
|
printLine(mostRecentMessages[i]);
|
|
}
|
|
}
|
|
|
|
function printMemberList(room) {
|
|
var fmts = {
|
|
join: clc.green,
|
|
ban: clc.red,
|
|
invite: clc.blue,
|
|
leave: clc.blackBright,
|
|
};
|
|
var members = room.currentState.getMembers();
|
|
// sorted based on name.
|
|
members.sort(function (a, b) {
|
|
if (a.name > b.name) {
|
|
return -1;
|
|
}
|
|
if (a.name < b.name) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
});
|
|
print('Membership list for room "%s"', room.name);
|
|
print(new Array(room.name.length + 28).join("-"));
|
|
room.currentState.getMembers().forEach(function (member) {
|
|
if (!member.membership) {
|
|
return;
|
|
}
|
|
var fmt =
|
|
fmts[member.membership] ||
|
|
function (a) {
|
|
return a;
|
|
};
|
|
var membershipWithPadding = member.membership + new Array(10 - member.membership.length).join(" ");
|
|
print(
|
|
"%s" + fmt(" :: ") + "%s" + fmt(" (") + "%s" + fmt(")"),
|
|
membershipWithPadding,
|
|
member.name,
|
|
member.userId === myUserId ? "Me" : member.userId,
|
|
fmt,
|
|
);
|
|
});
|
|
}
|
|
|
|
function printRoomInfo(room) {
|
|
var eventMap = room.currentState.events;
|
|
var eTypeHeader = " Event Type(state_key) ";
|
|
var sendHeader = " Sender ";
|
|
// pad content to 100
|
|
var restCount = 100 - "Content".length - " | ".length - " | ".length - eTypeHeader.length - sendHeader.length;
|
|
var padSide = new Array(Math.floor(restCount / 2)).join(" ");
|
|
var contentHeader = padSide + "Content" + padSide;
|
|
print(eTypeHeader + sendHeader + contentHeader);
|
|
print(new Array(100).join("-"));
|
|
eventMap.keys().forEach(function (eventType) {
|
|
if (eventType === EventType.RoomMember) {
|
|
return;
|
|
} // use /members instead.
|
|
var eventEventMap = eventMap.get(eventType);
|
|
eventEventMap.keys().forEach(function (stateKey) {
|
|
var typeAndKey = eventType + (stateKey.length > 0 ? "(" + stateKey + ")" : "");
|
|
var typeStr = fixWidth(typeAndKey, eTypeHeader.length);
|
|
var event = eventEventMap.get(stateKey);
|
|
var sendStr = fixWidth(event.getSender(), sendHeader.length);
|
|
var contentStr = fixWidth(JSON.stringify(event.getContent()), contentHeader.length);
|
|
print(typeStr + " | " + sendStr + " | " + contentStr);
|
|
});
|
|
});
|
|
}
|
|
|
|
function printLine(event) {
|
|
var fmt;
|
|
var name = event.sender ? event.sender.name : event.getSender();
|
|
var time = new Date(event.getTs()).toISOString().replace(/T/, " ").replace(/\..+/, "");
|
|
var separator = "<<<";
|
|
if (event.getSender() === myUserId) {
|
|
name = "Me";
|
|
separator = ">>>";
|
|
if (event.status === sdk.EventStatus.SENDING) {
|
|
separator = "...";
|
|
fmt = clc.xterm(8);
|
|
} else if (event.status === sdk.EventStatus.NOT_SENT) {
|
|
separator = " x ";
|
|
fmt = clc.redBright;
|
|
}
|
|
}
|
|
var body = "";
|
|
|
|
var maxNameWidth = 15;
|
|
if (name.length > maxNameWidth) {
|
|
name = name.slice(0, maxNameWidth - 1) + "\u2026";
|
|
}
|
|
|
|
if (event.getType() === EventType.RoomMessage) {
|
|
body = event.getContent().body;
|
|
} else if (event.isState()) {
|
|
var stateName = event.getType();
|
|
if (event.getStateKey().length > 0) {
|
|
stateName += " (" + event.getStateKey() + ")";
|
|
}
|
|
body = "[State: " + stateName + " updated to: " + JSON.stringify(event.getContent()) + "]";
|
|
separator = "---";
|
|
fmt = clc.xterm(249).italic;
|
|
} else {
|
|
// random message event
|
|
body = "[Message: " + event.getType() + " Content: " + JSON.stringify(event.getContent()) + "]";
|
|
separator = "---";
|
|
fmt = clc.xterm(249).italic;
|
|
}
|
|
if (fmt) {
|
|
print("[%s] %s %s %s", time, name, separator, body, fmt);
|
|
} else {
|
|
print("[%s] %s %s %s", time, name, separator, body);
|
|
}
|
|
}
|
|
|
|
function print(str, formatter) {
|
|
if (typeof arguments[arguments.length - 1] === "function") {
|
|
// last arg is the formatter so get rid of it and use it on each
|
|
// param passed in but not the template string.
|
|
var newArgs = [];
|
|
var i = 0;
|
|
for (i = 0; i < arguments.length - 1; i++) {
|
|
newArgs.push(arguments[i]);
|
|
}
|
|
var fmt = arguments[arguments.length - 1];
|
|
for (i = 0; i < newArgs.length; i++) {
|
|
newArgs[i] = fmt(newArgs[i]);
|
|
}
|
|
console.log.apply(console.log, newArgs);
|
|
} else {
|
|
console.log.apply(console.log, [...arguments]);
|
|
}
|
|
}
|
|
|
|
function fixWidth(str, len) {
|
|
if (str.length > len) {
|
|
return str.substring(0, len - 2) + "\u2026";
|
|
} else if (str.length < len) {
|
|
return str + new Array(len - str.length).join(" ");
|
|
}
|
|
return str;
|
|
}
|
|
|
|
matrixClient.startClient({ initialSyncLimit: numMessagesToShow });
|