✨ Pay for upload
This commit is contained in:
parent
96f429e1d9
commit
80739eab52
10
go.mod
10
go.mod
@ -3,10 +3,11 @@ module git.solsynth.dev/hypernet/paperclip
|
||||
go 1.23.2
|
||||
|
||||
require (
|
||||
git.solsynth.dev/hypernet/nexus v0.0.0-20241103165538-c0fec1084611
|
||||
git.solsynth.dev/hypernet/passport v0.0.0-20241102174750-808e7998dd1c
|
||||
git.solsynth.dev/hypernet/nexus v0.0.0-20241123050605-25ab1371739b
|
||||
git.solsynth.dev/hypernet/passport v0.0.0-20250128183757-09010d5867ed
|
||||
git.solsynth.dev/hypernet/wallet v0.0.0-20250129103922-9b5f67e67788
|
||||
github.com/barasher/go-exiftool v1.10.0
|
||||
github.com/dgraph-io/ristretto v0.1.1
|
||||
github.com/dgraph-io/ristretto v0.2.0
|
||||
github.com/eko/gocache/lib/v4 v4.1.6
|
||||
github.com/eko/gocache/store/ristretto/v4 v4.2.2
|
||||
github.com/fatih/color v1.18.0
|
||||
@ -32,7 +33,7 @@ require (
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
git.solsynth.dev/hypernet/pusher v0.0.0-20241026153052-cd2c326efa4e // indirect
|
||||
git.solsynth.dev/hypernet/pusher v0.0.0-20241228030233-50ff8304e465 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
@ -44,7 +45,6 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/glog v1.2.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
|
26
go.sum
26
go.sum
@ -33,12 +33,14 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
git.solsynth.dev/hypernet/nexus v0.0.0-20241103165538-c0fec1084611 h1:ZEzUDsO88X+amOaEKZOpnQHHNYm5iw3hCBdy138sQro=
|
||||
git.solsynth.dev/hypernet/nexus v0.0.0-20241103165538-c0fec1084611/go.mod h1:PhLCv2lsNoscPVJbkWnxwQnJ141lc4RIEkVffrHwl4s=
|
||||
git.solsynth.dev/hypernet/passport v0.0.0-20241102174750-808e7998dd1c h1:RVY0xsYGpb22ZuITxS+xpFu76XpPDrOpbIuSMDjW1+Q=
|
||||
git.solsynth.dev/hypernet/passport v0.0.0-20241102174750-808e7998dd1c/go.mod h1:Gj8uWVKUeUxU3Z6v1sYLGHB79ln1nubQ5XfsJVUcvWM=
|
||||
git.solsynth.dev/hypernet/pusher v0.0.0-20241026153052-cd2c326efa4e h1:DtHhMjgxS/spUt/KEdbRFtaVnepI6Vx8pbHdJaNH1hs=
|
||||
git.solsynth.dev/hypernet/pusher v0.0.0-20241026153052-cd2c326efa4e/go.mod h1:XHTqFU/vBe4JiuAjl87GUcL8+w/IizSNoqH6n3WkQFc=
|
||||
git.solsynth.dev/hypernet/nexus v0.0.0-20241123050605-25ab1371739b h1:8yB9kMwEMY/nIbmDDxrhH5sTypgmK5PIIiIfP5QXx4s=
|
||||
git.solsynth.dev/hypernet/nexus v0.0.0-20241123050605-25ab1371739b/go.mod h1:PhLCv2lsNoscPVJbkWnxwQnJ141lc4RIEkVffrHwl4s=
|
||||
git.solsynth.dev/hypernet/passport v0.0.0-20250128183757-09010d5867ed h1:+z84T2At6CbfZfo7zvvMQP4zv/+tGM5KlJlCSoIkB8Y=
|
||||
git.solsynth.dev/hypernet/passport v0.0.0-20250128183757-09010d5867ed/go.mod h1:h78BjtyDuchDDlddLtk3HjvDI7DAK8Jzk/uVwqvv2cw=
|
||||
git.solsynth.dev/hypernet/pusher v0.0.0-20241228030233-50ff8304e465 h1:KFtv9lF0JMUGsq1uHwQvop8PTyqdiLuUQuRrd5WmzPk=
|
||||
git.solsynth.dev/hypernet/pusher v0.0.0-20241228030233-50ff8304e465/go.mod h1:XHTqFU/vBe4JiuAjl87GUcL8+w/IizSNoqH6n3WkQFc=
|
||||
git.solsynth.dev/hypernet/wallet v0.0.0-20250129103922-9b5f67e67788 h1:jnZoRiRSFVTRl05mGSOynlbS5MIHAq3EUqVdkz8BjEI=
|
||||
git.solsynth.dev/hypernet/wallet v0.0.0-20250129103922-9b5f67e67788/go.mod h1:jd1MTBI5NPHne22nq7nR7kyl4iYb9kV2A+tpXi7HOYY=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@ -69,11 +71,10 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
|
||||
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
|
||||
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/eko/gocache/lib/v4 v4.1.6 h1:5WWIGISKhE7mfkyF+SJyWwqa4Dp2mkdX8QsZpnENqJI=
|
||||
@ -128,8 +129,6 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2V
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
|
||||
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@ -509,7 +508,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
@ -32,8 +32,8 @@ func createAttachmentDirectly(c *fiber.Ctx) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !user.HasPermNode("CreateAttachments", file.Size) {
|
||||
return fiber.NewError(fiber.StatusForbidden, "you are not permitted to create attachments like this large")
|
||||
if !user.HasPermNode("CreateAttachments", true) {
|
||||
return fiber.NewError(fiber.StatusForbidden, "you are not permitted to create attachments")
|
||||
} else if pool.Config.Data().MaxFileSize != nil && file.Size > *pool.Config.Data().MaxFileSize {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("attachment pool %s doesn't allow file larger than %d", pool.Alias, *pool.Config.Data().MaxFileSize))
|
||||
}
|
||||
@ -62,6 +62,13 @@ func createAttachmentDirectly(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
// If pool has no belongs to, it means it is shared pool, apply shared attachment discount
|
||||
withDiscount := pool.AccountID == nil
|
||||
if err := services.PlaceOrder(user.ID, file.Size, withDiscount); err != nil {
|
||||
tx.Rollback()
|
||||
return fiber.NewError(fiber.StatusPaymentRequired, err.Error())
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
metadata.Pool = &pool
|
||||
|
@ -41,13 +41,15 @@ func createAttachmentFragment(c *fiber.Ctx) error {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("unable to get attachment pool info: %v", err))
|
||||
}
|
||||
|
||||
if !user.HasPermNode("CreateAttachments", data.Size) {
|
||||
return fiber.NewError(fiber.StatusForbidden, "you are not permitted to create attachments like this large")
|
||||
if !user.HasPermNode("CreateAttachments", true) {
|
||||
return fiber.NewError(fiber.StatusForbidden, "you are not permitted to create attachments")
|
||||
} else if pool.Config.Data().MaxFileSize != nil && *pool.Config.Data().MaxFileSize > data.Size {
|
||||
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("attachment pool %s doesn't allow file larger than %d", pool.Alias, *pool.Config.Data().MaxFileSize))
|
||||
}
|
||||
|
||||
metadata, err := services.NewAttachmentFragment(database.C, user, models.AttachmentFragment{
|
||||
tx := database.C.Begin()
|
||||
|
||||
metadata, err := services.NewAttachmentFragment(tx, user, models.AttachmentFragment{
|
||||
Name: data.FileName,
|
||||
Size: data.Size,
|
||||
Alternative: data.Alternative,
|
||||
@ -63,6 +65,15 @@ func createAttachmentFragment(c *fiber.Ctx) error {
|
||||
metadata.FileChunksMissing = services.FindFragmentMissingChunks(metadata)
|
||||
}
|
||||
|
||||
// If pool has no belongs to, it means it is shared pool, apply shared attachment discount
|
||||
withDiscount := pool.AccountID == nil
|
||||
if err := services.PlaceOrder(user.ID, data.Size, withDiscount); err != nil {
|
||||
tx.Rollback()
|
||||
return fiber.NewError(fiber.StatusPaymentRequired, err.Error())
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"chunk_size": viper.GetInt64("performance.file_chunk_size"),
|
||||
"chunk_count": len(metadata.FileChunks),
|
||||
|
60
pkg/internal/services/payment.go
Normal file
60
pkg/internal/services/payment.go
Normal file
@ -0,0 +1,60 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.solsynth.dev/hypernet/paperclip/pkg/internal/gap"
|
||||
wproto "git.solsynth.dev/hypernet/wallet/pkg/proto"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
const DiscountFileSize = 52428800 // 50 MiB
|
||||
|
||||
// PlaceOrder create a transaction if needed for user
|
||||
// Pricing according here: https://kb.solsynth.dev/solar-network/wallet#file-uploads
|
||||
func PlaceOrder(user uint, filesize int64, withDiscount bool) error {
|
||||
if filesize <= DiscountFileSize && withDiscount {
|
||||
// Discount included
|
||||
return nil
|
||||
}
|
||||
|
||||
var amount float64
|
||||
if withDiscount {
|
||||
billableSize := filesize - DiscountFileSize
|
||||
amount = float64(billableSize) / 1024 / 1024 * 1
|
||||
} else if filesize > DiscountFileSize {
|
||||
amount = 50 + float64(filesize-DiscountFileSize)/1024/1024*5
|
||||
} else {
|
||||
amount = float64(filesize) / 1024 / 1024 * 1
|
||||
}
|
||||
|
||||
if !withDiscount {
|
||||
amount += 10 // Service fee
|
||||
}
|
||||
|
||||
conn, err := gap.Nx.GetClientGrpcConn("wa")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to connect wallet: %v", err)
|
||||
}
|
||||
|
||||
wc := wproto.NewPaymentServiceClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||
defer cancel()
|
||||
resp, err := wc.MakeTransactionWithAccount(ctx, &wproto.MakeTransactionWithAccountRequest{
|
||||
PayerAccountId: lo.ToPtr(uint64(user)),
|
||||
Amount: amount,
|
||||
Remark: "File Uploading Fee",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Uint64("transaction", resp.Id).Float64("amount", amount).Bool("discount", withDiscount).
|
||||
Msg("Order placed for charge file uploading fee...")
|
||||
|
||||
return nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user