Skip to content
This repository has been archived by the owner on May 30, 2023. It is now read-only.

Commit

Permalink
Merge pull request #40 from t3chguy/develop
Browse files Browse the repository at this point in the history
0.2.0
  • Loading branch information
t3chguy authored Aug 29, 2017
2 parents 8ea7465 + e3884f2 commit 4bdfd0c
Show file tree
Hide file tree
Showing 397 changed files with 159,062 additions and 107 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ Accepts the following command line arguments:

### Support

Currently hosted at https://stormy-bastion-98790.herokuapp.com/
Currently hosted at https://view.matrix.org

Discussion Matrix Room is [#matrix-static:matrix.org](https://matrix.to/#/#matrix-static:matrix.org)
Discussion Matrix Room is [#matrix-static:matrix.org](https://matrix.to/#/#matrix-static:matrix.org)
4 changes: 4 additions & 0 deletions assets/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
body {
color: #454545;
background-color: #ffffff;
-webkit-rtl-ordering: visual;
}
#roomList {
border-collapse: collapse;
Expand Down Expand Up @@ -56,6 +57,9 @@ td.roomAvatar {
td.roomAvatar img {
height: 96px;
}
td.fullWidth {
white-space: nowrap;
}
table#roomHeader {
width: 100%;
}
Expand Down
11 changes: 11 additions & 0 deletions assets/img/browserconfig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/favicon-70.png"/>
<square150x150logo src="/favicon-150.png"/>
<square310x310logo src="/favicon-310.png"/>
<TileColor>#FFFFFF</TileColor>
</tile>
</msapplication>
</browserconfig>
Binary file added assets/img/favicon-114.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-120.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-144.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-150.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-152.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-160.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-310.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-57.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-60.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-70.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-72.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-76.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon-96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/favicon.ico
Binary file not shown.
Binary file added assets/img/matrix-static-48px.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/matrix-static.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions assets/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *
Disallow: /room/*/members/*
47 changes: 47 additions & 0 deletions src/github.com/t3chguy/matrix-static/job-room-aliases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2017 Michael Telatynski <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/t3chguy/matrix-static/mxclient"
"github.com/t3chguy/matrix-static/utils"
)

type RoomAliasesResp struct {
RoomInfo mxclient.RoomInfo
RoomAliases mxclient.RoomAliases
PageSize int
Page int
}

type RoomAliasesJob struct {
roomID string
page int
pageSize int
}

func (job RoomAliasesJob) Work(w *Worker) {
room := w.rooms[job.roomID]
aliases := room.GetState().Aliases

start, end := utils.CalcPaginationStartEnd(job.page, job.pageSize, len(aliases))

w.Output <- RoomAliasesResp{
room.RoomInfo(),
aliases[start:end],
job.pageSize,
job.page,
}
}
6 changes: 6 additions & 0 deletions src/github.com/t3chguy/matrix-static/job-room-initialsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package main

import log "github.com/Sirupsen/logrus"

type RoomInitialSyncResp struct {
err error
}
Expand All @@ -26,9 +28,13 @@ func (job RoomInitialSyncJob) Work(w *Worker) {
resp := &RoomInitialSyncResp{}

if _, exists := w.rooms[job.roomID]; !exists {
loggerWithFields := log.WithField("worker", w.ID).WithField("roomID", job.roomID)
loggerWithFields.Info("Started Initial Syncing Room")
if newRoom, err := w.client.NewRoom(job.roomID); err == nil {
loggerWithFields.Info("Finished Initial Syncing Room")
w.rooms[job.roomID] = newRoom
} else {
loggerWithFields.WithError(err).Error("Failed Initial Syncing Room")
resp.err = err
}
}
Expand Down
141 changes: 109 additions & 32 deletions src/github.com/t3chguy/matrix-static/matrix-static.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ package main
import (
"bytes"
"flag"
"fmt"
"github.com/disintegration/letteravatar"
"github.com/gin-contrib/cache"
"github.com/gin-contrib/cache/persistence"
"github.com/gin-contrib/pprof"
"github.com/gin-gonic/gin"
"github.com/matrix-org/dugong"
log "github.com/Sirupsen/logrus"
"github.com/t3chguy/go-gin-prometheus"
"github.com/t3chguy/matrix-static/mxclient"
"github.com/t3chguy/matrix-static/sanitizer"
Expand All @@ -31,47 +32,76 @@ import (
"image/png"
"net/http"
"os"
"path/filepath"
"strconv"
"time"
"unicode"
"unicode/utf8"
)

// TODO Cache memberList+serverList until it changes

const PublicRoomsPageSize = 20
const RoomTimelineSize = 30
const RoomMembersPageSize = 20

type configVars struct {
ConfigFile string
NumWorkers int

PublicServePrefix string
EnablePrometheusMetrics bool
EnablePprof bool

LogDir string
}

func main() {
configPath := flag.String("config-file", "./config.json", "The path to the desired config file.")
numWorkers := flag.Int("num-workers", 32, "Number of Worker goroutines to start.")
config := configVars{}

publicServePrefix := flag.String("public-serve-prefix", "/", "Prefix for publicly accessible routes.")
enablePrometheusMetrics := flag.Bool("enable-prometheus-metrics", false, "Whether or not to enable the /metrics endpoint.")
enablePprof := flag.Bool("enable-pprof", false, "Whether or not to enable the /debug/pprof endpoints.")
flag.StringVar(&config.ConfigFile, "config-file", "./config.json", "The path to the desired config file.")
flag.IntVar(&config.NumWorkers, "num-workers", 32, "Number of Worker goroutines to start.")

flag.StringVar(&config.PublicServePrefix, "public-serve-prefix", "/", "Prefix for publicly accessible routes.")
flag.BoolVar(&config.EnablePrometheusMetrics, "enable-prometheus-metrics", false, "Whether or not to enable the /metrics endpoint.")
flag.BoolVar(&config.EnablePprof, "enable-pprof", false, "Whether or not to enable the /debug/pprof endpoints.")
flag.StringVar(&config.LogDir, "logger-directory", "", "Where to write the info, warn and error logs to.")

flag.Parse()

client, err := mxclient.NewClient(*configPath)
if config.LogDir != "" {
log.AddHook(dugong.NewFSHook(
filepath.Join(config.LogDir, "info.log"),
filepath.Join(config.LogDir, "warn.log"),
filepath.Join(config.LogDir, "error.log"),
&log.TextFormatter{
TimestampFormat: "2006-01-02 15:04:05.000000",
DisableColors: true,
DisableTimestamp: false,
DisableSorting: false,
}, &dugong.DailyRotationSchedule{GZip: false},
))
}

log.Infof("Matrix-Static (%+v)", config)

client, err := mxclient.NewClient(config.ConfigFile)
if err != nil {
fmt.Println(err)
log.WithError(err).Error("Unable to start new Client")
return
}

worldReadableRooms := client.NewWorldReadableRooms()
workers := NewWorkers(uint32(*numWorkers), client)
workers := NewWorkers(uint32(config.NumWorkers), client)
sanitizerFn := sanitizer.InitSanitizer()

router := gin.New()
router.RedirectTrailingSlash = false

if *enablePprof {
if config.EnablePprof {
pprof.Register(router, nil)
}

// This is temporary until generated server-side in Synapse as suggested by riot-web issues.
avatarRouter := router.Group(*publicServePrefix)
avatarRouter := router.Group(config.PublicServePrefix)
avatarRouter.Use(gin.Recovery())
generatedAvatarCache := persistence.NewInMemoryStore(time.Hour)
avatarRouter.GET("/avatar/:identifier", cache.CachePage(generatedAvatarCache, time.Hour, func(c *gin.Context) {
Expand Down Expand Up @@ -100,22 +130,23 @@ func main() {
c.Writer.Header().Set("Content-Length", strconv.Itoa(len(buffer.Bytes())))
_, err = c.Writer.Write(buffer.Bytes())

//if err != nil {
// panic(err)
//}
if err != nil {
log.WithError(err).Error("Failed to write Image Buffer out.")
}
}))

publicRouter := router.Group(*publicServePrefix)
publicRouter := router.Group(config.PublicServePrefix)
publicRouter.Use(gin.Logger(), gin.Recovery())

if *enablePrometheusMetrics {
if config.EnablePrometheusMetrics {
ginProm := ginprometheus.NewPrometheus("http")
publicRouter.Use(ginProm.HandlerFunc())
router.GET(ginProm.MetricsPath, ginprometheus.PrometheusHandler())
}

publicRouter.Static("/img", "./assets/img")
publicRouter.Static("/css", "./assets/css")
publicRouter.StaticFile("/robots.txt", "./assets/robots.txt")

publicRouter.GET("/", func(c *gin.Context) {
page := utils.StrToIntDefault(c.DefaultQuery("page", "1"), 1)
Expand All @@ -126,29 +157,63 @@ func main() {
})
})

roomAliasCache := persistence.NewInMemoryStore(time.Hour)
publicRouter.GET("/alias/:roomAlias", cache.CachePage(roomAliasCache, time.Hour, func(c *gin.Context) {
roomAlias := c.Param("roomAlias")
resp, err := client.GetRoomDirectoryAlias(roomAlias)

// TODO better error page
if err != nil || resp.RoomID == "" {
templates.WritePageTemplate(c.Writer, &templates.ErrorPage{
ErrType: "Unable to resolve Room Alias.",
Error: err,
})
return
}

c.Redirect(http.StatusTemporaryRedirect, "/room/"+resp.RoomID+"/")
}))

roomRouter := publicRouter.Group("/room/:roomID/")
{
// Load room worker into request object so that we can do any clean up etc here
roomRouter.Use(func(c *gin.Context) {
roomID := c.Param("roomID")

if roomID[0] != '!' {
templates.WritePageTemplate(c.Writer, &templates.ErrorPage{
ErrType: "Unable to Load Room.",
Details: "Room ID must start with a '!'",
})
c.Abort()
return
}

worker := workers.GetWorkerForRoomID(roomID)

worker.Queue <- &RoomInitialSyncJob{roomID}
resp := (<-worker.Output).(*RoomInitialSyncResp)

if resp.err != nil {
c.String(http.StatusNotFound, "Room Not Found")
if respErr, ok := mxclient.UnwrapRespError(resp.err); ok {
templates.WritePageTemplate(c.Writer, &templates.ErrorPage{
ErrType: "Unable to Join Room.",
Details: mxclient.TextForRespError(respErr),
})
c.Abort()
return
}

templates.WritePageTemplate(c.Writer, &templates.ErrorPage{
ErrType: "Cannot Load Room. Internal Server Error.",
Error: err,
})
c.Abort()
return
}

c.Set("RoomWorker", worker)
c.Next()

// c.HTML(http.StatusInternalServerError, "room_error.html", gin.H{
// "Error": "Failed to load room.",
// "Room": room,
// })
})

roomRouter.GET("/", func(c *gin.Context) {
Expand Down Expand Up @@ -200,11 +265,9 @@ func main() {

roomRouter.GET("/servers", func(c *gin.Context) {
worker := c.MustGet("RoomWorker").(Worker)
page := utils.StrToIntDefault(c.DefaultQuery("page", "1"), 1)

worker.Queue <- RoomServersJob{
c.Param("roomID"),
page,
utils.StrToIntDefault(c.DefaultQuery("page", "1"), 1),
RoomServersPageSize,
}

Expand All @@ -220,13 +283,25 @@ func main() {
*/
})

