commit
579ab4ccb7
9 changed files with 3703 additions and 0 deletions
@ -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> |
|||
); |
|||
}; |
File diff suppressed because it is too large
Loading…
Reference in new issue