mirror of
https://git.cyberia.club/cyberia/matrix-synapse-diskspace-janitor
synced 2024-05-31 23:02:12 +02:00
add delete rooms function
This commit is contained in:
parent
919490dcc2
commit
923f9b244d
62
frontend.go
62
frontend.go
|
@ -34,6 +34,7 @@ type FrontendApp struct {
|
|||
Port int
|
||||
Domain string
|
||||
Router *http.ServeMux
|
||||
DB *DBModel
|
||||
HTMLTemplates map[string]*template.Template
|
||||
cssHash string
|
||||
basicURLPathRegex *regexp.Regexp
|
||||
|
@ -47,9 +48,17 @@ type MatrixRoom struct {
|
|||
IdWithName string
|
||||
Rows int
|
||||
Percent int
|
||||
|
||||
Ban bool
|
||||
Status string
|
||||
}
|
||||
|
||||
func initFrontend(config *Config) FrontendApp {
|
||||
type DeleteProgress struct {
|
||||
Rooms []MatrixRoom
|
||||
StateGroupsStateProgress int
|
||||
}
|
||||
|
||||
func initFrontend(config *Config, db *DBModel) FrontendApp {
|
||||
|
||||
cssBytes, err := os.ReadFile(filepath.Join(".", "frontend", "static", "app.css"))
|
||||
if err != nil {
|
||||
|
@ -62,6 +71,7 @@ func initFrontend(config *Config) FrontendApp {
|
|||
Port: config.FrontendPort,
|
||||
Domain: config.FrontendDomain,
|
||||
Router: http.NewServeMux(),
|
||||
DB: db,
|
||||
HTMLTemplates: map[string]*template.Template{},
|
||||
basicURLPathRegex: regexp.MustCompile("(?i)[a-z0-9/?&_+-]+"),
|
||||
base58Regex: regexp.MustCompile("(?i)[a-z0-9_-]+"),
|
||||
|
@ -74,14 +84,43 @@ func initFrontend(config *Config) FrontendApp {
|
|||
|
||||
userIsLoggedIn := session.UserID != ""
|
||||
if userIsLoggedIn {
|
||||
|
||||
deleteProgress, err := ReadJsonFile[DeleteProgress]("data/deleteRooms.json")
|
||||
if err != nil {
|
||||
(*session.Flash)["error"] = "an error occurred reading deleteRooms json"
|
||||
}
|
||||
if deleteProgress.Rooms != nil && len(deleteProgress.Rooms) > 0 {
|
||||
app.buildPageFromTemplate(responseWriter, request, session, "deleting.html", deleteProgress)
|
||||
return
|
||||
}
|
||||
|
||||
if request.Method == "POST" {
|
||||
toDelete := []MatrixRoom{}
|
||||
for i := 0; i < 20; i++ {
|
||||
roomId := request.PostFormValue(fmt.Sprintf("id_%d", i))
|
||||
delete := request.PostFormValue(fmt.Sprintf("delete_%d", i))
|
||||
ban := request.PostFormValue(fmt.Sprintf("ban_%d", i))
|
||||
|
||||
log.Printf("%s %s %s", roomId, delete, ban)
|
||||
if roomId != "" && (delete != "" || ban != "") {
|
||||
toDelete = append(toDelete, MatrixRoom{
|
||||
Id: roomId,
|
||||
Ban: ban != "",
|
||||
IdWithName: fmt.Sprintf("%s: %s", roomId, app.getMatrixRoomNameWithCache(roomId)),
|
||||
Status: "...",
|
||||
})
|
||||
}
|
||||
}
|
||||
err := WriteJsonFile("data/deleteRooms.json", DeleteProgress{
|
||||
Rooms: toDelete,
|
||||
})
|
||||
if err != nil {
|
||||
(*session.Flash)["error"] = "an error occurred saving deleteRooms json"
|
||||
}
|
||||
|
||||
go doRoomDeletes(app.DB)
|
||||
|
||||
http.Redirect(responseWriter, request, "/", http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
diskUsage, err := os.ReadFile("data/diskUsage.json")
|
||||
|
@ -117,10 +156,7 @@ func initFrontend(config *Config) FrontendApp {
|
|||
bigRoomsRowCount := 0
|
||||
for i, room := range biggestRooms {
|
||||
// TODO cache this ??
|
||||
name, err := matrixAdmin.GetRoomName(room.Id)
|
||||
if err != nil {
|
||||
log.Printf("error getting name for '%s': %s\n", room.Id, err)
|
||||
}
|
||||
name := app.getMatrixRoomNameWithCache(room.Id)
|
||||
biggestRooms[i] = MatrixRoom{
|
||||
Id: room.Id,
|
||||
Name: name,
|
||||
|
@ -405,3 +441,17 @@ func (app *FrontendApp) reloadTemplates() {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func (app *FrontendApp) getMatrixRoomNameWithCache(id string) string {
|
||||
nameFromCache, hasNameFromCache := app.roomNameCache[id]
|
||||
if hasNameFromCache {
|
||||
return nameFromCache
|
||||
}
|
||||
name, err := matrixAdmin.GetRoomName(id)
|
||||
if err != nil {
|
||||
log.Printf("error getting name for '%s': %s\n", id, err)
|
||||
} else {
|
||||
app.roomNameCache[id] = name
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
|
22
frontend/deleting.gotemplate.html
Normal file
22
frontend/deleting.gotemplate.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<div class="horizontal justify-center wrap">
|
||||
<h3>deleting...</h3>
|
||||
|
||||
<div>
|
||||
{{ range $i, $room := .Rooms }}
|
||||
{{ if $room.Id }}
|
||||
<div class="horizontal align-center">
|
||||
|
||||
<label for="ban_{{ $i }}" >BAN</span>
|
||||
<input id="ban_{{ $i }}" type="checkbox" disabled value="{{if $room.Ban }}on{{ end }}"></input>
|
||||
<span> STATUS: {{ $room.Status }} {{ $room.IdWithName }}</span>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ if .StateGroupsStateProgress > 0 }}
|
||||
<p>
|
||||
Progress of deleting rows from <code>state_groups_state</code>: {{ .StateGroupsStateProgress }}%
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
144
main.go
144
main.go
|
@ -1,9 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -36,6 +38,7 @@ type DiskUsage struct {
|
|||
}
|
||||
|
||||
var isRunningScheduledTask bool
|
||||
var isDoingDeletes bool
|
||||
var mutex sync.Mutex
|
||||
var matrixAdmin *MatrixAdmin
|
||||
|
||||
|
@ -56,7 +59,7 @@ func main() {
|
|||
|
||||
db := initDatabase(&config)
|
||||
matrixAdmin = initMatrixAdmin(&config)
|
||||
frontend := initFrontend(&config)
|
||||
frontend := initFrontend(&config, db)
|
||||
|
||||
log.Printf("🧹 matrix-synapse-diskspace-janitor is about to try to start listening on :%d\n", config.FrontendPort)
|
||||
go frontend.ListenAndServe()
|
||||
|
@ -149,7 +152,7 @@ func runScheduledTask(db *DBModel, config *Config) {
|
|||
}
|
||||
}
|
||||
|
||||
err = WriteJsonFile[map[string]int]("data/stateGroupsStateRowCountByRoom.json", rowCountByRoom)
|
||||
err = WriteJsonFile("data/stateGroupsStateRowCountByRoom.json", rowCountByRoom)
|
||||
if err != nil {
|
||||
log.Printf("ERROR!: runScheduledTask can't write data/stateGroupsStateRowCountByRoom.json: %s\n", err)
|
||||
}
|
||||
|
@ -163,7 +166,7 @@ func runScheduledTask(db *DBModel, config *Config) {
|
|||
|
||||
janitorState.LastScheduledTaskRunUnixMilli = time.Now().UnixMilli()
|
||||
|
||||
err = WriteJsonFile[JanitorState]("data/janitorState.json", janitorState)
|
||||
err = WriteJsonFile("data/janitorState.json", janitorState)
|
||||
if err != nil {
|
||||
log.Printf("ERROR!: runScheduledTask can't write data/janitorState.json: %s\n", err)
|
||||
}
|
||||
|
@ -172,6 +175,141 @@ func runScheduledTask(db *DBModel, config *Config) {
|
|||
isRunningScheduledTask = false
|
||||
}
|
||||
|
||||
func doRoomDeletes(db *DBModel) {
|
||||
if isDoingDeletes {
|
||||
log.Println("doRoomDeletes(): isDoingDeletes already!")
|
||||
return
|
||||
}
|
||||
isDoingDeletes = true
|
||||
defer func() {
|
||||
isDoingDeletes = false
|
||||
}()
|
||||
|
||||
deleteProgress, err := ReadJsonFile[DeleteProgress]("data/deleteRooms.json")
|
||||
if err != nil {
|
||||
log.Println("doRoomDeletes(): Can't do room deletes because can't read deleteRooms.json")
|
||||
return
|
||||
}
|
||||
|
||||
if deleteProgress.Rooms == nil || len(deleteProgress.Rooms) == 0 {
|
||||
log.Println("doRoomDeletes(): Can't do room deletes because no rooms to delete")
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("doRoomDeletes(): starting to delete %d rooms\n", len(deleteProgress.Rooms))
|
||||
|
||||
for _, room := range deleteProgress.Rooms {
|
||||
err := matrixAdmin.DeleteRoom(room.Id, room.Ban)
|
||||
if err != nil {
|
||||
log.Printf("doRoomDeletes(): Can't do room deletes because deleting %s returned %s\n", room.Id, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("doRoomDeletes(): waiting for %d rooms to be done deleting...\n", len(deleteProgress.Rooms))
|
||||
|
||||
isDoneWaitingForRoomDeletesToFinish := false
|
||||
for !isDoneWaitingForRoomDeletesToFinish {
|
||||
|
||||
allRoomsDeletionComplete := true
|
||||
for i, room := range deleteProgress.Rooms {
|
||||
// TODO do something with the users that this returns? i.e. re-add them to the room later?
|
||||
status, _, err := matrixAdmin.GetDeleteRoomStatus(room.Id)
|
||||
if err != nil {
|
||||
log.Printf("doRoomDeletes(): Can't do room deletes because GetDeleteRoomStatus('%s') returned %s\n", room.Id, err)
|
||||
return
|
||||
}
|
||||
deleteProgress.Rooms[i] = MatrixRoom{
|
||||
Id: room.Id,
|
||||
IdWithName: room.IdWithName,
|
||||
Ban: room.Ban,
|
||||
Status: status,
|
||||
}
|
||||
|
||||
if status != "complete" {
|
||||
allRoomsDeletionComplete = false
|
||||
}
|
||||
}
|
||||
|
||||
err = WriteJsonFile("data/deleteRooms.json", deleteProgress)
|
||||
if err != nil {
|
||||
log.Println("doRoomDeletes(): Can't do room deletes because can't write deleteRooms.json")
|
||||
return
|
||||
}
|
||||
|
||||
if allRoomsDeletionComplete {
|
||||
isDoneWaitingForRoomDeletesToFinish = true
|
||||
} else {
|
||||
time.Sleep(time.Second * 5)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("doRoomDeletes(): getting state group ids for %d rooms...\n", len(deleteProgress.Rooms))
|
||||
|
||||
allStateGroupsToDelete := []int64{}
|
||||
for _, room := range deleteProgress.Rooms {
|
||||
stateGroups, err := db.GetStateGroupsForRoom(room.Id)
|
||||
if err != nil {
|
||||
log.Printf("doRoomDeletes(): Can't do room deletes because getting state group ids for %s returned %s\n", room.Id, err)
|
||||
return
|
||||
}
|
||||
allStateGroupsToDelete = append(allStateGroupsToDelete, stateGroups...)
|
||||
}
|
||||
|
||||
sort.Slice(allStateGroupsToDelete, func(i, j int) bool {
|
||||
return allStateGroupsToDelete[i] < allStateGroupsToDelete[j]
|
||||
})
|
||||
|
||||
allStateGroupsToDeleteFile, err := os.OpenFile("data/stateGroupsToDelete.txt", os.O_CREATE|os.O_WRONLY, 0644)
|
||||
for _, stateGroupId := range allStateGroupsToDelete {
|
||||
fmt.Fprintf(allStateGroupsToDeleteFile, "%d\n", stateGroupId)
|
||||
}
|
||||
allStateGroupsToDeleteFile.Close()
|
||||
|
||||
log.Printf("doRoomDeletes(): deleting %d state groups from state_groups_state...\n", len(allStateGroupsToDelete))
|
||||
|
||||
statusChannel := db.DeleteStateGroupsState(allStateGroupsToDelete, 0)
|
||||
lastUpdateTime := time.Now()
|
||||
for status := range statusChannel {
|
||||
if time.Since(lastUpdateTime) > time.Second*5 {
|
||||
lastUpdateTime = time.Now()
|
||||
deleteProgress.StateGroupsStateProgress = int((float64(status.StateGroupsDeleted) / float64(len(allStateGroupsToDelete))) * float64(100))
|
||||
|
||||
log.Printf(
|
||||
"doRoomDeletes(): %d/%d (%d rows) (%d errors) (%d%s)\n",
|
||||
status.StateGroupsDeleted, len(allStateGroupsToDelete), status.RowsDeleted,
|
||||
status.Errors, deleteProgress.StateGroupsStateProgress, "%",
|
||||
)
|
||||
|
||||
err = WriteJsonFile("data/deleteRooms.json", deleteProgress)
|
||||
if err != nil {
|
||||
log.Println("doRoomDeletes(): Can't do room deletes because can't write deleteRooms.json")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("doRoomDeletes(): deleting from state_groups_state complete! now cleaning up state_groups...")
|
||||
|
||||
totalStateGroupRows := 0
|
||||
for _, room := range deleteProgress.Rooms {
|
||||
rowsDeleted, err := db.DeleteStateGroupsForRoom(room.Id)
|
||||
if err != nil {
|
||||
log.Printf("doRoomDeletes(): DeleteStateGroupsForRoom('%s') returned %s\n", room.Id, err)
|
||||
}
|
||||
totalStateGroupRows += int(rowsDeleted)
|
||||
}
|
||||
|
||||
log.Printf("doRoomDeletes(): %d state_groups related rows deleted. \n", totalStateGroupRows)
|
||||
|
||||
err = os.Remove("data/deleteRooms.json")
|
||||
if err != nil {
|
||||
log.Printf("doRoomDeletes(): failed to remove deleteRooms.json: %s\n", err)
|
||||
}
|
||||
|
||||
log.Println("doRoomDeletes(): completed successfully!!")
|
||||
}
|
||||
|
||||
func validateConfig(config *Config) {
|
||||
|
||||
errors := []string{}
|
||||
|
|
|
@ -88,10 +88,10 @@ func initMatrixAdmin(config *Config) *MatrixAdmin {
|
|||
// curl -H "Content-Type: application/json" -X DELETE "localhost:8008/_synapse/admin/v2/rooms/$roomid?access_token=xxxxxxxxx" \
|
||||
// --data '{ "block": false, "force_purge": true, "purge": true, "message": "This room is being cleaned, stand by..." }'
|
||||
|
||||
func (admin *MatrixAdmin) DeleteRoom(roomId string) error {
|
||||
func (admin *MatrixAdmin) DeleteRoom(roomId string, ban bool) error {
|
||||
|
||||
deleteRequestBodyObject := DeleteRoomRequest{
|
||||
Block: false,
|
||||
Block: ban,
|
||||
ForcePurge: true,
|
||||
Purge: true,
|
||||
Message: "This room is being cleaned, stand by...",
|
||||
|
|
Loading…
Reference in a new issue