Initial commit
commit
579ab4ccb7
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
@ -0,0 +1,78 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const Promise = require("bluebird");
|
||||||
|
const express = require("express");
|
||||||
|
const expressPromiseRouter = require("express-promise-router");
|
||||||
|
const expressReactViews = require("@joepie91/express-react-views");
|
||||||
|
const path = require("path");
|
||||||
|
const url = require("url");
|
||||||
|
const autodiscoverClientConfiguration = require("@modular-matrix/autodiscover-client-configuration");
|
||||||
|
const bhttp = require("bhttp");
|
||||||
|
const createError = require("create-error");
|
||||||
|
|
||||||
|
let UpstreamError = createError("UpstreamError");
|
||||||
|
|
||||||
|
function generateSince(hostname, token) {
|
||||||
|
return url.format({ pathname: "/show-rooms", query: {
|
||||||
|
hostname: hostname,
|
||||||
|
since: token
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = express();
|
||||||
|
|
||||||
|
app.set("views", path.join(__dirname, "views"));
|
||||||
|
app.set("view engine", "jsx");
|
||||||
|
app.engine("jsx", expressReactViews.createEngine());
|
||||||
|
|
||||||
|
app.use(express.static(path.join(__dirname, "public")));
|
||||||
|
|
||||||
|
let router = expressPromiseRouter();
|
||||||
|
|
||||||
|
router.get("/", (req, res) => {
|
||||||
|
res.render("index");
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/show-rooms", (req, res) => {
|
||||||
|
return Promise.try(() => {
|
||||||
|
return autodiscoverClientConfiguration.discover(req.query.hostname);
|
||||||
|
}).then((clientConfiguration) => {
|
||||||
|
let roomsUrl = url.format({
|
||||||
|
... url.parse(clientConfiguration.homeserver),
|
||||||
|
pathname: "/_matrix/client/r0/publicRooms",
|
||||||
|
query: { since: req.query.since }
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.try(() => {
|
||||||
|
return bhttp.get(roomsUrl);
|
||||||
|
}).then((response) => {
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
console.log(response.body);
|
||||||
|
// next_batch
|
||||||
|
res.render("rooms", {
|
||||||
|
rooms: response.body.chunk,
|
||||||
|
nextBatchUrl: (response.body.next_batch != null)
|
||||||
|
? generateSince(req.query.hostname, response.body.next_batch)
|
||||||
|
: null,
|
||||||
|
previousBatchUrl: (response.body.previous_batch != null)
|
||||||
|
? generateSince(req.query.hostname, response.body.previous_batch)
|
||||||
|
: null,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new UpstreamError(`Non-200 status code received from homeserver: ${response.statusCode}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(router);
|
||||||
|
|
||||||
|
app.use((error, req, res, next) => {
|
||||||
|
if (error instanceof UpstreamError || error instanceof autodiscoverClientConfiguration.LookupFailed) {
|
||||||
|
res.render("error", { error: error });
|
||||||
|
} else {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000);
|
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "matrix-room-list-viewer",
|
||||||
|
"description": "A simple tool for viewing the list of public rooms on a given Matrix server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"repository": "git@git.cryto.net:joepie91/matrix-room-list-viewer.git",
|
||||||
|
"author": "Sven Slootweg <admin@cryto.net>",
|
||||||
|
"license": "WTFPL OR CC0-1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@joepie91/express-react-views": "^1.0.1",
|
||||||
|
"@modular-matrix/autodiscover-client-configuration": "^1.0.0",
|
||||||
|
"bhttp": "^1.2.4",
|
||||||
|
"bluebird": "^3.5.5",
|
||||||
|
"create-error": "^0.3.1",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-promise-router": "^3.0.3",
|
||||||
|
"react": "^16.9.0",
|
||||||
|
"react-dom": "^16.9.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^1.19.1"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room .name, .room .alias, .room .userCount {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room .name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room .alias {
|
||||||
|
color: rgb(58, 58, 58);
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const React = require("react");
|
||||||
|
|
||||||
|
const Layout = require("./layout");
|
||||||
|
|
||||||
|
module.exports = function Error({ error }) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
{error.message}
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const React = require("react");
|
||||||
|
|
||||||
|
const Layout = require("./layout");
|
||||||
|
|
||||||
|
function Field({ id, type, name, label, children }) {
|
||||||
|
return (
|
||||||
|
<div className="formField">
|
||||||
|
<label htmlFor={`field_${id}`}>{label}</label>
|
||||||
|
<input type={type} name={name} id={`field_${id}`} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function Index() {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<form method="get" action="/show-rooms">
|
||||||
|
<Field label="Homeserver" type="text" name="hostname" id="homeserver" />
|
||||||
|
<button type="submit">Show rooms</button>
|
||||||
|
</form>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const React = require("react");
|
||||||
|
|
||||||
|
module.exports = function Layout({ children }) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charSet="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<meta httpEquiv="X-UA-Compatible" content="ie=edge"/>
|
||||||
|
<link rel="stylesheet" href="/style.css"/>
|
||||||
|
<title>Matrix Room List Viewer</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div className="container">
|
||||||
|
<h1>Matrix Room List Viewer</h1>
|
||||||
|
<hr/>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,40 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const React = require("react");
|
||||||
|
|
||||||
|
const Layout = require("./layout");
|
||||||
|
|
||||||
|
function Room({ room }) {
|
||||||
|
return (
|
||||||
|
<div className="room">
|
||||||
|
<div className="name">{room.name}</div>
|
||||||
|
<div className="userCount">{room.num_joined_members} users</div>
|
||||||
|
<div className="alias">{room.canonical_alias}</div>
|
||||||
|
<div className="topic">{room.topic}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function Rooms({ rooms, nextBatchUrl, previousBatchUrl }) {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<div className="navigation">
|
||||||
|
{(previousBatchUrl != null)
|
||||||
|
? <a href={previousBatchUrl}><< Previous</a>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{(previousBatchUrl != null && nextBatchUrl != null)
|
||||||
|
? " | "
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{(nextBatchUrl != null)
|
||||||
|
? <a href={nextBatchUrl}>Next >></a>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
{rooms.map((room) => {
|
||||||
|
return <Room key={room.id} room={room} />;
|
||||||
|
})}
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue