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