Compare commits

...

10 commits

Author SHA1 Message Date
nquidox
6867d2d74e grpc server added 2025-10-01 19:32:56 +03:00
nquidox
5e1017df69 created 2025-10-01 19:32:27 +03:00
nquidox
850fb38e16 removed 2025-10-01 19:32:06 +03:00
nquidox
2ada5e5a9e update 2025-10-01 19:31:58 +03:00
nquidox
4759e7638c switch update to upsert 2025-10-01 12:13:43 +03:00
nquidox
a4097706de merch update method refactor 2025-10-01 11:00:39 +03:00
nquidox
7dd4a6830e release option fix 2025-09-30 18:47:23 +03:00
nquidox
62337d3943 action added
Some checks failed
/ Make image (push) Has been cancelled
2025-09-30 17:00:04 +03:00
nquidox
9a83bac140 update 2025-09-30 16:59:51 +03:00
nquidox
392cdbfd4d dockerfile created 2025-09-30 15:33:00 +03:00
23 changed files with 1073 additions and 68 deletions

6
.dockerignore Normal file
View file

@ -0,0 +1,6 @@
.idea
.git
.gitignore
api.env
gen-swag.sh
migrations.sql

View file

@ -0,0 +1,31 @@
on:
push:
tags:
- 'v[0-9]+*'
env:
IMAGE_NAME: repo-app
jobs:
docker:
name: Make image
runs-on: docker
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Login to Docker Registry
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login repo.nqws.ru -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
- name: Extract version from tag
id: extract_version
run: |
VERSION=${GITHUB_REF#refs/tags/}
echo "VERSION=${VERSION}" >> $GITHUB_ENV
- name: Make image
run: |
docker buildx build --platform linux/amd64 \
--tag repo.nqws.ru/merch-tracker/repo-app-v2:latest \
--tag repo.nqws.ru/merch-tracker/repo-app-v2:${{ env.VERSION }} \
--push .

34
Dockerfile Normal file
View file

@ -0,0 +1,34 @@
FROM golang:1.25.1-alpine3.22 AS builder
RUN apk add --no-cache \
bash \
curl \
git \
ca-certificates
RUN apk add --no-cache tzdata
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd
FROM alpine:3.22
RUN apk add --no-cache \
bash \
curl \
ca-certificates \
tzdata
COPY --from=builder /app/main /usr/local/bin/app
RUN chmod +x /usr/local/bin/app
RUN adduser -D -s /bin/bash appuser
USER appuser
ENTRYPOINT ["app"]

View file

@ -5,6 +5,9 @@ APP_API_PREFIX=/api/v2
APP_GIN_MODE=development
APP_ALLOWED_ORIGINS=http://localhost:5173,
GRPC_SERVER_PORT=9050
GRPC_CLIENT_PORT=9060
DB_HOST=
DB_PORT=
DB_USER=

View file

@ -8,6 +8,7 @@ import (
"merch-parser-api/internal/api/merch"
"merch-parser-api/internal/api/user"
"merch-parser-api/internal/app"
"merch-parser-api/internal/grpcService"
"merch-parser-api/internal/interfaces"
"merch-parser-api/internal/provider/auth"
"merch-parser-api/internal/provider/token"
@ -66,6 +67,10 @@ func main() {
})
log.Debug("Auth provider initialized")
tasksRepo := merch.NewTaskRepository(database)
tasksProvider := merch.NewTaskProvider(tasksRepo)
grpcServer := grpcService.NewGrpcServer(tasksProvider)
//register app modules
users := user.NewHandler(user.Deps{
Auth: authProvider,
@ -87,11 +92,14 @@ func main() {
//keep last
appl := app.NewApp(app.Deps{
Host: c.AppConf.Host,
Port: c.AppConf.Port,
ApiPrefix: c.AppConf.ApiPrefix,
RouterHandler: routerHandler,
Modules: modules,
Host: c.AppConf.Host,
Port: c.AppConf.Port,
ApiPrefix: c.AppConf.ApiPrefix,
RouterHandler: routerHandler,
Modules: modules,
GrpcServer: grpcServer,
GrpcServerPort: c.GrpcConf.GrpcServerPort,
GrpcClientPort: c.GrpcConf.GrpcClientPort,
})
err = appl.Run(ctx)

View file

@ -3,9 +3,10 @@ package config
import "strings"
type Config struct {
AppConf AppConfig
DBConf DatabaseConfig
JWTConf JWTConfig
AppConf AppConfig
DBConf DatabaseConfig
JWTConf JWTConfig
GrpcConf GrpcConfig
}
type AppConfig struct {
@ -34,6 +35,11 @@ type JWTConfig struct {
RefreshExpire string
}
type GrpcConfig struct {
GrpcServerPort string
GrpcClientPort string
}
func NewConfig() *Config {
return &Config{
AppConf: AppConfig{
@ -61,5 +67,10 @@ func NewConfig() *Config {
AccessExpire: getEnv("JWT_ACCESS_EXPIRE", ""),
RefreshExpire: getEnv("JWT_REFRESH_EXPIRE", ""),
},
GrpcConf: GrpcConfig{
GrpcServerPort: getEnv("GRPC_SERVER_PORT", ""),
GrpcClientPort: getEnv("GRPC_CLIENT_PORT", ""),
},
}
}

4
go.mod
View file

@ -12,6 +12,8 @@ require (
github.com/swaggo/gin-swagger v1.6.1
github.com/swaggo/swag v1.16.6
golang.org/x/crypto v0.42.0
google.golang.org/grpc v1.75.1
google.golang.org/protobuf v1.36.9
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.31.0
)
@ -66,5 +68,5 @@ require (
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/tools v0.37.0 // indirect
google.golang.org/protobuf v1.36.9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
)

6
go.sum
View file

@ -173,6 +173,12 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -134,16 +134,16 @@ func (co *controller) getAllMerch(c *gin.Context) {
// @Description Обновить информацию про мерч по его uuid в json-е
// @Tags Merch
// @Security BearerAuth
// @Param body body MerchDTO true "merch_uuid"
// @Success 200 {object} MerchDTO
// @Param body body UpdateMerchDTO true "merch_uuid"
// @Success 200
// @Failure 400 {object} responses.ErrorResponse400
// @Failure 500 {object} responses.ErrorResponse500
// @Router /merch/{uuid} [put]
// @Router /merch/ [put]
func (co *controller) updateMerch(c *gin.Context) {
var payload MerchDTO
var payload UpdateMerchDTO
if err := c.ShouldBind(&payload); err != nil {
c.JSON(http.StatusBadRequest, responses.ErrorResponse400{Error: err.Error()})
log.WithError(err).Error("Merch | Failed to bind JSON on add merch")
log.WithError(err).Error("Merch | Failed to bind JSON on update merch")
return
}

View file

@ -46,3 +46,10 @@ type PricesResponse struct {
MerchUuid string `json:"merch_uuid"`
Origins []OriginWithPrices `json:"origins"`
}
type UpdateMerchDTO struct {
MerchUuid string `json:"merch_uuid"`
Name string `json:"name"`
Origin string `json:"origin"`
Link string `json:"link"`
}

View file

@ -20,11 +20,10 @@ func (Merch) TableName() string {
}
type Surugaya struct {
Id uint `gorm:"primary_key" json:"-"`
DeletedAt sql.NullTime `json:"-"`
MerchUuid string `json:"-"`
Link string `json:"link"`
CookieValues string `json:"cookie_values"`
Id uint `gorm:"primary_key" json:"-"`
DeletedAt sql.NullTime `json:"-"`
MerchUuid string `json:"-"`
Link string `json:"link"`
}
func (Surugaya) TableName() string {

View file

@ -0,0 +1,93 @@
package merch
import (
"gorm.io/gorm"
"merch-parser-api/internal/shared"
)
type Link struct {
Surugaya []Surugaya
Mandarake []Mandarake
}
type TaskProvider struct {
repo TaskRepository
}
type TaskRepository interface {
GetLinks() (*Link, error)
InsertPrices() error
}
type TaskRepo struct {
db *gorm.DB
}
func NewTaskProvider(repo TaskRepository) *TaskProvider {
return &TaskProvider{
repo: repo,
}
}
func NewTaskRepository(db *gorm.DB) TaskRepository {
return &TaskRepo{db: db}
}
func (p *TaskProvider) PrepareTasks() (map[string]shared.Task, error) {
getLinks, err := p.repo.GetLinks()
if err != nil {
return nil, err
}
taskMap := make(map[string]shared.Task)
for _, item := range getLinks.Surugaya {
if task, exists := taskMap[item.MerchUuid]; exists {
task.OriginSurugayaLink = item.Link
taskMap[item.MerchUuid] = task
} else {
taskMap[item.MerchUuid] = shared.Task{
MerchUuid: item.MerchUuid,
OriginSurugayaLink: item.Link,
}
}
}
for _, item := range getLinks.Mandarake {
if task, exists := taskMap[item.MerchUuid]; exists {
task.OriginMandarakeLink = item.Link
taskMap[item.MerchUuid] = task
} else {
taskMap[item.MerchUuid] = shared.Task{
MerchUuid: item.MerchUuid,
OriginMandarakeLink: item.Link,
}
}
}
return taskMap, nil
}
func (p *TaskProvider) InsertPrices([]shared.TaskResult) error {
return nil
}
func (r *TaskRepo) GetLinks() (*Link, error) {
var surugayaList []Surugaya
if err := r.db.Model(&Surugaya{}).Find(&surugayaList).Error; err != nil {
return nil, err
}
var mandarakeList []Mandarake
if err := r.db.Model(&Mandarake{}).Find(&mandarakeList).Error; err != nil {
return nil, err
}
return &Link{
Surugaya: surugayaList,
Mandarake: mandarakeList,
}, nil
}
func (r *TaskRepo) InsertPrices() error {
return nil
}

View file

@ -4,6 +4,7 @@ import (
"database/sql"
"errors"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"time"
)
@ -23,7 +24,7 @@ type repository interface {
getSingleMerch(userUuid, merchUuid string) (merchBundle, error)
getAllMerch(userUuid string) ([]ListResponse, error)
updateMerch(payload MerchDTO, userUuid string) error
updateMerch(payload UpdateMerchDTO, userUuid string) error
deleteMerch(userUuid, merchUuid string) error
@ -99,7 +100,7 @@ func (r *Repo) getAllMerch(userUuid string) ([]ListResponse, error) {
return list, nil
}
func (r *Repo) updateMerch(payload MerchDTO, userUuid string) error {
func (r *Repo) updateMerch(payload UpdateMerchDTO, userUuid string) error {
m := make(map[string]any)
m["name"] = payload.Name
m["updated_at"] = sql.NullTime{
@ -115,27 +116,20 @@ func (r *Repo) updateMerch(payload MerchDTO, userUuid string) error {
return err
}
// surugaya
fields := make(map[string]any, 2)
if payload.OriginSurugaya.Link != "" {
fields["link"] = payload.OriginSurugaya.Link
}
if len(fields) > 0 {
if err := r.db.
Model(&Surugaya{}).
Where("merch_uuid = ?", payload.MerchUuid).
Updates(fields).Error; err != nil {
switch payload.Origin {
case "surugaya":
if err := r.upsertOrigin(&Surugaya{
MerchUuid: payload.MerchUuid,
Link: payload.Link,
}); err != nil {
return err
}
}
// mandarake
if payload.OriginMandarake.Link != "" {
if err := r.db.
Model(&Mandarake{}).
Where("merch_uuid = ?", payload.MerchUuid).
Update("link", payload.OriginMandarake.Link).Error; err != nil {
case "mandarake":
if err := r.upsertOrigin(&Mandarake{
MerchUuid: payload.MerchUuid,
Link: payload.Link,
}); err != nil {
return err
}
}
@ -223,3 +217,10 @@ func (r *Repo) getDistinctPrices(userUuid, merchUuid string, period time.Time) (
}
return prices, nil
}
func (r *Repo) upsertOrigin(model any) error {
return r.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "merch_uuid"}},
DoUpdates: clause.AssignmentColumns([]string{"link"}),
}).Create(model).Error
}

View file

@ -67,10 +67,19 @@ func (s *service) getAllMerch(userUuid string) ([]ListResponse, error) {
return s.repo.getAllMerch(userUuid)
}
func (s *service) updateMerch(payload MerchDTO, userUuid string) error {
func (s *service) updateMerch(payload UpdateMerchDTO, userUuid string) error {
if payload.MerchUuid == "" {
return errors.New("no MerchUuid or empty payload")
return errors.New("no merch uuid provided")
}
if payload.Origin == "" {
return errors.New("no origin provided")
}
if payload.Link == "" {
return errors.New("no link provided")
}
return s.repo.updateMerch(payload, userUuid)
}

View file

@ -4,33 +4,46 @@ import (
"context"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"merch-parser-api/internal/interfaces"
"net"
"net/http"
"time"
)
type App struct {
address string
apiPrefix string
modules []interfaces.Module
routerHandler interfaces.Router
router *gin.Engine
host string
address string
apiPrefix string
modules []interfaces.Module
routerHandler interfaces.Router
router *gin.Engine
grpcServer *grpc.Server
grpcServerPort string
grpcClientPort string
}
type Deps struct {
Host string
Port string
ApiPrefix string
Modules []interfaces.Module
RouterHandler interfaces.Router
Host string
Port string
ApiPrefix string
Modules []interfaces.Module
RouterHandler interfaces.Router
GrpcServer *grpc.Server
GrpcServerPort string
GrpcClientPort string
}
func NewApp(deps Deps) *App {
app := &App{
address: deps.Host + ":" + deps.Port,
apiPrefix: deps.ApiPrefix,
routerHandler: deps.RouterHandler,
modules: deps.Modules,
host: deps.Host,
address: deps.Host + ":" + deps.Port,
apiPrefix: deps.ApiPrefix,
routerHandler: deps.RouterHandler,
modules: deps.Modules,
grpcServer: deps.GrpcServer,
grpcServerPort: deps.GrpcServerPort,
grpcClientPort: deps.GrpcClientPort,
}
app.router = app.routerHandler.Set()
@ -62,6 +75,19 @@ func (a *App) Run(ctx context.Context) error {
serverErr <- server.ListenAndServe()
}()
go func() {
listener, err := net.Listen("tcp", net.JoinHostPort(a.host, a.grpcServerPort))
if err != nil {
log.WithField("err", err).Fatal("gRPC Server | Listener")
}
err = a.grpcServer.Serve(listener)
if err != nil {
log.WithField("err", err).Fatal("gRPC Server | Serve")
}
}()
log.Info("Starting gRPC server on port: ", a.grpcServerPort)
select {
case <-ctx.Done():
log.Info("Shutting down server")

View file

@ -0,0 +1,106 @@
package grpcService
import (
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
"io"
"merch-parser-api/internal/interfaces"
"merch-parser-api/internal/shared"
pb "merch-parser-api/proto/taskProcessor"
"time"
)
type repoServer struct {
pb.UnimplementedTaskProcessorServer
taskProvider interfaces.TaskProvider
}
func NewGrpcServer(taskProvider interfaces.TaskProvider) *grpc.Server {
srv := grpc.NewServer()
repoSrv := &repoServer{
taskProvider: taskProvider,
}
pb.RegisterTaskProcessorServer(srv, repoSrv)
return srv
}
func (r *repoServer) RequestTask(_ *emptypb.Empty, stream pb.TaskProcessor_RequestTaskServer) error {
tasks, err := r.taskProvider.PrepareTasks()
if err != nil {
log.WithField("err", err).Error("gRPC Server | Request task error")
return err
}
for _, task := range tasks {
if err = stream.Send(&pb.Task{
MerchUuid: task.MerchUuid,
OriginSurugayaLink: task.OriginSurugayaLink,
OriginMandarakeLink: task.OriginMandarakeLink,
}); err != nil {
log.WithField("err", err).Error("gRPC Server | Stream send error")
return err
}
}
return nil
}
func (r *repoServer) SendResult(stream pb.TaskProcessor_SendResultServer) error {
saveInterval := time.Second * 2
batch := make([]shared.TaskResult, 0)
ticker := time.NewTicker(saveInterval)
defer ticker.Stop()
done := make(chan struct{})
go func() {
for {
select {
case <-done:
return
case <-ticker.C:
if len(batch) > 0 {
err := r.taskProvider.InsertPrices(batch)
if err != nil {
log.WithField("err", err).Error("gRPC Server | Batch insert")
}
}
}
}
}()
for {
response, err := stream.Recv()
if err == io.EOF {
log.Debug("gRPC EOF")
break
}
if err != nil {
log.WithField("err", err).Error("gRPC Server | Receive")
return err
}
entry := shared.TaskResult{
MerchUuid: response.MerchUuid,
Origin: response.OriginName,
Price: response.Price,
}
batch = append(batch, entry)
log.WithField("response", entry).Debug("gRPC Server | Receive success")
}
close(done)
if len(batch) > 0 {
err := r.taskProvider.InsertPrices(batch)
if err != nil {
log.WithField("err", err).Error("gRPC Server | Last data batch insert")
return err
}
}
return nil
}

View file

@ -0,0 +1,8 @@
package interfaces
import "merch-parser-api/internal/shared"
type TaskProvider interface {
PrepareTasks() (map[string]shared.Task, error)
InsertPrices([]shared.TaskResult) error
}

View file

@ -7,17 +7,15 @@ import (
swaggerFiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"merch-parser-api/internal/interfaces"
"merch-parser-api/internal/shared"
"net/http"
"time"
)
type router struct {
apiPrefix string
engine *gin.Engine
ginMode string
excludeRoutes map[string]shared.ExcludeRoute
tokenProv interfaces.JWTProvider
apiPrefix string
engine *gin.Engine
ginMode string
tokenProv interfaces.JWTProvider
}
type Deps struct {
@ -28,8 +26,13 @@ type Deps struct {
}
func NewRouter(deps Deps) interfaces.Router {
engine := gin.Default()
if deps.GinMode == "release" {
gin.SetMode(gin.ReleaseMode)
} else {
gin.SetMode(gin.DebugMode)
}
engine := gin.Default()
if deps.GinMode == "release" {
gin.SetMode(gin.ReleaseMode)
err := engine.SetTrustedProxies([]string{"172.20.0.0/16"})

View file

@ -1,6 +0,0 @@
package shared
type ExcludeRoute struct {
Route string
Method string
}

13
internal/shared/task.go Normal file
View file

@ -0,0 +1,13 @@
package shared
type Task struct {
MerchUuid string
OriginSurugayaLink string
OriginMandarakeLink string
}
type TaskResult struct {
MerchUuid string
Origin string
Price uint32
}

41
proto/task.proto Normal file
View file

@ -0,0 +1,41 @@
syntax = "proto3";
import "google/protobuf/empty.proto";
package taskProcessor;
option go_package = "./taskProcessor";
message Task{
string merch_uuid = 1;
string origin_surugaya_link = 2;
string origin_mandarake_link = 3;
}
message Result{
string merch_uuid = 1;
string origin_name = 2;
uint32 price = 3;
}
message ProcessorStatusRequest{}
message ProcessorStatusResponse {
int64 appStart = 1;
int64 lastCheck = 2;
int32 tasksReceived = 3;
int32 tasksInProgress = 4;
int32 tasksFirstTry = 5;
int32 tasksDoneAfterRetry = 6;
int32 tasksFailed = 7;
string workStatus = 8;
int32 numCPUs = 9;
int32 checkPeriod = 10;
int32 retriesCount = 11;
int32 retriesMinutes = 12;
}
service TaskProcessor {
rpc RequestTask(google.protobuf.Empty) returns (stream Task);
rpc SendResult(stream Result) returns (google.protobuf.Empty);
rpc ProcessorStatus(ProcessorStatusRequest) returns (ProcessorStatusResponse);
}

View file

@ -0,0 +1,409 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v6.32.0
// source: task.proto
package taskProcessor
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Task struct {
state protoimpl.MessageState `protogen:"open.v1"`
MerchUuid string `protobuf:"bytes,1,opt,name=merch_uuid,json=merchUuid,proto3" json:"merch_uuid,omitempty"`
OriginSurugayaLink string `protobuf:"bytes,2,opt,name=origin_surugaya_link,json=originSurugayaLink,proto3" json:"origin_surugaya_link,omitempty"`
OriginMandarakeLink string `protobuf:"bytes,3,opt,name=origin_mandarake_link,json=originMandarakeLink,proto3" json:"origin_mandarake_link,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Task) Reset() {
*x = Task{}
mi := &file_task_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Task) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Task) ProtoMessage() {}
func (x *Task) ProtoReflect() protoreflect.Message {
mi := &file_task_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Task.ProtoReflect.Descriptor instead.
func (*Task) Descriptor() ([]byte, []int) {
return file_task_proto_rawDescGZIP(), []int{0}
}
func (x *Task) GetMerchUuid() string {
if x != nil {
return x.MerchUuid
}
return ""
}
func (x *Task) GetOriginSurugayaLink() string {
if x != nil {
return x.OriginSurugayaLink
}
return ""
}
func (x *Task) GetOriginMandarakeLink() string {
if x != nil {
return x.OriginMandarakeLink
}
return ""
}
type Result struct {
state protoimpl.MessageState `protogen:"open.v1"`
MerchUuid string `protobuf:"bytes,1,opt,name=merch_uuid,json=merchUuid,proto3" json:"merch_uuid,omitempty"`
OriginName string `protobuf:"bytes,2,opt,name=origin_name,json=originName,proto3" json:"origin_name,omitempty"`
Price uint32 `protobuf:"varint,3,opt,name=price,proto3" json:"price,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Result) Reset() {
*x = Result{}
mi := &file_task_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Result) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Result) ProtoMessage() {}
func (x *Result) ProtoReflect() protoreflect.Message {
mi := &file_task_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Result.ProtoReflect.Descriptor instead.
func (*Result) Descriptor() ([]byte, []int) {
return file_task_proto_rawDescGZIP(), []int{1}
}
func (x *Result) GetMerchUuid() string {
if x != nil {
return x.MerchUuid
}
return ""
}
func (x *Result) GetOriginName() string {
if x != nil {
return x.OriginName
}
return ""
}
func (x *Result) GetPrice() uint32 {
if x != nil {
return x.Price
}
return 0
}
type ProcessorStatusRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProcessorStatusRequest) Reset() {
*x = ProcessorStatusRequest{}
mi := &file_task_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProcessorStatusRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProcessorStatusRequest) ProtoMessage() {}
func (x *ProcessorStatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_task_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProcessorStatusRequest.ProtoReflect.Descriptor instead.
func (*ProcessorStatusRequest) Descriptor() ([]byte, []int) {
return file_task_proto_rawDescGZIP(), []int{2}
}
type ProcessorStatusResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
AppStart int64 `protobuf:"varint,1,opt,name=appStart,proto3" json:"appStart,omitempty"`
LastCheck int64 `protobuf:"varint,2,opt,name=lastCheck,proto3" json:"lastCheck,omitempty"`
TasksReceived int32 `protobuf:"varint,3,opt,name=tasksReceived,proto3" json:"tasksReceived,omitempty"`
TasksInProgress int32 `protobuf:"varint,4,opt,name=tasksInProgress,proto3" json:"tasksInProgress,omitempty"`
TasksFirstTry int32 `protobuf:"varint,5,opt,name=tasksFirstTry,proto3" json:"tasksFirstTry,omitempty"`
TasksDoneAfterRetry int32 `protobuf:"varint,6,opt,name=tasksDoneAfterRetry,proto3" json:"tasksDoneAfterRetry,omitempty"`
TasksFailed int32 `protobuf:"varint,7,opt,name=tasksFailed,proto3" json:"tasksFailed,omitempty"`
WorkStatus string `protobuf:"bytes,8,opt,name=workStatus,proto3" json:"workStatus,omitempty"`
NumCPUs int32 `protobuf:"varint,9,opt,name=numCPUs,proto3" json:"numCPUs,omitempty"`
CheckPeriod int32 `protobuf:"varint,10,opt,name=checkPeriod,proto3" json:"checkPeriod,omitempty"`
RetriesCount int32 `protobuf:"varint,11,opt,name=retriesCount,proto3" json:"retriesCount,omitempty"`
RetriesMinutes int32 `protobuf:"varint,12,opt,name=retriesMinutes,proto3" json:"retriesMinutes,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProcessorStatusResponse) Reset() {
*x = ProcessorStatusResponse{}
mi := &file_task_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProcessorStatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProcessorStatusResponse) ProtoMessage() {}
func (x *ProcessorStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_task_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProcessorStatusResponse.ProtoReflect.Descriptor instead.
func (*ProcessorStatusResponse) Descriptor() ([]byte, []int) {
return file_task_proto_rawDescGZIP(), []int{3}
}
func (x *ProcessorStatusResponse) GetAppStart() int64 {
if x != nil {
return x.AppStart
}
return 0
}
func (x *ProcessorStatusResponse) GetLastCheck() int64 {
if x != nil {
return x.LastCheck
}
return 0
}
func (x *ProcessorStatusResponse) GetTasksReceived() int32 {
if x != nil {
return x.TasksReceived
}
return 0
}
func (x *ProcessorStatusResponse) GetTasksInProgress() int32 {
if x != nil {
return x.TasksInProgress
}
return 0
}
func (x *ProcessorStatusResponse) GetTasksFirstTry() int32 {
if x != nil {
return x.TasksFirstTry
}
return 0
}
func (x *ProcessorStatusResponse) GetTasksDoneAfterRetry() int32 {
if x != nil {
return x.TasksDoneAfterRetry
}
return 0
}
func (x *ProcessorStatusResponse) GetTasksFailed() int32 {
if x != nil {
return x.TasksFailed
}
return 0
}
func (x *ProcessorStatusResponse) GetWorkStatus() string {
if x != nil {
return x.WorkStatus
}
return ""
}
func (x *ProcessorStatusResponse) GetNumCPUs() int32 {
if x != nil {
return x.NumCPUs
}
return 0
}
func (x *ProcessorStatusResponse) GetCheckPeriod() int32 {
if x != nil {
return x.CheckPeriod
}
return 0
}
func (x *ProcessorStatusResponse) GetRetriesCount() int32 {
if x != nil {
return x.RetriesCount
}
return 0
}
func (x *ProcessorStatusResponse) GetRetriesMinutes() int32 {
if x != nil {
return x.RetriesMinutes
}
return 0
}
var File_task_proto protoreflect.FileDescriptor
const file_task_proto_rawDesc = "" +
"\n" +
"\n" +
"task.proto\x12\rtaskProcessor\x1a\x1bgoogle/protobuf/empty.proto\"\x8b\x01\n" +
"\x04Task\x12\x1d\n" +
"\n" +
"merch_uuid\x18\x01 \x01(\tR\tmerchUuid\x120\n" +
"\x14origin_surugaya_link\x18\x02 \x01(\tR\x12originSurugayaLink\x122\n" +
"\x15origin_mandarake_link\x18\x03 \x01(\tR\x13originMandarakeLink\"^\n" +
"\x06Result\x12\x1d\n" +
"\n" +
"merch_uuid\x18\x01 \x01(\tR\tmerchUuid\x12\x1f\n" +
"\vorigin_name\x18\x02 \x01(\tR\n" +
"originName\x12\x14\n" +
"\x05price\x18\x03 \x01(\rR\x05price\"\x18\n" +
"\x16ProcessorStatusRequest\"\xc5\x03\n" +
"\x17ProcessorStatusResponse\x12\x1a\n" +
"\bappStart\x18\x01 \x01(\x03R\bappStart\x12\x1c\n" +
"\tlastCheck\x18\x02 \x01(\x03R\tlastCheck\x12$\n" +
"\rtasksReceived\x18\x03 \x01(\x05R\rtasksReceived\x12(\n" +
"\x0ftasksInProgress\x18\x04 \x01(\x05R\x0ftasksInProgress\x12$\n" +
"\rtasksFirstTry\x18\x05 \x01(\x05R\rtasksFirstTry\x120\n" +
"\x13tasksDoneAfterRetry\x18\x06 \x01(\x05R\x13tasksDoneAfterRetry\x12 \n" +
"\vtasksFailed\x18\a \x01(\x05R\vtasksFailed\x12\x1e\n" +
"\n" +
"workStatus\x18\b \x01(\tR\n" +
"workStatus\x12\x18\n" +
"\anumCPUs\x18\t \x01(\x05R\anumCPUs\x12 \n" +
"\vcheckPeriod\x18\n" +
" \x01(\x05R\vcheckPeriod\x12\"\n" +
"\fretriesCount\x18\v \x01(\x05R\fretriesCount\x12&\n" +
"\x0eretriesMinutes\x18\f \x01(\x05R\x0eretriesMinutes2\xee\x01\n" +
"\rTaskProcessor\x12<\n" +
"\vRequestTask\x12\x16.google.protobuf.Empty\x1a\x13.taskProcessor.Task0\x01\x12=\n" +
"\n" +
"SendResult\x12\x15.taskProcessor.Result\x1a\x16.google.protobuf.Empty(\x01\x12`\n" +
"\x0fProcessorStatus\x12%.taskProcessor.ProcessorStatusRequest\x1a&.taskProcessor.ProcessorStatusResponseB\x11Z\x0f./taskProcessorb\x06proto3"
var (
file_task_proto_rawDescOnce sync.Once
file_task_proto_rawDescData []byte
)
func file_task_proto_rawDescGZIP() []byte {
file_task_proto_rawDescOnce.Do(func() {
file_task_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_task_proto_rawDesc), len(file_task_proto_rawDesc)))
})
return file_task_proto_rawDescData
}
var file_task_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_task_proto_goTypes = []any{
(*Task)(nil), // 0: taskProcessor.Task
(*Result)(nil), // 1: taskProcessor.Result
(*ProcessorStatusRequest)(nil), // 2: taskProcessor.ProcessorStatusRequest
(*ProcessorStatusResponse)(nil), // 3: taskProcessor.ProcessorStatusResponse
(*emptypb.Empty)(nil), // 4: google.protobuf.Empty
}
var file_task_proto_depIdxs = []int32{
4, // 0: taskProcessor.TaskProcessor.RequestTask:input_type -> google.protobuf.Empty
1, // 1: taskProcessor.TaskProcessor.SendResult:input_type -> taskProcessor.Result
2, // 2: taskProcessor.TaskProcessor.ProcessorStatus:input_type -> taskProcessor.ProcessorStatusRequest
0, // 3: taskProcessor.TaskProcessor.RequestTask:output_type -> taskProcessor.Task
4, // 4: taskProcessor.TaskProcessor.SendResult:output_type -> google.protobuf.Empty
3, // 5: taskProcessor.TaskProcessor.ProcessorStatus:output_type -> taskProcessor.ProcessorStatusResponse
3, // [3:6] is the sub-list for method output_type
0, // [0:3] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_task_proto_init() }
func file_task_proto_init() {
if File_task_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_task_proto_rawDesc), len(file_task_proto_rawDesc)),
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_task_proto_goTypes,
DependencyIndexes: file_task_proto_depIdxs,
MessageInfos: file_task_proto_msgTypes,
}.Build()
File_task_proto = out.File
file_task_proto_goTypes = nil
file_task_proto_depIdxs = nil
}

View file

@ -0,0 +1,195 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v6.32.0
// source: task.proto
package taskProcessor
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
TaskProcessor_RequestTask_FullMethodName = "/taskProcessor.TaskProcessor/RequestTask"
TaskProcessor_SendResult_FullMethodName = "/taskProcessor.TaskProcessor/SendResult"
TaskProcessor_ProcessorStatus_FullMethodName = "/taskProcessor.TaskProcessor/ProcessorStatus"
)
// TaskProcessorClient is the client API for TaskProcessor service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type TaskProcessorClient interface {
RequestTask(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Task], error)
SendResult(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[Result, emptypb.Empty], error)
ProcessorStatus(ctx context.Context, in *ProcessorStatusRequest, opts ...grpc.CallOption) (*ProcessorStatusResponse, error)
}
type taskProcessorClient struct {
cc grpc.ClientConnInterface
}
func NewTaskProcessorClient(cc grpc.ClientConnInterface) TaskProcessorClient {
return &taskProcessorClient{cc}
}
func (c *taskProcessorClient) RequestTask(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Task], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &TaskProcessor_ServiceDesc.Streams[0], TaskProcessor_RequestTask_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[emptypb.Empty, Task]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type TaskProcessor_RequestTaskClient = grpc.ServerStreamingClient[Task]
func (c *taskProcessorClient) SendResult(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[Result, emptypb.Empty], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &TaskProcessor_ServiceDesc.Streams[1], TaskProcessor_SendResult_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[Result, emptypb.Empty]{ClientStream: stream}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type TaskProcessor_SendResultClient = grpc.ClientStreamingClient[Result, emptypb.Empty]
func (c *taskProcessorClient) ProcessorStatus(ctx context.Context, in *ProcessorStatusRequest, opts ...grpc.CallOption) (*ProcessorStatusResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ProcessorStatusResponse)
err := c.cc.Invoke(ctx, TaskProcessor_ProcessorStatus_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// TaskProcessorServer is the server API for TaskProcessor service.
// All implementations must embed UnimplementedTaskProcessorServer
// for forward compatibility.
type TaskProcessorServer interface {
RequestTask(*emptypb.Empty, grpc.ServerStreamingServer[Task]) error
SendResult(grpc.ClientStreamingServer[Result, emptypb.Empty]) error
ProcessorStatus(context.Context, *ProcessorStatusRequest) (*ProcessorStatusResponse, error)
mustEmbedUnimplementedTaskProcessorServer()
}
// UnimplementedTaskProcessorServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedTaskProcessorServer struct{}
func (UnimplementedTaskProcessorServer) RequestTask(*emptypb.Empty, grpc.ServerStreamingServer[Task]) error {
return status.Errorf(codes.Unimplemented, "method RequestTask not implemented")
}
func (UnimplementedTaskProcessorServer) SendResult(grpc.ClientStreamingServer[Result, emptypb.Empty]) error {
return status.Errorf(codes.Unimplemented, "method SendResult not implemented")
}
func (UnimplementedTaskProcessorServer) ProcessorStatus(context.Context, *ProcessorStatusRequest) (*ProcessorStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ProcessorStatus not implemented")
}
func (UnimplementedTaskProcessorServer) mustEmbedUnimplementedTaskProcessorServer() {}
func (UnimplementedTaskProcessorServer) testEmbeddedByValue() {}
// UnsafeTaskProcessorServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to TaskProcessorServer will
// result in compilation errors.
type UnsafeTaskProcessorServer interface {
mustEmbedUnimplementedTaskProcessorServer()
}
func RegisterTaskProcessorServer(s grpc.ServiceRegistrar, srv TaskProcessorServer) {
// If the following call pancis, it indicates UnimplementedTaskProcessorServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&TaskProcessor_ServiceDesc, srv)
}
func _TaskProcessor_RequestTask_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(emptypb.Empty)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(TaskProcessorServer).RequestTask(m, &grpc.GenericServerStream[emptypb.Empty, Task]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type TaskProcessor_RequestTaskServer = grpc.ServerStreamingServer[Task]
func _TaskProcessor_SendResult_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(TaskProcessorServer).SendResult(&grpc.GenericServerStream[Result, emptypb.Empty]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type TaskProcessor_SendResultServer = grpc.ClientStreamingServer[Result, emptypb.Empty]
func _TaskProcessor_ProcessorStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProcessorStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TaskProcessorServer).ProcessorStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: TaskProcessor_ProcessorStatus_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TaskProcessorServer).ProcessorStatus(ctx, req.(*ProcessorStatusRequest))
}
return interceptor(ctx, in, info, handler)
}
// TaskProcessor_ServiceDesc is the grpc.ServiceDesc for TaskProcessor service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var TaskProcessor_ServiceDesc = grpc.ServiceDesc{
ServiceName: "taskProcessor.TaskProcessor",
HandlerType: (*TaskProcessorServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ProcessorStatus",
Handler: _TaskProcessor_ProcessorStatus_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "RequestTask",
Handler: _TaskProcessor_RequestTask_Handler,
ServerStreams: true,
},
{
StreamName: "SendResult",
Handler: _TaskProcessor_SendResult_Handler,
ClientStreams: true,
},
},
Metadata: "task.proto",
}