roomRouter.GET("/members", func(c *gin.Context) {
const RoomAliasesPageSize = 10

roomRouter.GET("/aliases", func(c *gin.Context) {
worker := c.MustGet("RoomWorker").(Worker)
page := utils.StrToIntDefault(c.DefaultQuery("page", "1"), 1)
worker.Queue <- RoomAliasesJob{
c.Param("roomID"),
utils.StrToIntDefault(c.DefaultQuery("page", "1"), 1),
RoomAliasesPageSize,
}

jobResult := templates.RoomAliasesPage((<-worker.Output).(RoomAliasesResp))
templates.WritePageTemplate(c.Writer, &jobResult)
})

roomRouter.GET("/members", func(c *gin.Context) {
worker := c.MustGet("RoomWorker").(Worker)
worker.Queue <- RoomMembersJob{
c.Param("roomID"),
page,
utils.StrToIntDefault(c.DefaultQuery("page", "1"), 1),
RoomMembersPageSize,
}

Expand Down Expand Up @@ -263,7 +338,7 @@ func main() {

go startForwardPaginator(workers)
go startPublicRoomListTimer(worldReadableRooms)
fmt.Println("Listening on port " + port)
log.Info("Listening on port " + port)

srv := &http.Server{
ReadTimeout: 5 * time.Second,
Expand All @@ -273,7 +348,7 @@ func main() {
Addr: ":" + port,
}

panic(srv.ListenAndServe())
log.Fatal(srv.ListenAndServe())
}

const LoadPublicRoomsPeriod = time.Hour
Expand All @@ -282,6 +357,7 @@ func startPublicRoomListTimer(worldReadableRooms *mxclient.WorldReadableRooms) {
t := time.NewTicker(LoadPublicRoomsPeriod)
for {
<-t.C
log.Info("Reloading public room list")
worldReadableRooms.Update()
}
}
Expand All @@ -292,6 +368,7 @@ func startForwardPaginator(workers *Workers) {
t := time.NewTicker(LazyForwardPaginateRooms)
for {
<-t.C
log.Info("Forward paginating all loaded rooms")
workers.JobForAllWorkers(RoomForwardPaginateJob{})
}
}
Loading

0 comments on commit 4bdfd0c

Please sign in to comment.