new settlement flow #288
@@ -49,6 +49,6 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
google.golang.org/grpc v1.78.0 // indirect
|
google.golang.org/grpc v1.78.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
google.golang.org/grpc v1.78.0 // indirect
|
google.golang.org/grpc v1.78.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -50,5 +50,5 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260119175649-084b3e29eee1 // indirect
|
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260120135015-58f41aaaee16 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.24.4 // indirect
|
github.com/bits-and-blooms/bitset v1.24.4 // indirect
|
||||||
github.com/bmatcuk/doublestar/v4 v4.9.2 // indirect
|
github.com/bmatcuk/doublestar/v4 v4.9.2 // indirect
|
||||||
@@ -86,5 +86,5 @@ require (
|
|||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
|||||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260119175649-084b3e29eee1 h1:uq8tHimZusJXFqiZG2EyQhyLYUWXkOumwNRFAyWcyHw=
|
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260120135015-58f41aaaee16 h1:zhGT51SYKfpAlhdhfHqJbNMpjT5Q0E6/31byd8yTnxY=
|
||||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260119175649-084b3e29eee1/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20260120135015-58f41aaaee16/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||||
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
|
github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0=
|
||||||
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
|
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
@@ -362,8 +362,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -50,5 +50,5 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -38,5 +38,5 @@ messaging:
|
|||||||
gateway:
|
gateway:
|
||||||
rail: "provider_settlement"
|
rail: "provider_settlement"
|
||||||
target_chat_id_env: TGSETTLE_GATEWAY_CHAT_ID
|
target_chat_id_env: TGSETTLE_GATEWAY_CHAT_ID
|
||||||
timeout_seconds: 120
|
timeout_seconds: 259200
|
||||||
accepted_user_ids: []
|
accepted_user_ids: []
|
||||||
|
|||||||
@@ -47,5 +47,5 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
|
confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
|
||||||
paymentgateway "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway"
|
paymentgateway "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway"
|
||||||
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||||
|
tnotifications "github.com/tech/sendico/pkg/messaging/notifications/telegram"
|
||||||
"github.com/tech/sendico/pkg/mlogger"
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
"github.com/tech/sendico/pkg/model"
|
"github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
@@ -34,8 +35,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultConfirmationTimeoutSeconds = 120
|
defaultConfirmationTimeoutSeconds = 259200
|
||||||
executedStatus = "executed"
|
executedStatus = "executed"
|
||||||
|
telegramSuccessReaction = "\u2705"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -43,6 +45,8 @@ const (
|
|||||||
metadataQuoteRef = "quote_ref"
|
metadataQuoteRef = "quote_ref"
|
||||||
metadataTargetChatID = "target_chat_id"
|
metadataTargetChatID = "target_chat_id"
|
||||||
metadataOutgoingLeg = "outgoing_leg"
|
metadataOutgoingLeg = "outgoing_leg"
|
||||||
|
metadataSourceAmount = "source_amount"
|
||||||
|
metadataSourceCurrency = "source_currency"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -77,14 +81,14 @@ func NewService(logger mlogger.Logger, repo storage.Repository, producer msg.Pro
|
|||||||
}
|
}
|
||||||
logger = logger.Named("service")
|
logger = logger.Named("service")
|
||||||
svc := &Service{
|
svc := &Service{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
producer: producer,
|
producer: producer,
|
||||||
broker: broker,
|
broker: broker,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
rail: strings.TrimSpace(cfg.Rail),
|
rail: strings.TrimSpace(cfg.Rail),
|
||||||
invokeURI: strings.TrimSpace(cfg.InvokeURI),
|
invokeURI: strings.TrimSpace(cfg.InvokeURI),
|
||||||
pending: map[string]*model.PaymentGatewayIntent{},
|
pending: map[string]*model.PaymentGatewayIntent{},
|
||||||
}
|
}
|
||||||
svc.chatID = strings.TrimSpace(readEnv(cfg.TargetChatIDEnv))
|
svc.chatID = strings.TrimSpace(readEnv(cfg.TargetChatIDEnv))
|
||||||
svc.startConsumers()
|
svc.startConsumers()
|
||||||
@@ -322,6 +326,7 @@ func (s *Service) onConfirmationResult(ctx context.Context, result *model.Confir
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.publishExecution(intent, result)
|
s.publishExecution(intent, result)
|
||||||
|
s.publishTelegramReaction(result)
|
||||||
s.removeIntent(requestID)
|
s.removeIntent(requestID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -416,6 +421,39 @@ func (s *Service) publishExecution(intent *model.PaymentGatewayIntent, result *m
|
|||||||
zap.String("status", string(result.Status)))
|
zap.String("status", string(result.Status)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) publishTelegramReaction(result *model.ConfirmationResult) {
|
||||||
|
if s == nil || s.producer == nil || result == nil || result.RawReply == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if result.Status != model.ConfirmationStatusConfirmed && result.Status != model.ConfirmationStatusClarified {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
request := &model.TelegramReactionRequest{
|
||||||
|
RequestID: strings.TrimSpace(result.RequestID),
|
||||||
|
ChatID: strings.TrimSpace(result.RawReply.ChatID),
|
||||||
|
MessageID: strings.TrimSpace(result.RawReply.MessageID),
|
||||||
|
Emoji: telegramSuccessReaction,
|
||||||
|
}
|
||||||
|
if request.ChatID == "" || request.MessageID == "" || request.Emoji == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
env := tnotifications.TelegramReaction(string(mservice.PaymentGateway), request)
|
||||||
|
if err := s.producer.SendMessage(env); err != nil {
|
||||||
|
s.logger.Warn("Failed to publish telegram reaction",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.String("request_id", request.RequestID),
|
||||||
|
zap.String("chat_id", request.ChatID),
|
||||||
|
zap.String("message_id", request.MessageID),
|
||||||
|
zap.String("emoji", request.Emoji))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.logger.Info("Published telegram reaction",
|
||||||
|
zap.String("request_id", request.RequestID),
|
||||||
|
zap.String("chat_id", request.ChatID),
|
||||||
|
zap.String("message_id", request.MessageID),
|
||||||
|
zap.String("emoji", request.Emoji))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) trackIntent(requestID string, intent *model.PaymentGatewayIntent) {
|
func (s *Service) trackIntent(requestID string, intent *model.PaymentGatewayIntent) {
|
||||||
if s == nil || intent == nil {
|
if s == nil || intent == nil {
|
||||||
return
|
return
|
||||||
@@ -507,6 +545,7 @@ func intentFromSubmitTransfer(req *chainv1.SubmitTransferRequest, defaultRail, d
|
|||||||
if amount == nil {
|
if amount == nil {
|
||||||
return nil, merrors.InvalidArgument("submit_transfer: amount is required")
|
return nil, merrors.InvalidArgument("submit_transfer: amount is required")
|
||||||
}
|
}
|
||||||
|
metadata := req.GetMetadata()
|
||||||
requestedMoney := &paymenttypes.Money{
|
requestedMoney := &paymenttypes.Money{
|
||||||
Amount: strings.TrimSpace(amount.GetAmount()),
|
Amount: strings.TrimSpace(amount.GetAmount()),
|
||||||
Currency: strings.TrimSpace(amount.GetCurrency()),
|
Currency: strings.TrimSpace(amount.GetCurrency()),
|
||||||
@@ -514,7 +553,14 @@ func intentFromSubmitTransfer(req *chainv1.SubmitTransferRequest, defaultRail, d
|
|||||||
if requestedMoney.Amount == "" || requestedMoney.Currency == "" {
|
if requestedMoney.Amount == "" || requestedMoney.Currency == "" {
|
||||||
return nil, merrors.InvalidArgument("submit_transfer: amount is required")
|
return nil, merrors.InvalidArgument("submit_transfer: amount is required")
|
||||||
}
|
}
|
||||||
metadata := req.GetMetadata()
|
sourceAmount := strings.TrimSpace(metadata[metadataSourceAmount])
|
||||||
|
sourceCurrency := strings.TrimSpace(metadata[metadataSourceCurrency])
|
||||||
|
if sourceAmount != "" && sourceCurrency != "" {
|
||||||
|
requestedMoney = &paymenttypes.Money{
|
||||||
|
Amount: sourceAmount,
|
||||||
|
Currency: sourceCurrency,
|
||||||
|
}
|
||||||
|
}
|
||||||
paymentIntentID := strings.TrimSpace(req.GetClientReference())
|
paymentIntentID := strings.TrimSpace(req.GetClientReference())
|
||||||
if paymentIntentID == "" {
|
if paymentIntentID == "" {
|
||||||
paymentIntentID = strings.TrimSpace(metadata[metadataPaymentIntentID])
|
paymentIntentID = strings.TrimSpace(metadata[metadataPaymentIntentID])
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import (
|
|||||||
"github.com/tech/sendico/gateway/tgsettle/storage"
|
"github.com/tech/sendico/gateway/tgsettle/storage"
|
||||||
storagemodel "github.com/tech/sendico/gateway/tgsettle/storage/model"
|
storagemodel "github.com/tech/sendico/gateway/tgsettle/storage/model"
|
||||||
envelope "github.com/tech/sendico/pkg/messaging/envelope"
|
envelope "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
mloggerfactory "github.com/tech/sendico/pkg/mlogger/factory"
|
||||||
"github.com/tech/sendico/pkg/model"
|
"github.com/tech/sendico/pkg/model"
|
||||||
notification "github.com/tech/sendico/pkg/model/notification"
|
notification "github.com/tech/sendico/pkg/model/notification"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
mloggerfactory "github.com/tech/sendico/pkg/mlogger/factory"
|
|
||||||
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||||
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
|
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakePaymentsStore struct {
|
type fakePaymentsStore struct {
|
||||||
@@ -147,6 +149,25 @@ func TestOnIntentCreatesConfirmationRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntentFromSubmitTransferUsesSourceMoney(t *testing.T) {
|
||||||
|
req := &chainv1.SubmitTransferRequest{
|
||||||
|
IdempotencyKey: "idem-1",
|
||||||
|
ClientReference: "pi-1",
|
||||||
|
Amount: &moneyv1.Money{Amount: "10.00", Currency: "EUR"},
|
||||||
|
Metadata: map[string]string{
|
||||||
|
metadataSourceAmount: "12.34",
|
||||||
|
metadataSourceCurrency: "USD",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
intent, err := intentFromSubmitTransfer(req, "provider_settlement", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("intentFromSubmitTransfer error: %v", err)
|
||||||
|
}
|
||||||
|
if intent.RequestedMoney == nil || intent.RequestedMoney.Amount != "12.34" || intent.RequestedMoney.Currency != "USD" {
|
||||||
|
t.Fatalf("expected source money override, got: %#v", intent.RequestedMoney)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfirmationResultPersistsExecutionAndReply(t *testing.T) {
|
func TestConfirmationResultPersistsExecutionAndReply(t *testing.T) {
|
||||||
logger := mloggerfactory.NewLogger(false)
|
logger := mloggerfactory.NewLogger(false)
|
||||||
repo := &fakeRepo{payments: &fakePaymentsStore{}, tg: &fakeTelegramStore{}}
|
repo := &fakeRepo{payments: &fakePaymentsStore{}, tg: &fakeTelegramStore{}}
|
||||||
|
|||||||
@@ -51,5 +51,5 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ require (
|
|||||||
golang.org/x/net v0.49.0 // indirect
|
golang.org/x/net v0.49.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
google.golang.org/grpc v1.78.0 // indirect
|
google.golang.org/grpc v1.78.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -229,8 +229,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tech/sendico/notification/internal/server/notificationimp/telegram"
|
"github.com/tech/sendico/notification/internal/server/notificationimp/telegram"
|
||||||
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
msg "github.com/tech/sendico/pkg/messaging"
|
msg "github.com/tech/sendico/pkg/messaging"
|
||||||
confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
|
confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
|
||||||
"github.com/tech/sendico/pkg/merrors"
|
|
||||||
"github.com/tech/sendico/pkg/mlogger"
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
"github.com/tech/sendico/pkg/model"
|
"github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
@@ -35,12 +35,12 @@ type confirmationManager struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type confirmationState struct {
|
type confirmationState struct {
|
||||||
request model.ConfirmationRequest
|
request model.ConfirmationRequest
|
||||||
requestMessageID string
|
requestMessageID string
|
||||||
targetChatID string
|
targetChatID string
|
||||||
callbackSubject string
|
callbackSubject string
|
||||||
clarified bool
|
clarified bool
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConfirmationManager(logger mlogger.Logger, tg telegram.Client, outbox msg.Producer) *confirmationManager {
|
func newConfirmationManager(logger mlogger.Logger, tg telegram.Client, outbox msg.Producer) *confirmationManager {
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ import (
|
|||||||
"github.com/tech/sendico/pkg/domainprovider"
|
"github.com/tech/sendico/pkg/domainprovider"
|
||||||
"github.com/tech/sendico/pkg/merrors"
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
na "github.com/tech/sendico/pkg/messaging/notifications/account"
|
na "github.com/tech/sendico/pkg/messaging/notifications/account"
|
||||||
confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
|
|
||||||
cnotifications "github.com/tech/sendico/pkg/messaging/notifications/confirmation"
|
cnotifications "github.com/tech/sendico/pkg/messaging/notifications/confirmation"
|
||||||
|
confirmations "github.com/tech/sendico/pkg/messaging/notifications/confirmations"
|
||||||
ni "github.com/tech/sendico/pkg/messaging/notifications/invitation"
|
ni "github.com/tech/sendico/pkg/messaging/notifications/invitation"
|
||||||
snotifications "github.com/tech/sendico/pkg/messaging/notifications/site"
|
snotifications "github.com/tech/sendico/pkg/messaging/notifications/site"
|
||||||
|
tnotifications "github.com/tech/sendico/pkg/messaging/notifications/telegram"
|
||||||
"github.com/tech/sendico/pkg/mlogger"
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
"github.com/tech/sendico/pkg/model"
|
"github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
@@ -91,6 +92,10 @@ func CreateAPI(a api.API) (*NotificationAPI, error) {
|
|||||||
p.logger.Error("Failed to register confirmation request handler", zap.Error(err))
|
p.logger.Error("Failed to register confirmation request handler", zap.Error(err))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := a.Register().Consumer(tnotifications.NewTelegramReactionProcessor(p.logger, p.onTelegramReaction)); err != nil {
|
||||||
|
p.logger.Error("Failed to register telegram reaction handler", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
idb, err := a.DBFactory().NewInvitationsDB()
|
idb, err := a.DBFactory().NewInvitationsDB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type Client interface {
|
|||||||
SendContactRequest(ctx context.Context, request *model.ContactRequest) error
|
SendContactRequest(ctx context.Context, request *model.ContactRequest) error
|
||||||
SendCallRequest(ctx context.Context, request *model.CallRequest) error
|
SendCallRequest(ctx context.Context, request *model.CallRequest) error
|
||||||
SendText(ctx context.Context, chatID string, text string, replyToMessageID string) (*model.TelegramMessage, error)
|
SendText(ctx context.Context, chatID string, text string, replyToMessageID string) (*model.TelegramMessage, error)
|
||||||
|
SetMessageReaction(ctx context.Context, chatID string, messageID string, emoji string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
@@ -132,6 +133,25 @@ type messageUser struct {
|
|||||||
Username string `json:"username,omitempty"`
|
Username string `json:"username,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type setMessageReactionPayload struct {
|
||||||
|
ChatID string `json:"chat_id"`
|
||||||
|
MessageID int64 `json:"message_id"`
|
||||||
|
Reaction []reactionType `json:"reaction,omitempty"`
|
||||||
|
IsBig bool `json:"is_big,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type reactionType struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Emoji string `json:"emoji,omitempty"`
|
||||||
|
CustomEmojiID string `json:"custom_emoji_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type setMessageReactionResponse struct {
|
||||||
|
OK bool `json:"ok"`
|
||||||
|
Result bool `json:"result,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
func (c *client) sendMessage(ctx context.Context, payload sendMessagePayload) (*model.TelegramMessage, error) {
|
func (c *client) sendMessage(ctx context.Context, payload sendMessagePayload) (*model.TelegramMessage, error) {
|
||||||
body, err := json.Marshal(&payload)
|
body, err := json.Marshal(&payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -193,7 +213,12 @@ func (c *client) sendMessage(ctx context.Context, payload sendMessagePayload) (*
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) endpoint() string {
|
func (c *client) endpoint() string {
|
||||||
return fmt.Sprintf("%s/bot%s/sendMessage", c.apiURL, c.botToken)
|
return c.endpointFor("sendMessage")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) endpointFor(method string) string {
|
||||||
|
method = strings.TrimPrefix(strings.TrimSpace(method), "/")
|
||||||
|
return fmt.Sprintf("%s/bot%s/%s", c.apiURL, c.botToken, method)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) SendContactRequest(ctx context.Context, request *model.ContactRequest) error {
|
func (c *client) SendContactRequest(ctx context.Context, request *model.ContactRequest) error {
|
||||||
@@ -248,6 +273,80 @@ func (c *client) SendText(ctx context.Context, chatID string, text string, reply
|
|||||||
return c.sendMessage(ctx, payload)
|
return c.sendMessage(ctx, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *client) SetMessageReaction(ctx context.Context, chatID string, messageID string, emoji string) error {
|
||||||
|
chatID = strings.TrimSpace(chatID)
|
||||||
|
if chatID == "" {
|
||||||
|
return merrors.InvalidArgument("telegram chat id is empty", "chat_id")
|
||||||
|
}
|
||||||
|
msgID, err := strconv.ParseInt(strings.TrimSpace(messageID), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return merrors.InvalidArgumentWrap(err, "invalid message_id", "message_id")
|
||||||
|
}
|
||||||
|
emoji = strings.TrimSpace(emoji)
|
||||||
|
reaction := []reactionType{}
|
||||||
|
if emoji != "" {
|
||||||
|
reaction = append(reaction, reactionType{Type: "emoji", Emoji: emoji})
|
||||||
|
}
|
||||||
|
payload := setMessageReactionPayload{
|
||||||
|
ChatID: chatID,
|
||||||
|
MessageID: msgID,
|
||||||
|
Reaction: reaction,
|
||||||
|
}
|
||||||
|
return c.sendReaction(ctx, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) sendReaction(ctx context.Context, payload setMessageReactionPayload) error {
|
||||||
|
body, err := json.Marshal(&payload)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Warn("Failed to marshal telegram reaction payload", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpointFor("setMessageReaction"), bytes.NewReader(body))
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Warn("Failed to create telegram reaction request", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
fields := []zap.Field{
|
||||||
|
zap.String("chat_id", payload.ChatID),
|
||||||
|
zap.Int64("message_id", payload.MessageID),
|
||||||
|
zap.Int("payload_size_bytes", len(body)),
|
||||||
|
}
|
||||||
|
c.logger.Debug("Sending Telegram reaction", fields...)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Warn("Telegram reaction request failed", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 16<<10))
|
||||||
|
if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
|
||||||
|
var parsed setMessageReactionResponse
|
||||||
|
if err := json.Unmarshal(respBody, &parsed); err != nil {
|
||||||
|
c.logger.Warn("Failed to decode telegram reaction response", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !parsed.OK || !parsed.Result {
|
||||||
|
msg := "telegram setMessageReaction response missing result"
|
||||||
|
if parsed.Description != "" {
|
||||||
|
msg = parsed.Description
|
||||||
|
}
|
||||||
|
return merrors.Internal(msg)
|
||||||
|
}
|
||||||
|
c.logger.Debug("Telegram reaction sent", zap.Int("status_code", resp.StatusCode), zap.Duration("latency", time.Since(start)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c.logger.Warn("Telegram API returned non-success status for reaction",
|
||||||
|
zap.Int("status_code", resp.StatusCode),
|
||||||
|
zap.ByteString("response_body", respBody),
|
||||||
|
zap.String("chat_id", payload.ChatID))
|
||||||
|
return merrors.Internal(fmt.Sprintf("telegram setMessageReaction failed with status %d: %s", resp.StatusCode, string(respBody)))
|
||||||
|
}
|
||||||
|
|
||||||
func toTelegramMessage(msg *messageResponse) *model.TelegramMessage {
|
func toTelegramMessage(msg *messageResponse) *model.TelegramMessage {
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package notificationimp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/merrors"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *NotificationAPI) onTelegramReaction(ctx context.Context, request *model.TelegramReactionRequest) error {
|
||||||
|
if request == nil {
|
||||||
|
return merrors.InvalidArgument("telegram reaction request is nil", "request")
|
||||||
|
}
|
||||||
|
if a.tg == nil {
|
||||||
|
return merrors.Internal("telegram client is not configured")
|
||||||
|
}
|
||||||
|
chatID := strings.TrimSpace(request.ChatID)
|
||||||
|
messageID := strings.TrimSpace(request.MessageID)
|
||||||
|
if chatID == "" {
|
||||||
|
return merrors.InvalidArgument("telegram chat_id is required", "chat_id")
|
||||||
|
}
|
||||||
|
if messageID == "" {
|
||||||
|
return merrors.InvalidArgument("telegram message_id is required", "message_id")
|
||||||
|
}
|
||||||
|
emoji := strings.TrimSpace(request.Emoji)
|
||||||
|
if emoji == "" {
|
||||||
|
return merrors.InvalidArgument("telegram emoji is required", "emoji")
|
||||||
|
}
|
||||||
|
if err := a.tg.SetMessageReaction(ctx, chatID, messageID, emoji); err != nil {
|
||||||
|
a.logger.Warn("Failed to send telegram reaction",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.String("request_id", strings.TrimSpace(request.RequestID)),
|
||||||
|
zap.String("chat_id", chatID),
|
||||||
|
zap.String("message_id", messageID),
|
||||||
|
zap.String("emoji", emoji))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.logger.Info("Telegram reaction sent",
|
||||||
|
zap.String("request_id", strings.TrimSpace(request.RequestID)),
|
||||||
|
zap.String("chat_id", chatID),
|
||||||
|
zap.String("message_id", messageID),
|
||||||
|
zap.String("emoji", emoji))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -62,5 +62,5 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -215,8 +215,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ const (
|
|||||||
providerSettlementMetaQuoteRef = "quote_ref"
|
providerSettlementMetaQuoteRef = "quote_ref"
|
||||||
providerSettlementMetaTargetChatID = "target_chat_id"
|
providerSettlementMetaTargetChatID = "target_chat_id"
|
||||||
providerSettlementMetaOutgoingLeg = "outgoing_leg"
|
providerSettlementMetaOutgoingLeg = "outgoing_leg"
|
||||||
|
providerSettlementMetaSourceAmount = "source_amount"
|
||||||
|
providerSettlementMetaSourceCurrency = "source_currency"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *paymentExecutor) buildProviderSettlementTransferRequest(payment *model.Payment, step *model.PaymentStep, amount *paymenttypes.Money, quote *orchestratorv1.PaymentQuote, idx int) (rail.TransferRequest, error) {
|
func (p *paymentExecutor) buildProviderSettlementTransferRequest(payment *model.Payment, step *model.PaymentStep, amount *paymenttypes.Money, quote *orchestratorv1.PaymentQuote, idx int) (rail.TransferRequest, error) {
|
||||||
@@ -46,6 +48,15 @@ func (p *paymentExecutor) buildProviderSettlementTransferRequest(payment *model.
|
|||||||
if strings.TrimSpace(metadata[providerSettlementMetaOutgoingLeg]) == "" {
|
if strings.TrimSpace(metadata[providerSettlementMetaOutgoingLeg]) == "" {
|
||||||
metadata[providerSettlementMetaOutgoingLeg] = strings.ToLower(strings.TrimSpace(string(step.Rail)))
|
metadata[providerSettlementMetaOutgoingLeg] = strings.ToLower(strings.TrimSpace(string(step.Rail)))
|
||||||
}
|
}
|
||||||
|
sourceAmount := resolveDebitAmount(payment, quote, payment.Intent.Amount)
|
||||||
|
if sourceAmount != nil {
|
||||||
|
if strings.TrimSpace(metadata[providerSettlementMetaSourceAmount]) == "" {
|
||||||
|
metadata[providerSettlementMetaSourceAmount] = strings.TrimSpace(sourceAmount.Amount)
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(metadata[providerSettlementMetaSourceCurrency]) == "" {
|
||||||
|
metadata[providerSettlementMetaSourceCurrency] = strings.TrimSpace(sourceAmount.Currency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sourceWalletRef := ""
|
sourceWalletRef := ""
|
||||||
if payment.Intent.Source.ManagedWallet != nil {
|
if payment.Intent.Source.ManagedWallet != nil {
|
||||||
|
|||||||
@@ -93,6 +93,6 @@ require (
|
|||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -269,8 +269,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
nm "github.com/tech/sendico/pkg/model/notification"
|
||||||
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TelegramReactionNotification struct {
|
||||||
|
messaging.Envelope
|
||||||
|
payload model.TelegramReactionRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trn *TelegramReactionNotification) Serialize() ([]byte, error) {
|
||||||
|
data, err := json.Marshal(trn.payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return trn.Envelope.Wrap(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramReactionEvent() model.NotificationEvent {
|
||||||
|
return model.NewNotification(mservice.Notifications, nm.NATelegramReaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTelegramReactionEnvelope(sender string, request *model.TelegramReactionRequest) messaging.Envelope {
|
||||||
|
var payload model.TelegramReactionRequest
|
||||||
|
if request != nil {
|
||||||
|
payload = *request
|
||||||
|
}
|
||||||
|
return &TelegramReactionNotification{
|
||||||
|
Envelope: messaging.CreateEnvelope(sender, telegramReactionEvent()),
|
||||||
|
payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
me "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||||
|
ch "github.com/tech/sendico/pkg/messaging/notifications/telegram/handler"
|
||||||
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TelegramReactionProcessor struct {
|
||||||
|
logger mlogger.Logger
|
||||||
|
handler ch.TelegramReactionHandler
|
||||||
|
event model.NotificationEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trp *TelegramReactionProcessor) Process(ctx context.Context, envelope me.Envelope) error {
|
||||||
|
var msg model.TelegramReactionRequest
|
||||||
|
if err := json.Unmarshal(envelope.GetData(), &msg); err != nil {
|
||||||
|
trp.logger.Warn("Failed to decode telegram reaction envelope", zap.Error(err), zap.String("topic", trp.event.ToString()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if trp.handler == nil {
|
||||||
|
trp.logger.Warn("Telegram reaction handler is not configured", zap.String("topic", trp.event.ToString()))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return trp.handler(ctx, &msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trp *TelegramReactionProcessor) GetSubject() model.NotificationEvent {
|
||||||
|
return trp.event
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTelegramReactionProcessor(logger mlogger.Logger, handler ch.TelegramReactionHandler) np.EnvelopeProcessor {
|
||||||
|
if logger != nil {
|
||||||
|
logger = logger.Named("telegram_reaction_processor")
|
||||||
|
}
|
||||||
|
return &TelegramReactionProcessor{
|
||||||
|
logger: logger,
|
||||||
|
handler: handler,
|
||||||
|
event: telegramReactionEvent(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TelegramReactionHandler = func(context.Context, *model.TelegramReactionRequest) error
|
||||||
18
api/pkg/messaging/notifications/telegram/telegram.go
Normal file
18
api/pkg/messaging/notifications/telegram/telegram.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
messaging "github.com/tech/sendico/pkg/messaging/envelope"
|
||||||
|
tinternal "github.com/tech/sendico/pkg/messaging/internal/notifications/telegram"
|
||||||
|
np "github.com/tech/sendico/pkg/messaging/notifications/processor"
|
||||||
|
ch "github.com/tech/sendico/pkg/messaging/notifications/telegram/handler"
|
||||||
|
"github.com/tech/sendico/pkg/mlogger"
|
||||||
|
"github.com/tech/sendico/pkg/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TelegramReaction(sender string, request *model.TelegramReactionRequest) messaging.Envelope {
|
||||||
|
return tinternal.NewTelegramReactionEnvelope(sender, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTelegramReactionProcessor(logger mlogger.Logger, handler ch.TelegramReactionHandler) np.EnvelopeProcessor {
|
||||||
|
return tinternal.NewTelegramReactionProcessor(logger, handler)
|
||||||
|
}
|
||||||
@@ -27,16 +27,6 @@ type ConfirmationResult struct {
|
|||||||
RequestID string `bson:"requestId,omitempty" json:"request_id,omitempty"`
|
RequestID string `bson:"requestId,omitempty" json:"request_id,omitempty"`
|
||||||
Money *paymenttypes.Money `bson:"money,omitempty" json:"money,omitempty"`
|
Money *paymenttypes.Money `bson:"money,omitempty" json:"money,omitempty"`
|
||||||
RawReply *TelegramMessage `bson:"rawReply,omitempty" json:"raw_reply,omitempty"`
|
RawReply *TelegramMessage `bson:"rawReply,omitempty" json:"raw_reply,omitempty"`
|
||||||
Status ConfirmationStatus `bson:"status,omitempty" json:"status,omitempty"`
|
Status ConfirmationStatus `bson:"status,omitempty" json:"status,omitempty"`
|
||||||
ParseError string `bson:"parseError,omitempty" json:"parse_error,omitempty"`
|
ParseError string `bson:"parseError,omitempty" json:"parse_error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TelegramMessage struct {
|
|
||||||
ChatID string `bson:"chatId,omitempty" json:"chat_id,omitempty"`
|
|
||||||
MessageID string `bson:"messageId,omitempty" json:"message_id,omitempty"`
|
|
||||||
ReplyToMessageID string `bson:"replyToMessageId,omitempty" json:"reply_to_message_id,omitempty"`
|
|
||||||
FromUserID string `bson:"fromUserId,omitempty" json:"from_user_id,omitempty"`
|
|
||||||
FromUsername string `bson:"fromUsername,omitempty" json:"from_username,omitempty"`
|
|
||||||
Text string `bson:"text,omitempty" json:"text,omitempty"`
|
|
||||||
SentAt int64 `bson:"sentAt,omitempty" json:"sent_at,omitempty"`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func FromStringImp(s string) (*NotificationEventImp, error) {
|
|||||||
|
|
||||||
func StringToNotificationAction(s string) (nm.NotificationAction, error) {
|
func StringToNotificationAction(s string) (nm.NotificationAction, error) {
|
||||||
switch nm.NotificationAction(s) {
|
switch nm.NotificationAction(s) {
|
||||||
case nm.NACreated, nm.NAPending, nm.NAUpdated, nm.NADeleted, nm.NAAssigned, nm.NAPasswordReset:
|
case nm.NACreated, nm.NAPending, nm.NAUpdated, nm.NADeleted, nm.NAAssigned, nm.NAPasswordReset, nm.NAConfirmationRequest, nm.NATelegramReaction, nm.NAPaymentGatewayIntent, nm.NAPaymentGatewayExecution, nm.NADiscoveryServiceAnnounce, nm.NADiscoveryGatewayAnnounce, nm.NADiscoveryHeartbeat, nm.NADiscoveryLookupRequest, nm.NADiscoveryLookupResponse, nm.NADiscoveryRefreshUI:
|
||||||
return nm.NotificationAction(s), nil
|
return nm.NotificationAction(s), nil
|
||||||
default:
|
default:
|
||||||
return "", merrors.DataConflict("invalid Notification action: " + s)
|
return "", merrors.DataConflict("invalid Notification action: " + s)
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ const (
|
|||||||
NASent NotificationAction = "sent"
|
NASent NotificationAction = "sent"
|
||||||
NAPasswordReset NotificationAction = "password_reset"
|
NAPasswordReset NotificationAction = "password_reset"
|
||||||
|
|
||||||
NAConfirmationRequest NotificationAction = "confirmation.request"
|
NAConfirmationRequest NotificationAction = "confirmation.request"
|
||||||
NAPaymentGatewayIntent NotificationAction = "intent.request"
|
NATelegramReaction NotificationAction = "telegram.reaction"
|
||||||
|
NAPaymentGatewayIntent NotificationAction = "intent.request"
|
||||||
NAPaymentGatewayExecution NotificationAction = "execution.result"
|
NAPaymentGatewayExecution NotificationAction = "execution.result"
|
||||||
|
|
||||||
NADiscoveryServiceAnnounce NotificationAction = "service.announce"
|
NADiscoveryServiceAnnounce NotificationAction = "service.announce"
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ func StringToNotificationAction(s string) (nm.NotificationAction, error) {
|
|||||||
nm.NAAssigned,
|
nm.NAAssigned,
|
||||||
nm.NAPasswordReset,
|
nm.NAPasswordReset,
|
||||||
nm.NAConfirmationRequest,
|
nm.NAConfirmationRequest,
|
||||||
|
nm.NATelegramReaction,
|
||||||
nm.NAPaymentGatewayIntent,
|
nm.NAPaymentGatewayIntent,
|
||||||
nm.NAPaymentGatewayExecution,
|
nm.NAPaymentGatewayExecution,
|
||||||
nm.NADiscoveryServiceAnnounce,
|
nm.NADiscoveryServiceAnnounce,
|
||||||
|
|||||||
18
api/pkg/model/telegram.go
Normal file
18
api/pkg/model/telegram.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type TelegramMessage struct {
|
||||||
|
ChatID string `bson:"chatId,omitempty" json:"chat_id,omitempty"`
|
||||||
|
MessageID string `bson:"messageId,omitempty" json:"message_id,omitempty"`
|
||||||
|
ReplyToMessageID string `bson:"replyToMessageId,omitempty" json:"reply_to_message_id,omitempty"`
|
||||||
|
FromUserID string `bson:"fromUserId,omitempty" json:"from_user_id,omitempty"`
|
||||||
|
FromUsername string `bson:"fromUsername,omitempty" json:"from_username,omitempty"`
|
||||||
|
Text string `bson:"text,omitempty" json:"text,omitempty"`
|
||||||
|
SentAt int64 `bson:"sentAt,omitempty" json:"sent_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TelegramReactionRequest struct {
|
||||||
|
RequestID string `bson:"requestId,omitempty" json:"request_id,omitempty"`
|
||||||
|
ChatID string `bson:"chatId,omitempty" json:"chat_id,omitempty"`
|
||||||
|
MessageID string `bson:"messageId,omitempty" json:"message_id,omitempty"`
|
||||||
|
Emoji string `bson:"emoji,omitempty" json:"emoji,omitempty"`
|
||||||
|
}
|
||||||
@@ -139,6 +139,6 @@ require (
|
|||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.19.0 // indirect
|
||||||
golang.org/x/sys v0.40.0 // indirect
|
golang.org/x/sys v0.40.0 // indirect
|
||||||
golang.org/x/text v0.33.0 // indirect
|
golang.org/x/text v0.33.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 // indirect
|
||||||
google.golang.org/grpc v1.78.0 // indirect
|
google.golang.org/grpc v1.78.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -361,8 +361,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575 h1:vzOYHDZEHIsPYYnaSYo60AqHkJronSu0rzTz/s4quL0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120174246-409b4a993575/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
|||||||
@@ -35,6 +35,11 @@
|
|||||||
header Expires "0"
|
header Expires "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Telegram webhook -> notification service.
|
||||||
|
handle /telegram/webhook {
|
||||||
|
reverse_proxy sendico-notification:8081
|
||||||
|
}
|
||||||
|
|
||||||
# Monetix payout callbacks -> mntx gateway (IP allow-listed)
|
# Monetix payout callbacks -> mntx gateway (IP allow-listed)
|
||||||
@monetixSuccess {
|
@monetixSuccess {
|
||||||
path /gateway/m/success*
|
path /gateway/m/success*
|
||||||
|
|||||||
Reference in New Issue
Block a user