Feature: Tail live logs (#27)

* chore: add new yarn.lock

* chore: add pkgs

* feat: push events via server-sent-events

* feat(web): tail live logs

* fix: update irc network

* fix: set baseurl

* fix: headers
This commit is contained in:
Ludvig Lundgren 2021-09-07 22:23:27 +02:00 committed by GitHub
parent 11fcf1ead9
commit 09eb0b1716
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 213 additions and 26 deletions

View file

@ -7,6 +7,7 @@ import (
"os/signal"
"syscall"
"github.com/r3labs/sse/v2"
"github.com/rs/zerolog/log"
"github.com/spf13/pflag"
_ "modernc.org/sqlite"
@ -40,8 +41,14 @@ func main() {
// read config
cfg = config.Read(configPath)
// setup server-sent-events
serverEvents := sse.New()
serverEvents.AutoReplay = false
serverEvents.CreateStream("logs")
// setup logger
logger.Setup(cfg)
logger.Setup(cfg, serverEvents)
// if configPath is set then put database inside that path, otherwise create wherever it's run
var dataSource = database.DataSourceName(configPath, "autobrr.db")
@ -85,7 +92,7 @@ func main() {
errorChannel := make(chan error)
go func() {
httpServer := http.NewServer(addr, cfg.BaseURL, actionService, authService, downloadClientService, filterService, indexerService, ircService)
httpServer := http.NewServer(serverEvents, addr, cfg.BaseURL, actionService, authService, downloadClientService, filterService, indexerService, ircService)
errorChannel <- httpServer.Open()
}()

4
go.mod
View file

@ -4,13 +4,15 @@ go 1.16
require (
github.com/anacrolix/torrent v1.29.1
github.com/fluffle/goirc v1.0.3
github.com/gdm85/go-libdeluge v0.5.4
github.com/go-chi/chi v1.5.4
github.com/gorilla/sessions v1.2.1
github.com/gorilla/websocket v1.4.2
github.com/lib/pq v1.10.2
github.com/pelletier/go-toml v1.6.0 // indirect
github.com/pkg/errors v0.9.1
github.com/r3labs/sse/v2 v2.3.6
github.com/rs/cors v1.8.0
github.com/rs/zerolog v1.20.0
github.com/smartystreets/assertions v1.0.0 // indirect
github.com/spf13/pflag v1.0.3

23
go.sum
View file

@ -210,8 +210,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fluffle/goirc v1.0.3 h1:xyH13ALiX3ZkspwAmUZUg82YXmcMrShiZHvzZT5ZGEY=
github.com/fluffle/goirc v1.0.3/go.mod h1:SqQ+D/FJYnNf6btZfM1NsOkESlVw39Q5bvjjRUUQ2Ho=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@ -227,6 +225,8 @@ github.com/gdm85/go-libdeluge v0.5.4/go.mod h1:Fxm576GtD2fTcSUCSPqJINBZRkY8WrtGf
github.com/gdm85/go-rencode v0.1.6 h1:JbSv//2Og8aeSMUBMDTRNA6JW55iZbLMJU8bp9GqULY=
github.com/gdm85/go-rencode v0.1.6/go.mod h1:0dr3BuaKzeseY1of6o1KRTGB/Oo7eio+YEyz8KDp5+s=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
@ -245,6 +245,8 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@ -263,7 +265,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -319,6 +320,7 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gosuri/uilive v0.0.0-20170323041506-ac356e6e42cd/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
github.com/gosuri/uilive v0.0.3/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
@ -398,6 +400,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
@ -421,6 +424,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@ -589,11 +593,15 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/r3labs/sse/v2 v2.3.6 h1:9a67i0Jr2FLYiYpTdf0Z6+RxoE/N5O5XQrs4+fqYyT0=
github.com/r3labs/sse/v2 v2.3.6/go.mod h1:hUrYMKfu9WquG9MyI0r6TKiNH+6Sw/QPKm2YbNbU5g8=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
github.com/rs/dnscache v0.0.0-20190621150935-06bb5526f76b/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/rs/dnscache v0.0.0-20210201191234-295bba877686/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -685,6 +693,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
@ -766,7 +776,6 @@ golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -787,6 +796,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191125084936-ffdde1057850/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -845,6 +855,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -986,6 +997,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
@ -994,6 +1007,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=

View file

@ -9,11 +9,16 @@ import (
"github.com/autobrr/autobrr/web"
"github.com/go-chi/chi"
"github.com/r3labs/sse/v2"
"github.com/rs/cors"
)
type Server struct {
sse *sse.Server
address string
baseUrl string
actionService actionService
authService authService
downloadClientService downloadClientService
@ -22,10 +27,12 @@ type Server struct {
ircService ircService
}
func NewServer(address string, baseUrl string, actionService actionService, authService authService, downloadClientSvc downloadClientService, filterSvc filterService, indexerSvc indexerService, ircSvc ircService) Server {
func NewServer(sse *sse.Server, address string, baseUrl string, actionService actionService, authService authService, downloadClientSvc downloadClientService, filterSvc filterService, indexerSvc indexerService, ircSvc ircService) Server {
return Server{
sse: sse,
address: address,
baseUrl: baseUrl,
actionService: actionService,
authService: authService,
downloadClientService: downloadClientSvc,
@ -51,6 +58,17 @@ func (s Server) Open() error {
func (s Server) Handler() http.Handler {
r := chi.NewRouter()
c := cors.New(cors.Options{
AllowCredentials: true,
AllowedMethods: []string{"HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"},
AllowOriginFunc: func(origin string) bool { return true },
OptionsPassthrough: true,
// Enable Debugging for testing, consider disabling in production
Debug: false,
})
r.Use(c.Handler)
//r.Get("/", index)
//r.Get("/dashboard", dashboard)
@ -76,6 +94,19 @@ func (s Server) Handler() http.Handler {
r.Route("/filters", newFilterHandler(encoder, s.filterService).Routes)
r.Route("/irc", newIrcHandler(encoder, s.ircService).Routes)
r.Route("/indexer", newIndexerHandler(encoder, s.indexerService, s.ircService).Routes)
r.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) {
// inject CORS headers to bypass checks
s.sse.Headers = map[string]string{
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no",
}
s.sse.HTTPHandler(w, r)
})
})
})

View file

@ -408,7 +408,7 @@ func (s *Handler) handleMode(msg *irc.Message) error {
}
func (s *Handler) handlePing(msg *irc.Message) error {
log.Trace().Msgf("%v: PING %v", s.network.Server, msg)
log.Trace().Msgf("%v: %v", s.network.Server, msg)
pong := irc.Message{
Command: "PONG",

View file

@ -7,12 +7,13 @@ import (
"github.com/autobrr/autobrr/internal/domain"
"github.com/r3labs/sse/v2"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"gopkg.in/natefinch/lumberjack.v2"
)
func Setup(cfg domain.Config) {
func Setup(cfg domain.Config, sse *sse.Server) {
zerolog.TimeFieldFormat = time.RFC3339
switch cfg.LogLevel {
@ -47,6 +48,7 @@ func Setup(cfg domain.Config) {
writers = io.MultiWriter(consoleWriter, fileWriter)
}
log.Logger = log.Hook(&ServerSentEventHook{sse: sse})
log.Logger = log.Output(writers)
log.Print("Starting autobrr")

View file

@ -0,0 +1,43 @@
package logger
import (
"encoding/json"
"strings"
"time"
"github.com/r3labs/sse/v2"
"github.com/rs/zerolog"
)
type LogMessage struct {
Time string `json:"time"`
Level string `json:"level"`
Message string `json:"message"`
}
func (m LogMessage) ToJsonString() string {
j, err := json.Marshal(m)
if err != nil {
return ""
}
return string(j)
}
type ServerSentEventHook struct {
sse *sse.Server
}
func (h *ServerSentEventHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
if h.sse != nil {
// publish too logs topic
logMsg := LogMessage{
Time: time.Now().Format(time.RFC3339),
Level: strings.ToUpper(level.String()),
Message: msg,
}
h.sse.Publish("logs", &sse.Event{
Data: []byte(logMsg.ToJsonString()),
})
}
}

View file

@ -12,19 +12,19 @@
<link rel="apple-touch-icon" href="%PUBLIC_URL%/static/logo192.png" />
<link crossorigin="use-credentials" rel="manifest" href="%PUBLIC_URL%/static/manifest.json" />
<title>autobrr</title>
{{if eq .BaseUrl "/" }}
<!-- {{if eq .BaseUrl "/" }}
<base href="%PUBLIC_URL%/">
<script>
window.APP = {}
window.APP.baseUrl = "/"
</script>
{{else}}
{{else}} -->
<base href="{{.BaseUrl}}">
<script>
window.APP = {}
window.APP.baseUrl = "{{.BaseUrl}}"
</script>
{{end}}
<!-- {{end}} -->
</head>
<body class="bg-gray-100">
<noscript>You need to enable JavaScript to run this app.</noscript>

View file

@ -1,5 +1,5 @@
import {Action, DownloadClient, Filter, Indexer, Network} from "../domain/interfaces";
import {baseUrl} from "../utils/utils";
import {baseUrl, sseBaseUrl} from "../utils/utils";
function baseClient(endpoint: string, method: string, { body, ...customConfig}: any = {}) {
let baseURL = baseUrl()
@ -106,6 +106,9 @@ const APIClient = {
updateNetwork: (network: Network) => appClient.Put(`api/irc/network/${network.id}`, network),
deleteNetwork: (id: number) => appClient.Delete(`api/irc/network/${id}`),
},
events: {
logs: () => new EventSource(`${sseBaseUrl()}api/events?stream=logs`, { withCredentials: true })
}
}
export default APIClient;

View file

@ -58,11 +58,7 @@ function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
};
const validate = (values: any) => {
const errors = {
nickserv: {
account: null,
}
} as any;
const errors = {} as any;
if (!values.name) {
errors.name = "Required";
@ -125,7 +121,7 @@ function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
nickserv: network.nickserv,
pass: network.pass,
invite_command: network.invite_command,
connect_commands: network.connect_commands,
// connect_commands: network.connect_commands,
channels: network.channels
}}
mutators={{
@ -274,7 +270,7 @@ function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
</button>
<button
type="submit"
disabled={pristine || invalid}
// disabled={pristine || invalid}
className={classNames(pristine || invalid ? "bg-indigo-300" : "bg-indigo-600 hover:bg-indigo-700", "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500")}
>
Save

View file

@ -5,6 +5,7 @@ import {NavLink,Link, Route, Switch} from "react-router-dom";
import Settings from "./Settings";
import { Dashboard } from "./Dashboard";
import { FilterDetails, Filters} from "./Filters";
import Logs from './Logs';
const profile = ['Settings', 'Sign out']
@ -13,7 +14,7 @@ function classNames(...classes: string[]) {
}
export default function Base() {
const nav = [{name: 'Dashboard', path: "/"}, {name: 'Filters', path: "/filters"}, {name: "Settings", path: "/settings"}]
const nav = [{name: 'Dashboard', path: "/"}, {name: 'Filters', path: "/filters"}, {name: "Settings", path: "/settings"},{name: "Logs", path: "/logs"}]
return (
<div>
@ -180,6 +181,10 @@ export default function Base() {
</Disclosure>
<Switch>
<Route path="/logs">
<Logs />
</Route>
<Route path="/settings">
<Settings/>
</Route>

59
web/src/screens/Logs.tsx Normal file
View file

@ -0,0 +1,59 @@
import { useEffect, useRef, useState } from "react";
import APIClient from "../api/APIClient";
type LogEvent = {
time: string;
level: string;
message: string;
};
export default function Logs() {
const [logs, setLogs] = useState<LogEvent[]>([])
const messagesEndRef: any = useRef(null)
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "auto" })
}
useEffect(() => {
const es = APIClient.events.logs()
es.onmessage = (event) => {
let d: LogEvent = JSON.parse(event.data)
setLogs(prevState => ([...prevState, d]))
scrollToBottom()
}
return () => {
es.close()
}
}, [setLogs]);
return (
<main className="-mt-48">
<header className="py-10">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-3xl font-bold text-white capitalize">Logs</h1>
</div>
</header>
<div className="max-w-7xl mx-auto pb-12 px-2 sm:px-4 lg:px-8">
<div className="bg-white rounded-lg shadow px-2 sm:px-4 py-3 sm:py-4">
<div className=" overflow-y-auto p-2 rounded-lg h-96 bg-gray-900">
{logs.map((a, idx) => (
<p key={idx}>
<span className="font-mono text-gray-600 mr-2">{a.time}</span>
{a.level === "TRACE" && <span className="font-mono font-semibold text-purple-300">{a.level}</span>}
{a.level === "DEBUG" && <span className="font-mono font-semibold text-yellow-500">{a.level}</span>}
{a.level === "INFO" && <span className="font-mono font-semibold text-green-500">{a.level} </span>}
{a.level === "ERROR" && <span className="font-mono font-semibold text-red-500">{a.level}</span>}
<span className="ml-2 text-gray-300">{a.message}</span>
</p>
))}
<div ref={messagesEndRef} />
</div>
</div>
</div>
</main>
)
}

View file

@ -21,6 +21,18 @@ export function baseUrl() {
return baseUrl
}
// get sseBaseUrl for SSE
export function sseBaseUrl() {
let {origin} = window.location
let env = process.env.NODE_ENV
if (env === "development") {
return `http://localhost:8989/`
}
return `${origin}${baseUrl()}`
}
export function buildPath(...args: string[]): string {
const [first] = args;
const firstTrimmed = first.trim();

View file

@ -5599,6 +5599,11 @@ globby@^6.1.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
goober@^2.0.35:
version "2.0.41"
resolved "https://registry.yarnpkg.com/goober/-/goober-2.0.41.tgz#0a3d786ff9917bcf2a096eef703bf717838cbec9"
integrity sha512-kwjegMT5018zWydhOQlQneCgCtrKJaPsru7TaBWmTYV0nsMeUrM6L6O8JmNYb9UbPMgWcmtf+9p4Y3oJabIH1A==
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
version "4.2.8"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
@ -9506,6 +9511,13 @@ react-final-form@^6.5.3:
dependencies:
"@babel/runtime" "^7.12.1"
react-hot-toast@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.1.1.tgz#56409ab406b534e9e58274cf98d80355ba0fdda0"
integrity sha512-Odrp4wue0fHh0pOfZt5H+9nWCMtqs3wdlFSzZPp7qsxfzmbE26QmGWIh6hG43CukiPeOjA8WQhBJU8JwtWvWbQ==
dependencies:
goober "^2.0.35"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"