feature: add stats endpoints

This commit is contained in:
divyam234 2024-04-19 02:16:47 +05:30
parent 3774c2974c
commit 6364f86571
21 changed files with 244 additions and 100 deletions

View file

@ -28,6 +28,7 @@ func InitRouter(r *gin.Engine, c *controller.Controller, cnf *config.Config) *gi
files.PATCH(":fileID", authmiddleware, c.UpdateFile)
files.HEAD(":fileID/stream/:fileName", c.GetFileStream)
files.GET(":fileID/stream/:fileName", c.GetFileStream)
files.GET("/category/stats", authmiddleware, c.GetCategoryStats)
files.POST("/move", authmiddleware, c.MoveFiles)
files.POST("/directories", authmiddleware, c.MakeDirectory)
files.POST("/delete", authmiddleware, c.DeleteFiles)
@ -37,6 +38,7 @@ func InitRouter(r *gin.Engine, c *controller.Controller, cnf *config.Config) *gi
uploads := api.Group("/uploads")
{
uploads.Use(authmiddleware)
uploads.GET("/stats", c.UploadStats)
uploads.GET(":id", c.GetUploadFileById)
uploads.POST(":id", c.UploadFile)
uploads.DELETE(":id", c.DeleteUploadFile)
@ -46,7 +48,6 @@ func InitRouter(r *gin.Engine, c *controller.Controller, cnf *config.Config) *gi
users.Use(authmiddleware)
users.GET("/profile", c.GetProfilePhoto)
users.GET("/stats", c.GetStats)
users.GET("/bots", c.GetBots)
users.GET("/channels", c.ListChannels)
users.PATCH("/channels", c.UpdateChannel)
users.POST("/bots", c.AddBots)

View file

@ -101,7 +101,13 @@ func runApplication(conf *config.Config) {
Development: conf.Log.Development,
FilePath: conf.Log.File,
})
defer logging.DefaultLogger().Sync()
tgContext, cancel := context.WithCancel(context.Background())
defer func() {
logging.DefaultLogger().Sync()
cancel()
}()
app := fx.New(
fx.Supply(conf),
@ -115,7 +121,7 @@ func runApplication(conf *config.Config) {
fx.Provide(
database.NewDatabase,
kv.NewBoltKV,
tgc.NewStreamWorker,
tgc.NewStreamWorker(tgContext),
tgc.NewUploadWorker,
services.NewAuthService,
services.NewFileService,

22
go.mod
View file

@ -29,11 +29,11 @@ require (
)
require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@ -50,10 +50,10 @@ require (
github.com/spf13/cast v1.6.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/dig v1.17.1 // indirect
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect
google.golang.org/grpc v1.60.1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc v1.63.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)
@ -83,7 +83,7 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
@ -95,18 +95,18 @@ require (
github.com/stretchr/testify v1.9.0
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect
go.opentelemetry.io/otel/trace v1.25.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.22.0
golang.org/x/net v0.22.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.10 // indirect
nhooyr.io/websocket v1.8.11 // indirect
rsc.io/qr v0.2.0 // indirect
)

52
go.sum
View file

@ -21,8 +21,8 @@ github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf5
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
@ -105,8 +105,8 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@ -154,8 +154,8 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@ -290,10 +290,10 @@ github.com/ydb-platform/ydb-go-sdk/v3 v3.55.1/go.mod h1:udNPW8eupyH/EZocecFmaSNJ
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k=
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM=
go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
@ -315,25 +315,25 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo=
golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -364,16 +364,16 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
@ -413,8 +413,8 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q=
nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=

View file

@ -0,0 +1,52 @@
package catregory
import (
"path/filepath"
"strings"
)
type Category string
const (
Document Category = "document"
Image Category = "image"
Video Category = "video"
Audio Category = "audio"
Archive Category = "archive"
Other Category = "other"
)
var (
documentExtensions = []string{"doc", "docx", "ppt", "pptx", "pps", "ppsx", "odt", "xls", "xlsx", "csv", "pdf", "txt"}
imageExtensions = []string{"jpg", "jpeg", "png", "gif", "bmp", "svg"}
videoExtensions = []string{"mp4", "webm", "mov", "avi", "m4v", "flv", "wmv", "mkv", "mpg", "mpeg", "m2v", "mpv"}
audioExtensions = []string{"mp3", "wav", "ogg", "m4a", "flac", "aac", "wma", "aiff", "ape", "alac", "opus", "pcm"}
archiveExtensions = []string{"zip", "rar", "tar", "gz", "7z", "iso", "dmg", "pkg"}
)
func GetCategory(fileName string) Category {
fileExtension := strings.ToLower(filepath.Ext(fileName))
if contains(documentExtensions, fileExtension) {
return Document
} else if contains(imageExtensions, fileExtension) {
return Image
} else if contains(videoExtensions, fileExtension) {
return Video
} else if contains(audioExtensions, fileExtension) {
return Audio
} else if contains(archiveExtensions, fileExtension) {
return Archive
} else {
return Other
}
}
func contains(slice []string, item string) bool {
for _, a := range slice {
if a == item {
return true
}
}
return false
}

View file

@ -20,7 +20,7 @@ func NewDatabase(cfg *config.Config) (*gorm.DB, error) {
logger = NewLogger(time.Second, true, zapcore.Level(cfg.DB.LogLevel))
)
for i := 0; i <= 30; i++ {
for i := 0; i <= 10; i++ {
db, err = gorm.Open(postgres.Open(cfg.DB.DataSource), &gorm.Config{
Logger: logger,
NamingStrategy: schema.NamingStrategy{
@ -38,7 +38,7 @@ func NewDatabase(cfg *config.Config) (*gorm.DB, error) {
time.Sleep(500 * time.Millisecond)
}
if err != nil {
return nil, err
logging.DefaultLogger().Fatalf("database: %v", err)
}
rawDB, err := db.DB()

View file

@ -0,0 +1,32 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE "teldrive"."files" ADD COLUMN "category" text;
CREATE INDEX IF NOT EXISTS "files_category_type_user_id_index" ON "teldrive"."files" ("category","type","user_id");
UPDATE teldrive.files
SET category =
CASE
WHEN name ILIKE '%.doc%' OR name ILIKE '%.docx%' OR name ILIKE '%.ppt%' OR name ILIKE '%.pptx%' OR
name ILIKE '%.pps%' OR name ILIKE '%.ppsx%' OR name ILIKE '%.odt%' OR name ILIKE '%.xls%' OR
name ILIKE '%.xlsx%' OR name ILIKE '%.csv%' OR name ILIKE '%.pdf%' OR name ILIKE '%.txt%'
THEN 'document'
WHEN name ILIKE '%.jpg%' OR name ILIKE '%.jpeg%' OR name ILIKE '%.png%' OR
name ILIKE '%.gif%' OR name ILIKE '%.bmp%' OR name ILIKE '%.svg%'
THEN 'image'
WHEN name ILIKE '%.mp4%' OR name ILIKE '%.webm%' OR name ILIKE '%.mov%' OR
name ILIKE '%.avi%' OR name ILIKE '%.m4v%' OR name ILIKE '%.flv%' OR
name ILIKE '%.wmv%' OR name ILIKE '%.mkv%' OR name ILIKE '%.mpg%' OR
name ILIKE '%.mpeg%' OR name ILIKE '%.m2v%' OR name ILIKE '%.mpv%'
THEN 'video'
WHEN name ILIKE '%.mp3%' OR name ILIKE '%.wav%' OR name ILIKE '%.ogg%' OR
name ILIKE '%.m4a%' OR name ILIKE '%.flac%' OR name ILIKE '%.aac%' OR
name ILIKE '%.wma%' OR name ILIKE '%.aiff%' OR name ILIKE '%.ape%' OR
name ILIKE '%.alac%' OR name ILIKE '%.opus%' OR name ILIKE '%.pcm%'
THEN 'audio'
WHEN name ILIKE '%.zip%' OR name ILIKE '%.rar%' OR name ILIKE '%.tar%' OR name ILIKE '%.gz%' OR
name ILIKE '%.7z%' OR name ILIKE '%.iso%' OR name ILIKE '%.dmg%' OR name ILIKE '%.pkg%'
THEN 'archive'
ELSE 'other'
END
WHERE type = 'file';
-- +goose StatementEnd

View file

@ -11,20 +11,6 @@ import (
"github.com/gotd/td/tgerr"
)
func hasError(err error, target string) bool {
for err != nil {
if err.Error() == target {
return true
}
if unwrapper, ok := err.(interface{ Unwrap() error }); ok {
err = unwrapper.Unwrap()
} else {
break
}
}
return false
}
type recovery struct {
ctx context.Context
backoff backoff.BackOff
@ -61,10 +47,7 @@ func (r *recovery) shouldRecover(err error) bool {
default:
}
//recover only if context is not cancelled and error is not a rpc error
isContextErr := hasError(err, "context canceled")
_, ok := tgerr.As(err)
return !isContextErr && !ok
return !errors.Is(err, context.Canceled) && !ok
}

View file

@ -28,18 +28,7 @@ func defaultMiddlewares(ctx context.Context) ([]telegram.Middleware, error) {
func New(ctx context.Context, config *config.TGConfig, handler telegram.UpdateHandler, storage session.Storage, middlewares ...telegram.Middleware) *telegram.Client {
_clock := tdclock.System
noUpdates := true
if handler != nil {
noUpdates = false
}
opts := telegram.Options{
ReconnectionBackoff: func() backoff.BackOff {
return Backoff(_clock)
},
Device: telegram.DeviceConfig{
DeviceModel: config.DeviceModel,
SystemVersion: config.SystemVersion,
@ -53,8 +42,6 @@ func New(ctx context.Context, config *config.TGConfig, handler telegram.UpdateHa
MaxRetries: 10,
DialTimeout: 10 * time.Second,
Middlewares: middlewares,
Clock: _clock,
NoUpdates: noUpdates,
UpdateHandler: handler,
}

View file

@ -53,6 +53,7 @@ type StreamWorker struct {
currIdx map[int64]int
cnf *config.TGConfig
kv kv.KV
ctx context.Context
}
func (w *StreamWorker) Set(bots []string, channelId int64) {
@ -65,7 +66,7 @@ func (w *StreamWorker) Set(bots []string, channelId int64) {
w.currIdx = make(map[int64]int)
w.bots[channelId] = bots
for _, token := range bots {
client, _ := BotClient(context.TODO(), w.kv, w.cnf, token)
client, _ := BotClient(w.ctx, w.kv, w.cnf, token)
w.clients[channelId] = append(w.clients[channelId], &Client{Tg: client, Status: "idle"})
}
w.currIdx[channelId] = 0
@ -102,7 +103,7 @@ func (w *StreamWorker) UserWorker(client *telegram.Client, userId int64) (*Clien
}
nextClient := w.clients[userId][0]
if nextClient.Status == "idle" {
stop, err := bg.Connect(nextClient.Tg)
stop, err := bg.Connect(nextClient.Tg, bg.WithContext(w.ctx))
if err != nil {
return nil, err
}
@ -112,6 +113,9 @@ func (w *StreamWorker) UserWorker(client *telegram.Client, userId int64) (*Clien
return nextClient, nil
}
func NewStreamWorker(cnf *config.Config, kv kv.KV) *StreamWorker {
return &StreamWorker{cnf: &cnf.TG, kv: kv}
func NewStreamWorker(ctx context.Context) func(cnf *config.Config, kv kv.KV) *StreamWorker {
return func(cnf *config.Config, kv kv.KV) *StreamWorker {
return &StreamWorker{cnf: &cnf.TG, kv: kv, ctx: ctx}
}
}

View file

@ -168,6 +168,18 @@ func (fc *Controller) MoveDirectory(c *gin.Context) {
c.JSON(http.StatusOK, res)
}
func (fc *Controller) GetCategoryStats(c *gin.Context) {
userId, _ := services.GetUserAuth(c)
res, err := fc.FileService.GetCategoryStats(userId)
if err != nil {
httputil.NewError(c, err.Code, err.Error)
return
}
c.JSON(http.StatusOK, res)
}
func (fc *Controller) GetFileStream(c *gin.Context) {
fc.FileService.GetFileStream(c)
}

View file

@ -2,8 +2,10 @@ package controller
import (
"net/http"
"strconv"
"github.com/divyam234/teldrive/pkg/httputil"
"github.com/divyam234/teldrive/pkg/services"
"github.com/gin-gonic/gin"
)
@ -36,3 +38,21 @@ func (uc *Controller) UploadFile(c *gin.Context) {
c.JSON(http.StatusCreated, res)
}
func (uc *Controller) UploadStats(c *gin.Context) {
userId, _ := services.GetUserAuth(c)
days := 7
if c.Query("days") != "" {
days, _ = strconv.Atoi(c.Query("days"))
}
res, err := uc.UploadService.GetUploadStats(userId, days)
if err != nil {
httputil.NewError(c, err.Code, err.Error)
return
}
c.JSON(http.StatusCreated, res)
}

View file

@ -17,16 +17,6 @@ func (uc *Controller) GetStats(c *gin.Context) {
c.JSON(http.StatusOK, res)
}
func (uc *Controller) GetBots(c *gin.Context) {
res, err := uc.UserService.GetBots(c)
if err != nil {
httputil.NewError(c, err.Code, err.Error)
return
}
c.JSON(http.StatusOK, res)
}
func (uc *Controller) UpdateChannel(c *gin.Context) {
res, err := uc.UserService.UpdateChannel(c)
if err != nil {

View file

@ -15,6 +15,7 @@ func ToFileOut(file models.File) *schemas.FileOut {
Name: file.Name,
Type: file.Type,
MimeType: file.MimeType,
Category: file.Category,
Path: file.Path,
Size: size,
Starred: file.Starred,

View file

@ -15,6 +15,7 @@ type File struct {
Size *int64 `gorm:"type:bigint"`
Starred bool `gorm:"default:false"`
Depth *int `gorm:"type:integer"`
Category string `gorm:"type:text"`
Encrypted bool `gorm:"default:false"`
UserID int64 `gorm:"type:bigint;not null"`
Status string `gorm:"type:text"`

View file

@ -17,6 +17,7 @@ type FileQuery struct {
Op string `form:"op"`
Starred *bool `form:"starred"`
ParentID string `form:"parentId"`
Category string `form:"category"`
UpdatedAt *time.Time `form:"updatedAt"`
Sort string `form:"sort"`
Order string `form:"order"`
@ -41,6 +42,7 @@ type FileOut struct {
Name string `json:"name"`
Type string `json:"type"`
MimeType string `json:"mimeType"`
Category string `json:"category,omitempty"`
Path string `json:"path,omitempty"`
Size int64 `json:"size,omitempty"`
Starred bool `json:"starred"`
@ -89,3 +91,9 @@ type Copy struct {
Name string `json:"name" binding:"required"`
Destination string `json:"destination" binding:"required"`
}
type FileCategoryStats struct {
TotalFiles int `json:"totalFiles"`
TotalSize int `json:"totalSize"`
Category string `json:"category"`
}

View file

@ -31,3 +31,8 @@ type UploadPart struct {
Size int64 `json:"size"`
Encrypted bool `json:"encrypted"`
}
type UploadStats struct {
UploadDate string `json:"uploadDate"`
TotalUploaded int64 `json:"totalUpladed"`
}

View file

@ -6,7 +6,6 @@ type Channel struct {
}
type AccountStats struct {
TotalSize int64 `json:"totalSize"`
TotalFiles int64 `json:"totalFiles"`
Channel
ChannelID int64 `json:"channelId"`
Bots []string `json:"bots"`
}

View file

@ -11,6 +11,7 @@ import (
"strings"
"github.com/divyam234/teldrive/internal/cache"
category "github.com/divyam234/teldrive/internal/category"
"github.com/divyam234/teldrive/internal/config"
"github.com/divyam234/teldrive/internal/database"
"github.com/divyam234/teldrive/internal/http_range"
@ -78,6 +79,7 @@ func (fs *FileService) CreateFile(c *gin.Context, userId int64, fileIn *schemas.
}
fileDB.ChannelID = &channelId
fileDB.MimeType = fileIn.MimeType
fileDB.Category = string(category.GetCategory(fileIn.MimeType))
parts := models.Parts{}
for _, part := range fileIn.Parts {
parts = append(parts, models.Part{
@ -172,6 +174,7 @@ func (fs *FileService) ListFiles(userId int64, fquery *schemas.FileQuery) (*sche
filter.Name = fquery.Name
filter.Type = fquery.Type
filter.ParentID = fquery.ParentID
filter.Category = fquery.Category
filter.Path = fquery.Path
filter.Type = fquery.Type
if fquery.Starred != nil {
@ -274,6 +277,19 @@ func (fs *FileService) MoveDirectory(userId int64, payload *schemas.DirMove) (*s
return &schemas.Message{Message: "directory moved"}, nil
}
func (fs *FileService) GetCategoryStats(userId int64) ([]schemas.FileCategoryStats, *types.AppError) {
var stats []schemas.FileCategoryStats
if err := fs.db.Model(&models.File{}).Select("category", "COUNT(*) as total_files", "coalesce(SUM(size),0) as total_size").
Where(&models.File{UserID: userId, Type: "file", Status: "active"}).
Order("category ASC").Group("category").Find(&stats).Error; err != nil {
return nil, &types.AppError{Error: err}
}
return stats, nil
}
func (fs *FileService) CopyFile(c *gin.Context) (*schemas.FileOut, *types.AppError) {
var payload schemas.Copy

View file

@ -4,6 +4,7 @@ import (
"context"
"crypto/rand"
"crypto/sha256"
"database/sql"
"encoding/base64"
"errors"
"net/http"
@ -63,6 +64,41 @@ func (us *UploadService) DeleteUploadFile(c *gin.Context) (*schemas.Message, *ty
return &schemas.Message{Message: "upload deleted"}, nil
}
func (us *UploadService) GetUploadStats(userId int64, days int) ([]schemas.UploadStats, *types.AppError) {
var stats []schemas.UploadStats
rows, err := us.db.Raw(`
SELECT
dates.upload_date::date AS upload_date,
COALESCE(SUM(files.size), 0)::bigint AS total_uploaded
FROM
generate_series(CURRENT_DATE - INTERVAL '1 day' * @days, CURRENT_DATE, '1 day') AS dates(upload_date)
LEFT JOIN
teldrive.files AS files
ON
dates.upload_date = DATE_TRUNC('day', files.created_at)
WHERE
dates.upload_date >= CURRENT_DATE - INTERVAL '1 day' * @days and files.user_id = @userId
GROUP BY
dates.upload_date
ORDER BY
dates.upload_date desc
`, sql.Named("days", days-1), sql.Named("userId", userId)).Rows()
if err != nil {
return nil, &types.AppError{Error: err}
}
defer rows.Close()
for rows.Next() {
var uploadDate string
var totalUploaded int64
rows.Scan(&uploadDate, &totalUploaded)
stats = append(stats, schemas.UploadStats{UploadDate: uploadDate, TotalUploaded: totalUploaded})
}
return stats, nil
}
func (us *UploadService) UploadFile(c *gin.Context) (*schemas.UploadPartOut, *types.AppError) {
var (
uploadQuery schemas.UploadQuery

View file

@ -80,15 +80,6 @@ func (us *UserService) GetProfilePhoto(c *gin.Context) {
}
func (us *UserService) GetStats(c *gin.Context) (*schemas.AccountStats, *types.AppError) {
userId, _ := GetUserAuth(c)
var res []schemas.AccountStats
if err := us.db.Raw("select * from teldrive.account_stats(?);", userId).Scan(&res).Error; err != nil {
return nil, &types.AppError{Error: err, Code: http.StatusInternalServerError}
}
return &res[0], nil
}
func (us *UserService) GetBots(c *gin.Context) ([]string, *types.AppError) {
userID, _ := GetUserAuth(c)
var (
channelId int64
@ -108,7 +99,7 @@ func (us *UserService) GetBots(c *gin.Context) ([]string, *types.AppError) {
if err != nil {
return nil, &types.AppError{Error: err, Code: http.StatusInternalServerError}
}
return tokens, nil
return &schemas.AccountStats{Bots: tokens, ChannelID: channelId}, nil
}
func (us *UserService) UpdateChannel(c *gin.Context) (*schemas.Message, *types.AppError) {