Add Wildberries product fetching and rate limiting functionality
This commit is contained in:
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM alpine:latest
|
||||
WORKDIR /app
|
||||
COPY main .
|
||||
COPY ".env" .
|
||||
RUN apk add gcompat
|
||||
CMD ["./main"]
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.6
|
||||
// protoc v6.31.0
|
||||
// protoc v6.31.1
|
||||
// source: marketplace/marketplace.proto
|
||||
|
||||
package marketplace
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v6.31.0
|
||||
// - protoc v6.31.1
|
||||
// source: marketplace/marketplace.proto
|
||||
|
||||
package marketplace
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.6
|
||||
// protoc v6.31.0
|
||||
// protoc v6.31.1
|
||||
// source: ozon/products.proto
|
||||
|
||||
package products
|
||||
@@ -110,6 +110,94 @@ func (x *GetListOfProductsResponse) GetProducts() []*Product {
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetProductPriceRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
MarketplaceId int64 `protobuf:"varint,1,opt,name=marketplace_id,json=marketplaceId,proto3" json:"marketplace_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetProductPriceRequest) Reset() {
|
||||
*x = GetProductPriceRequest{}
|
||||
mi := &file_ozon_products_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetProductPriceRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetProductPriceRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetProductPriceRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_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 GetProductPriceRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetProductPriceRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *GetProductPriceRequest) GetMarketplaceId() int64 {
|
||||
if x != nil {
|
||||
return x.MarketplaceId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetProductPriceResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ProductPrices []*ProductPrice `protobuf:"bytes,1,rep,name=product_prices,json=productPrices,proto3" json:"product_prices,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetProductPriceResponse) Reset() {
|
||||
*x = GetProductPriceResponse{}
|
||||
mi := &file_ozon_products_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetProductPriceResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetProductPriceResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetProductPriceResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_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 GetProductPriceResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetProductPriceResponse) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *GetProductPriceResponse) GetProductPrices() []*ProductPrice {
|
||||
if x != nil {
|
||||
return x.ProductPrices
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Product struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
@@ -123,7 +211,7 @@ type Product struct {
|
||||
|
||||
func (x *Product) Reset() {
|
||||
*x = Product{}
|
||||
mi := &file_ozon_products_proto_msgTypes[2]
|
||||
mi := &file_ozon_products_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -135,7 +223,7 @@ func (x *Product) String() string {
|
||||
func (*Product) ProtoMessage() {}
|
||||
|
||||
func (x *Product) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_proto_msgTypes[2]
|
||||
mi := &file_ozon_products_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -148,7 +236,7 @@ func (x *Product) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Product.ProtoReflect.Descriptor instead.
|
||||
func (*Product) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{2}
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *Product) GetId() int64 {
|
||||
@@ -186,6 +274,74 @@ func (x *Product) GetStatuses() *Product_Status {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ProductPrice struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Acquiring uint32 `protobuf:"varint,1,opt,name=acquiring,proto3" json:"acquiring,omitempty"`
|
||||
Commissions *ProductPrice_Commissions `protobuf:"bytes,2,opt,name=commissions,proto3" json:"commissions,omitempty"`
|
||||
OfferId string `protobuf:"bytes,4,opt,name=offer_id,json=offerId,proto3" json:"offer_id,omitempty"`
|
||||
ProductId uint32 `protobuf:"varint,7,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ProductPrice) Reset() {
|
||||
*x = ProductPrice{}
|
||||
mi := &file_ozon_products_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ProductPrice) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProductPrice) ProtoMessage() {}
|
||||
|
||||
func (x *ProductPrice) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_proto_msgTypes[5]
|
||||
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 ProductPrice.ProtoReflect.Descriptor instead.
|
||||
func (*ProductPrice) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *ProductPrice) GetAcquiring() uint32 {
|
||||
if x != nil {
|
||||
return x.Acquiring
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice) GetCommissions() *ProductPrice_Commissions {
|
||||
if x != nil {
|
||||
return x.Commissions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ProductPrice) GetOfferId() string {
|
||||
if x != nil {
|
||||
return x.OfferId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ProductPrice) GetProductId() uint32 {
|
||||
if x != nil {
|
||||
return x.ProductId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Product_Status struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
StatusName string `protobuf:"bytes,1,opt,name=status_name,json=statusName,proto3" json:"status_name,omitempty"`
|
||||
@@ -195,7 +351,7 @@ type Product_Status struct {
|
||||
|
||||
func (x *Product_Status) Reset() {
|
||||
*x = Product_Status{}
|
||||
mi := &file_ozon_products_proto_msgTypes[3]
|
||||
mi := &file_ozon_products_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -207,7 +363,7 @@ func (x *Product_Status) String() string {
|
||||
func (*Product_Status) ProtoMessage() {}
|
||||
|
||||
func (x *Product_Status) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_proto_msgTypes[3]
|
||||
mi := &file_ozon_products_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -220,7 +376,7 @@ func (x *Product_Status) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Product_Status.ProtoReflect.Descriptor instead.
|
||||
func (*Product_Status) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{2, 0}
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{4, 0}
|
||||
}
|
||||
|
||||
func (x *Product_Status) GetStatusName() string {
|
||||
@@ -240,7 +396,7 @@ type Product_Stocks struct {
|
||||
|
||||
func (x *Product_Stocks) Reset() {
|
||||
*x = Product_Stocks{}
|
||||
mi := &file_ozon_products_proto_msgTypes[4]
|
||||
mi := &file_ozon_products_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -252,7 +408,7 @@ func (x *Product_Stocks) String() string {
|
||||
func (*Product_Stocks) ProtoMessage() {}
|
||||
|
||||
func (x *Product_Stocks) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_proto_msgTypes[4]
|
||||
mi := &file_ozon_products_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -265,7 +421,7 @@ func (x *Product_Stocks) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Product_Stocks.ProtoReflect.Descriptor instead.
|
||||
func (*Product_Stocks) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{2, 1}
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{4, 1}
|
||||
}
|
||||
|
||||
func (x *Product_Stocks) GetStocks() []*Product_Stock {
|
||||
@@ -294,7 +450,7 @@ type Product_Stock struct {
|
||||
|
||||
func (x *Product_Stock) Reset() {
|
||||
*x = Product_Stock{}
|
||||
mi := &file_ozon_products_proto_msgTypes[5]
|
||||
mi := &file_ozon_products_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@@ -306,7 +462,7 @@ func (x *Product_Stock) String() string {
|
||||
func (*Product_Stock) ProtoMessage() {}
|
||||
|
||||
func (x *Product_Stock) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_proto_msgTypes[5]
|
||||
mi := &file_ozon_products_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@@ -319,7 +475,7 @@ func (x *Product_Stock) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use Product_Stock.ProtoReflect.Descriptor instead.
|
||||
func (*Product_Stock) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{2, 2}
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{4, 2}
|
||||
}
|
||||
|
||||
func (x *Product_Stock) GetPresent() int64 {
|
||||
@@ -350,6 +506,138 @@ func (x *Product_Stock) GetSource() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type ProductPrice_Commissions struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
FboDelivToCustomerAmount float64 `protobuf:"fixed64,1,opt,name=fbo_deliv_to_customer_amount,json=fboDelivToCustomerAmount,proto3" json:"fbo_deliv_to_customer_amount,omitempty"`
|
||||
FboDirectFlowTransMaxAmount float64 `protobuf:"fixed64,2,opt,name=fbo_direct_flow_trans_max_amount,json=fboDirectFlowTransMaxAmount,proto3" json:"fbo_direct_flow_trans_max_amount,omitempty"`
|
||||
FboDirectFlowTransMinAmount float64 `protobuf:"fixed64,3,opt,name=fbo_direct_flow_trans_min_amount,json=fboDirectFlowTransMinAmount,proto3" json:"fbo_direct_flow_trans_min_amount,omitempty"`
|
||||
FboReturnFlowAmount float64 `protobuf:"fixed64,4,opt,name=fbo_return_flow_amount,json=fboReturnFlowAmount,proto3" json:"fbo_return_flow_amount,omitempty"`
|
||||
FbsDelivToCustomerAmount float64 `protobuf:"fixed64,5,opt,name=fbs_deliv_to_customer_amount,json=fbsDelivToCustomerAmount,proto3" json:"fbs_deliv_to_customer_amount,omitempty"`
|
||||
FbsDirectFlowTransMaxAmount float64 `protobuf:"fixed64,6,opt,name=fbs_direct_flow_trans_max_amount,json=fbsDirectFlowTransMaxAmount,proto3" json:"fbs_direct_flow_trans_max_amount,omitempty"`
|
||||
FbsDirectFlowTransMinAmount float64 `protobuf:"fixed64,7,opt,name=fbs_direct_flow_trans_min_amount,json=fbsDirectFlowTransMinAmount,proto3" json:"fbs_direct_flow_trans_min_amount,omitempty"`
|
||||
FbsFirstMileMaxAmount float64 `protobuf:"fixed64,8,opt,name=fbs_first_mile_max_amount,json=fbsFirstMileMaxAmount,proto3" json:"fbs_first_mile_max_amount,omitempty"`
|
||||
FbsFirstMileMinAmount float64 `protobuf:"fixed64,9,opt,name=fbs_first_mile_min_amount,json=fbsFirstMileMinAmount,proto3" json:"fbs_first_mile_min_amount,omitempty"`
|
||||
FbsReturnFlowAmount float64 `protobuf:"fixed64,10,opt,name=fbs_return_flow_amount,json=fbsReturnFlowAmount,proto3" json:"fbs_return_flow_amount,omitempty"`
|
||||
SalesPercentFbo float64 `protobuf:"fixed64,11,opt,name=sales_percent_fbo,json=salesPercentFbo,proto3" json:"sales_percent_fbo,omitempty"`
|
||||
SalesPercentFbs float64 `protobuf:"fixed64,12,opt,name=sales_percent_fbs,json=salesPercentFbs,proto3" json:"sales_percent_fbs,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) Reset() {
|
||||
*x = ProductPrice_Commissions{}
|
||||
mi := &file_ozon_products_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProductPrice_Commissions) ProtoMessage() {}
|
||||
|
||||
func (x *ProductPrice_Commissions) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ozon_products_proto_msgTypes[9]
|
||||
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 ProductPrice_Commissions.ProtoReflect.Descriptor instead.
|
||||
func (*ProductPrice_Commissions) Descriptor() ([]byte, []int) {
|
||||
return file_ozon_products_proto_rawDescGZIP(), []int{5, 0}
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFboDelivToCustomerAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FboDelivToCustomerAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFboDirectFlowTransMaxAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FboDirectFlowTransMaxAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFboDirectFlowTransMinAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FboDirectFlowTransMinAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFboReturnFlowAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FboReturnFlowAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFbsDelivToCustomerAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FbsDelivToCustomerAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFbsDirectFlowTransMaxAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FbsDirectFlowTransMaxAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFbsDirectFlowTransMinAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FbsDirectFlowTransMinAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFbsFirstMileMaxAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FbsFirstMileMaxAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFbsFirstMileMinAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FbsFirstMileMinAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetFbsReturnFlowAmount() float64 {
|
||||
if x != nil {
|
||||
return x.FbsReturnFlowAmount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetSalesPercentFbo() float64 {
|
||||
if x != nil {
|
||||
return x.SalesPercentFbo
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProductPrice_Commissions) GetSalesPercentFbs() float64 {
|
||||
if x != nil {
|
||||
return x.SalesPercentFbs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_ozon_products_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_ozon_products_proto_rawDesc = "" +
|
||||
@@ -358,7 +646,11 @@ const file_ozon_products_proto_rawDesc = "" +
|
||||
"\x18GetListOfProductsRequest\x12%\n" +
|
||||
"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"O\n" +
|
||||
"\x19GetListOfProductsResponse\x122\n" +
|
||||
"\bproducts\x18\x01 \x03(\v2\x16.ozon.products.ProductR\bproducts\"\xb3\x03\n" +
|
||||
"\bproducts\x18\x01 \x03(\v2\x16.ozon.products.ProductR\bproducts\"?\n" +
|
||||
"\x16GetProductPriceRequest\x12%\n" +
|
||||
"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"]\n" +
|
||||
"\x17GetProductPriceResponse\x12B\n" +
|
||||
"\x0eproduct_prices\x18\x01 \x03(\v2\x1b.ozon.products.ProductPriceR\rproductPrices\"\xb3\x03\n" +
|
||||
"\aProduct\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x19\n" +
|
||||
"\boffer_id\x18\x02 \x01(\tR\aofferId\x125\n" +
|
||||
@@ -375,9 +667,30 @@ const file_ozon_products_proto_rawDesc = "" +
|
||||
"\apresent\x18\x01 \x01(\x03R\apresent\x12\x1a\n" +
|
||||
"\breserved\x18\x02 \x01(\x03R\breserved\x12\x10\n" +
|
||||
"\x03SKU\x18\x03 \x01(\x03R\x03SKU\x12\x16\n" +
|
||||
"\x06source\x18\x04 \x01(\tR\x06source2{\n" +
|
||||
"\x06source\x18\x04 \x01(\tR\x06source\"\x93\a\n" +
|
||||
"\fProductPrice\x12\x1c\n" +
|
||||
"\tacquiring\x18\x01 \x01(\rR\tacquiring\x12I\n" +
|
||||
"\vcommissions\x18\x02 \x01(\v2'.ozon.products.ProductPrice.CommissionsR\vcommissions\x12\x19\n" +
|
||||
"\boffer_id\x18\x04 \x01(\tR\aofferId\x12\x1d\n" +
|
||||
"\n" +
|
||||
"product_id\x18\a \x01(\rR\tproductId\x1a\xdf\x05\n" +
|
||||
"\vCommissions\x12>\n" +
|
||||
"\x1cfbo_deliv_to_customer_amount\x18\x01 \x01(\x01R\x18fboDelivToCustomerAmount\x12E\n" +
|
||||
" fbo_direct_flow_trans_max_amount\x18\x02 \x01(\x01R\x1bfboDirectFlowTransMaxAmount\x12E\n" +
|
||||
" fbo_direct_flow_trans_min_amount\x18\x03 \x01(\x01R\x1bfboDirectFlowTransMinAmount\x123\n" +
|
||||
"\x16fbo_return_flow_amount\x18\x04 \x01(\x01R\x13fboReturnFlowAmount\x12>\n" +
|
||||
"\x1cfbs_deliv_to_customer_amount\x18\x05 \x01(\x01R\x18fbsDelivToCustomerAmount\x12E\n" +
|
||||
" fbs_direct_flow_trans_max_amount\x18\x06 \x01(\x01R\x1bfbsDirectFlowTransMaxAmount\x12E\n" +
|
||||
" fbs_direct_flow_trans_min_amount\x18\a \x01(\x01R\x1bfbsDirectFlowTransMinAmount\x128\n" +
|
||||
"\x19fbs_first_mile_max_amount\x18\b \x01(\x01R\x15fbsFirstMileMaxAmount\x128\n" +
|
||||
"\x19fbs_first_mile_min_amount\x18\t \x01(\x01R\x15fbsFirstMileMinAmount\x123\n" +
|
||||
"\x16fbs_return_flow_amount\x18\n" +
|
||||
" \x01(\x01R\x13fbsReturnFlowAmount\x12*\n" +
|
||||
"\x11sales_percent_fbo\x18\v \x01(\x01R\x0fsalesPercentFbo\x12*\n" +
|
||||
"\x11sales_percent_fbs\x18\f \x01(\x01R\x0fsalesPercentFbs2\xdf\x01\n" +
|
||||
"\x0fProductsService\x12h\n" +
|
||||
"\x11GetListOfProducts\x12'.ozon.products.GetListOfProductsRequest\x1a(.ozon.products.GetListOfProductsResponse0\x01B\x11Z\x0f./ozon/productsb\x06proto3"
|
||||
"\x11GetListOfProducts\x12'.ozon.products.GetListOfProductsRequest\x1a(.ozon.products.GetListOfProductsResponse0\x01\x12b\n" +
|
||||
"\x0fGetProductPrice\x12%.ozon.products.GetProductPriceRequest\x1a&.ozon.products.GetProductPriceResponse0\x01B\x11Z\x0f./ozon/productsb\x06proto3"
|
||||
|
||||
var (
|
||||
file_ozon_products_proto_rawDescOnce sync.Once
|
||||
@@ -391,27 +704,35 @@ func file_ozon_products_proto_rawDescGZIP() []byte {
|
||||
return file_ozon_products_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_ozon_products_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_ozon_products_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_ozon_products_proto_goTypes = []any{
|
||||
(*GetListOfProductsRequest)(nil), // 0: ozon.products.GetListOfProductsRequest
|
||||
(*GetListOfProductsResponse)(nil), // 1: ozon.products.GetListOfProductsResponse
|
||||
(*Product)(nil), // 2: ozon.products.Product
|
||||
(*Product_Status)(nil), // 3: ozon.products.Product.Status
|
||||
(*Product_Stocks)(nil), // 4: ozon.products.Product.Stocks
|
||||
(*Product_Stock)(nil), // 5: ozon.products.Product.Stock
|
||||
(*GetProductPriceRequest)(nil), // 2: ozon.products.GetProductPriceRequest
|
||||
(*GetProductPriceResponse)(nil), // 3: ozon.products.GetProductPriceResponse
|
||||
(*Product)(nil), // 4: ozon.products.Product
|
||||
(*ProductPrice)(nil), // 5: ozon.products.ProductPrice
|
||||
(*Product_Status)(nil), // 6: ozon.products.Product.Status
|
||||
(*Product_Stocks)(nil), // 7: ozon.products.Product.Stocks
|
||||
(*Product_Stock)(nil), // 8: ozon.products.Product.Stock
|
||||
(*ProductPrice_Commissions)(nil), // 9: ozon.products.ProductPrice.Commissions
|
||||
}
|
||||
var file_ozon_products_proto_depIdxs = []int32{
|
||||
2, // 0: ozon.products.GetListOfProductsResponse.products:type_name -> ozon.products.Product
|
||||
4, // 1: ozon.products.Product.stocks:type_name -> ozon.products.Product.Stocks
|
||||
3, // 2: ozon.products.Product.statuses:type_name -> ozon.products.Product.Status
|
||||
5, // 3: ozon.products.Product.Stocks.stocks:type_name -> ozon.products.Product.Stock
|
||||
0, // 4: ozon.products.ProductsService.GetListOfProducts:input_type -> ozon.products.GetListOfProductsRequest
|
||||
1, // 5: ozon.products.ProductsService.GetListOfProducts:output_type -> ozon.products.GetListOfProductsResponse
|
||||
5, // [5:6] is the sub-list for method output_type
|
||||
4, // [4:5] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
4, // 0: ozon.products.GetListOfProductsResponse.products:type_name -> ozon.products.Product
|
||||
5, // 1: ozon.products.GetProductPriceResponse.product_prices:type_name -> ozon.products.ProductPrice
|
||||
7, // 2: ozon.products.Product.stocks:type_name -> ozon.products.Product.Stocks
|
||||
6, // 3: ozon.products.Product.statuses:type_name -> ozon.products.Product.Status
|
||||
9, // 4: ozon.products.ProductPrice.commissions:type_name -> ozon.products.ProductPrice.Commissions
|
||||
8, // 5: ozon.products.Product.Stocks.stocks:type_name -> ozon.products.Product.Stock
|
||||
0, // 6: ozon.products.ProductsService.GetListOfProducts:input_type -> ozon.products.GetListOfProductsRequest
|
||||
2, // 7: ozon.products.ProductsService.GetProductPrice:input_type -> ozon.products.GetProductPriceRequest
|
||||
1, // 8: ozon.products.ProductsService.GetListOfProducts:output_type -> ozon.products.GetListOfProductsResponse
|
||||
3, // 9: ozon.products.ProductsService.GetProductPrice:output_type -> ozon.products.GetProductPriceResponse
|
||||
8, // [8:10] is the sub-list for method output_type
|
||||
6, // [6:8] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_ozon_products_proto_init() }
|
||||
@@ -425,7 +746,7 @@ func file_ozon_products_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ozon_products_proto_rawDesc), len(file_ozon_products_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v6.31.0
|
||||
// - protoc v6.31.1
|
||||
// source: ozon/products.proto
|
||||
|
||||
package products
|
||||
@@ -20,6 +20,7 @@ const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
ProductsService_GetListOfProducts_FullMethodName = "/ozon.products.ProductsService/GetListOfProducts"
|
||||
ProductsService_GetProductPrice_FullMethodName = "/ozon.products.ProductsService/GetProductPrice"
|
||||
)
|
||||
|
||||
// ProductsServiceClient is the client API for ProductsService service.
|
||||
@@ -28,6 +29,7 @@ const (
|
||||
type ProductsServiceClient interface {
|
||||
// Retrieves a list of products based on the provided request.
|
||||
GetListOfProducts(ctx context.Context, in *GetListOfProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetListOfProductsResponse], error)
|
||||
GetProductPrice(ctx context.Context, in *GetProductPriceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductPriceResponse], error)
|
||||
}
|
||||
|
||||
type productsServiceClient struct {
|
||||
@@ -57,12 +59,32 @@ func (c *productsServiceClient) GetListOfProducts(ctx context.Context, in *GetLi
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type ProductsService_GetListOfProductsClient = grpc.ServerStreamingClient[GetListOfProductsResponse]
|
||||
|
||||
func (c *productsServiceClient) GetProductPrice(ctx context.Context, in *GetProductPriceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductPriceResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &ProductsService_ServiceDesc.Streams[1], ProductsService_GetProductPrice_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[GetProductPriceRequest, GetProductPriceResponse]{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 ProductsService_GetProductPriceClient = grpc.ServerStreamingClient[GetProductPriceResponse]
|
||||
|
||||
// ProductsServiceServer is the server API for ProductsService service.
|
||||
// All implementations must embed UnimplementedProductsServiceServer
|
||||
// for forward compatibility.
|
||||
type ProductsServiceServer interface {
|
||||
// Retrieves a list of products based on the provided request.
|
||||
GetListOfProducts(*GetListOfProductsRequest, grpc.ServerStreamingServer[GetListOfProductsResponse]) error
|
||||
GetProductPrice(*GetProductPriceRequest, grpc.ServerStreamingServer[GetProductPriceResponse]) error
|
||||
mustEmbedUnimplementedProductsServiceServer()
|
||||
}
|
||||
|
||||
@@ -76,6 +98,9 @@ type UnimplementedProductsServiceServer struct{}
|
||||
func (UnimplementedProductsServiceServer) GetListOfProducts(*GetListOfProductsRequest, grpc.ServerStreamingServer[GetListOfProductsResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetListOfProducts not implemented")
|
||||
}
|
||||
func (UnimplementedProductsServiceServer) GetProductPrice(*GetProductPriceRequest, grpc.ServerStreamingServer[GetProductPriceResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetProductPrice not implemented")
|
||||
}
|
||||
func (UnimplementedProductsServiceServer) mustEmbedUnimplementedProductsServiceServer() {}
|
||||
func (UnimplementedProductsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@@ -108,6 +133,17 @@ func _ProductsService_GetListOfProducts_Handler(srv interface{}, stream grpc.Ser
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type ProductsService_GetListOfProductsServer = grpc.ServerStreamingServer[GetListOfProductsResponse]
|
||||
|
||||
func _ProductsService_GetProductPrice_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(GetProductPriceRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(ProductsServiceServer).GetProductPrice(m, &grpc.GenericServerStream[GetProductPriceRequest, GetProductPriceResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type ProductsService_GetProductPriceServer = grpc.ServerStreamingServer[GetProductPriceResponse]
|
||||
|
||||
// ProductsService_ServiceDesc is the grpc.ServiceDesc for ProductsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -121,6 +157,11 @@ var ProductsService_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _ProductsService_GetListOfProducts_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "GetProductPrice",
|
||||
Handler: _ProductsService_GetProductPrice_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "ozon/products.proto",
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.6
|
||||
// protoc v6.31.0
|
||||
// protoc v6.31.1
|
||||
// source: wb/products.proto
|
||||
|
||||
package products
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
@@ -20,20 +21,255 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GetProductsRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
MarketplaceId int64 `protobuf:"varint,1,opt,name=marketplace_id,json=marketplaceId,proto3" json:"marketplace_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetProductsRequest) Reset() {
|
||||
*x = GetProductsRequest{}
|
||||
mi := &file_wb_products_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetProductsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetProductsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetProductsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_wb_products_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 GetProductsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetProductsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_wb_products_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *GetProductsRequest) GetMarketplaceId() int64 {
|
||||
if x != nil {
|
||||
return x.MarketplaceId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Product struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
NmID int64 `protobuf:"varint,1,opt,name=nmID,proto3" json:"nmID,omitempty"`
|
||||
SubjectID int64 `protobuf:"varint,2,opt,name=subjectID,proto3" json:"subjectID,omitempty"`
|
||||
VendorCode string `protobuf:"bytes,3,opt,name=vendor_code,json=vendorCode,proto3" json:"vendor_code,omitempty"`
|
||||
Sizes []*Product_Size `protobuf:"bytes,4,rep,name=sizes,proto3" json:"sizes,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Product) Reset() {
|
||||
*x = Product{}
|
||||
mi := &file_wb_products_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Product) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Product) ProtoMessage() {}
|
||||
|
||||
func (x *Product) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_wb_products_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 Product.ProtoReflect.Descriptor instead.
|
||||
func (*Product) Descriptor() ([]byte, []int) {
|
||||
return file_wb_products_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Product) GetNmID() int64 {
|
||||
if x != nil {
|
||||
return x.NmID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Product) GetSubjectID() int64 {
|
||||
if x != nil {
|
||||
return x.SubjectID
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Product) GetVendorCode() string {
|
||||
if x != nil {
|
||||
return x.VendorCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Product) GetSizes() []*Product_Size {
|
||||
if x != nil {
|
||||
return x.Sizes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetProductsResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Products []*Product `protobuf:"bytes,1,rep,name=products,proto3" json:"products,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetProductsResponse) Reset() {
|
||||
*x = GetProductsResponse{}
|
||||
mi := &file_wb_products_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetProductsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetProductsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetProductsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_wb_products_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 GetProductsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetProductsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_wb_products_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *GetProductsResponse) GetProducts() []*Product {
|
||||
if x != nil {
|
||||
return x.Products
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Product_Size struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Skus []string `protobuf:"bytes,1,rep,name=skus,proto3" json:"skus,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Product_Size) Reset() {
|
||||
*x = Product_Size{}
|
||||
mi := &file_wb_products_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Product_Size) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Product_Size) ProtoMessage() {}
|
||||
|
||||
func (x *Product_Size) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_wb_products_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 Product_Size.ProtoReflect.Descriptor instead.
|
||||
func (*Product_Size) Descriptor() ([]byte, []int) {
|
||||
return file_wb_products_proto_rawDescGZIP(), []int{1, 0}
|
||||
}
|
||||
|
||||
func (x *Product_Size) GetSkus() []string {
|
||||
if x != nil {
|
||||
return x.Skus
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_wb_products_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_wb_products_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x11wb/products.proto\x12\vwb.products2\x11\n" +
|
||||
"\x0fProductsServiceB\x0fZ\r./wb/productsb\x06proto3"
|
||||
"\x11wb/products.proto\x12\vwb.products\";\n" +
|
||||
"\x12GetProductsRequest\x12%\n" +
|
||||
"\x0emarketplace_id\x18\x01 \x01(\x03R\rmarketplaceId\"\xa9\x01\n" +
|
||||
"\aProduct\x12\x12\n" +
|
||||
"\x04nmID\x18\x01 \x01(\x03R\x04nmID\x12\x1c\n" +
|
||||
"\tsubjectID\x18\x02 \x01(\x03R\tsubjectID\x12\x1f\n" +
|
||||
"\vvendor_code\x18\x03 \x01(\tR\n" +
|
||||
"vendorCode\x12/\n" +
|
||||
"\x05sizes\x18\x04 \x03(\v2\x19.wb.products.Product.SizeR\x05sizes\x1a\x1a\n" +
|
||||
"\x04Size\x12\x12\n" +
|
||||
"\x04skus\x18\x01 \x03(\tR\x04skus\"G\n" +
|
||||
"\x13GetProductsResponse\x120\n" +
|
||||
"\bproducts\x18\x01 \x03(\v2\x14.wb.products.ProductR\bproducts2e\n" +
|
||||
"\x0fProductsService\x12R\n" +
|
||||
"\vGetProducts\x12\x1f.wb.products.GetProductsRequest\x1a .wb.products.GetProductsResponse0\x01B\x0fZ\r./wb/productsb\x06proto3"
|
||||
|
||||
var file_wb_products_proto_goTypes = []any{}
|
||||
var (
|
||||
file_wb_products_proto_rawDescOnce sync.Once
|
||||
file_wb_products_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_wb_products_proto_rawDescGZIP() []byte {
|
||||
file_wb_products_proto_rawDescOnce.Do(func() {
|
||||
file_wb_products_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_wb_products_proto_rawDesc), len(file_wb_products_proto_rawDesc)))
|
||||
})
|
||||
return file_wb_products_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_wb_products_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_wb_products_proto_goTypes = []any{
|
||||
(*GetProductsRequest)(nil), // 0: wb.products.GetProductsRequest
|
||||
(*Product)(nil), // 1: wb.products.Product
|
||||
(*GetProductsResponse)(nil), // 2: wb.products.GetProductsResponse
|
||||
(*Product_Size)(nil), // 3: wb.products.Product.Size
|
||||
}
|
||||
var file_wb_products_proto_depIdxs = []int32{
|
||||
0, // [0:0] is the sub-list for method output_type
|
||||
0, // [0:0] 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
|
||||
3, // 0: wb.products.Product.sizes:type_name -> wb.products.Product.Size
|
||||
1, // 1: wb.products.GetProductsResponse.products:type_name -> wb.products.Product
|
||||
0, // 2: wb.products.ProductsService.GetProducts:input_type -> wb.products.GetProductsRequest
|
||||
2, // 3: wb.products.ProductsService.GetProducts:output_type -> wb.products.GetProductsResponse
|
||||
3, // [3:4] is the sub-list for method output_type
|
||||
2, // [2:3] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_wb_products_proto_init() }
|
||||
@@ -47,12 +283,13 @@ func file_wb_products_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_wb_products_proto_rawDesc), len(file_wb_products_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_wb_products_proto_goTypes,
|
||||
DependencyIndexes: file_wb_products_proto_depIdxs,
|
||||
MessageInfos: file_wb_products_proto_msgTypes,
|
||||
}.Build()
|
||||
File_wb_products_proto = out.File
|
||||
file_wb_products_proto_goTypes = nil
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v6.31.0
|
||||
// - protoc v6.31.1
|
||||
// source: wb/products.proto
|
||||
|
||||
package products
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
@@ -15,10 +18,15 @@ import (
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
ProductsService_GetProducts_FullMethodName = "/wb.products.ProductsService/GetProducts"
|
||||
)
|
||||
|
||||
// ProductsServiceClient is the client API for ProductsService 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 ProductsServiceClient interface {
|
||||
GetProducts(ctx context.Context, in *GetProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductsResponse], error)
|
||||
}
|
||||
|
||||
type productsServiceClient struct {
|
||||
@@ -29,10 +37,30 @@ func NewProductsServiceClient(cc grpc.ClientConnInterface) ProductsServiceClient
|
||||
return &productsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *productsServiceClient) GetProducts(ctx context.Context, in *GetProductsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[GetProductsResponse], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &ProductsService_ServiceDesc.Streams[0], ProductsService_GetProducts_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[GetProductsRequest, GetProductsResponse]{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 ProductsService_GetProductsClient = grpc.ServerStreamingClient[GetProductsResponse]
|
||||
|
||||
// ProductsServiceServer is the server API for ProductsService service.
|
||||
// All implementations must embed UnimplementedProductsServiceServer
|
||||
// for forward compatibility.
|
||||
type ProductsServiceServer interface {
|
||||
GetProducts(*GetProductsRequest, grpc.ServerStreamingServer[GetProductsResponse]) error
|
||||
mustEmbedUnimplementedProductsServiceServer()
|
||||
}
|
||||
|
||||
@@ -43,6 +71,9 @@ type ProductsServiceServer interface {
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedProductsServiceServer struct{}
|
||||
|
||||
func (UnimplementedProductsServiceServer) GetProducts(*GetProductsRequest, grpc.ServerStreamingServer[GetProductsResponse]) error {
|
||||
return status.Errorf(codes.Unimplemented, "method GetProducts not implemented")
|
||||
}
|
||||
func (UnimplementedProductsServiceServer) mustEmbedUnimplementedProductsServiceServer() {}
|
||||
func (UnimplementedProductsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@@ -64,6 +95,17 @@ func RegisterProductsServiceServer(s grpc.ServiceRegistrar, srv ProductsServiceS
|
||||
s.RegisterService(&ProductsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ProductsService_GetProducts_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(GetProductsRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(ProductsServiceServer).GetProducts(m, &grpc.GenericServerStream[GetProductsRequest, GetProductsResponse]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type ProductsService_GetProductsServer = grpc.ServerStreamingServer[GetProductsResponse]
|
||||
|
||||
// ProductsService_ServiceDesc is the grpc.ServiceDesc for ProductsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -71,6 +113,12 @@ var ProductsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "wb.products.ProductsService",
|
||||
HandlerType: (*ProductsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "wb/products.proto",
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "GetProducts",
|
||||
Handler: _ProductsService_GetProducts_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "wb/products.proto",
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.6
|
||||
// protoc v6.31.0
|
||||
// protoc v6.31.1
|
||||
// source: yandexmarket/products.proto
|
||||
|
||||
package products
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v6.31.0
|
||||
// - protoc v6.31.1
|
||||
// source: yandexmarket/products.proto
|
||||
|
||||
package products
|
||||
|
||||
Submodule api/proto/v1 updated: c6df89a7a3...2c4ca98d2d
@@ -8,9 +8,12 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"net"
|
||||
"os"
|
||||
"sipro-mps/internal/config"
|
||||
"sipro-mps/internal/marketplace"
|
||||
ozon "sipro-mps/internal/ozon/products"
|
||||
"sipro-mps/internal/redis"
|
||||
"sipro-mps/internal/tasks/client"
|
||||
wb "sipro-mps/internal/wb/products"
|
||||
)
|
||||
|
||||
func logMessage(level string, format string, a ...interface{}) {
|
||||
@@ -50,7 +53,11 @@ func createGrpcServer(pool *pgxpool.Pool) {
|
||||
fmt.Printf("failed to register Ozon Products gRPC server: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = wb.RegisterAdapterGRPC(grpcServer, *repo)
|
||||
if err != nil {
|
||||
fmt.Printf("failed to register Wildberries Products gRPC server: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("gRPC server registered successfully.")
|
||||
// Start serving gRPC requests
|
||||
fmt.Println("gRPC server is starting on port 8080...")
|
||||
@@ -61,26 +68,64 @@ func createGrpcServer(pool *pgxpool.Pool) {
|
||||
fmt.Println("gRPC server created.")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initializing the dotenv file
|
||||
func initDotenv() error {
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
logMessage("error", "Error loading .env file: %v", err)
|
||||
return
|
||||
return fmt.Errorf("error loading .env file: %w", err)
|
||||
}
|
||||
logMessage("info", "Dotenv file loaded successfully. 🌱")
|
||||
return nil
|
||||
}
|
||||
|
||||
func initRedisClient(ctx context.Context) error {
|
||||
err := redis.InitClient(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error initializing Redis client: %w", err)
|
||||
}
|
||||
//defer redis.CloseClient()
|
||||
logMessage("info", "Redis client initialized successfully. 🟥")
|
||||
return nil
|
||||
}
|
||||
func initRedisLocker() error {
|
||||
err := redis.InitLocker()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error initializing Redis locker: %w", err)
|
||||
}
|
||||
logMessage("info", "Redis locker initialized successfully. 🟥")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := initDotenv()
|
||||
if err != nil {
|
||||
logMessage("error", "Failed to load .env file: %v", err)
|
||||
return
|
||||
}
|
||||
logMessage("info", "Starting the SIPRO Marketplace Server... 🚀1")
|
||||
ctx := context.Background()
|
||||
|
||||
// Initializing the Redis client
|
||||
err = redis.InitClient(ctx)
|
||||
err = initRedisClient(ctx)
|
||||
if err != nil {
|
||||
logMessage("error", "Failed to initialize Redis client: %v", err)
|
||||
return
|
||||
}
|
||||
defer redis.CloseClient()
|
||||
logMessage("info", "Redis client initialized successfully. 🟥")
|
||||
|
||||
// Initializing the Redis locker
|
||||
err = initRedisLocker()
|
||||
if err != nil {
|
||||
logMessage("error", "Failed to initialize Redis locker: %v", err)
|
||||
return
|
||||
}
|
||||
defer redis.CloseLocker()
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
logMessage("error", "Failed to load configuration: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
client.InitClient(*cfg.Redis)
|
||||
// Initializing pgx connection
|
||||
dbpool, err := pgxpool.New(ctx, os.Getenv("POSTGRES_URL"))
|
||||
if err != nil {
|
||||
@@ -88,11 +133,6 @@ func main() {
|
||||
return
|
||||
}
|
||||
defer dbpool.Close()
|
||||
logMessage("info", "Connected to PostgreSQL successfully. 🐘")
|
||||
|
||||
createGrpcServer(dbpool)
|
||||
|
||||
}
|
||||
|
||||
//for _, item := range items {
|
||||
// //logMessage("info", "Product ID: %s, Name: %s, Price: %d", item.Price, item.Name, item.Price)
|
||||
//}
|
||||
|
||||
34
cmd/tasks_server/main.go
Normal file
34
cmd/tasks_server/main.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"sipro-mps/internal/config"
|
||||
"sipro-mps/internal/redis"
|
||||
"sipro-mps/internal/tasks/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
err = redis.InitClient(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer redis.CloseClient()
|
||||
err = redis.InitLocker()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer redis.CloseLocker()
|
||||
dbpool, err := pgxpool.New(ctx, cfg.Database.URL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
srv := server.NewAsynqServer(cfg.Redis, dbpool)
|
||||
srv.Run()
|
||||
}
|
||||
51
cmd/test/main.go
Normal file
51
cmd/test/main.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/redis/rueidis"
|
||||
"sipro-mps/internal/config"
|
||||
"sipro-mps/internal/redis"
|
||||
"sipro-mps/internal/tasks"
|
||||
)
|
||||
|
||||
func main() {
|
||||
godotenv.Load()
|
||||
ctx := context.Background()
|
||||
|
||||
redis.InitClient(ctx)
|
||||
c := *redis.Client
|
||||
key := fmt.Sprintf("wb:products:%d", "test")
|
||||
v, err := c.Do(ctx, c.B().Get().Key(key).Build()).ToString()
|
||||
if err != nil {
|
||||
if errors.As(err, &rueidis.Nil) {
|
||||
fmt.Println("Key does not exist in Redis:", key)
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Println("Value from Redis:", v)
|
||||
return
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
client := asynq.NewClient(asynq.RedisClientOpt{Addr: cfg.Redis.Host + ":" + cfg.Redis.Port, Password: cfg.Redis.Password})
|
||||
defer func(client *asynq.Client) {
|
||||
err := client.Close()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}(client)
|
||||
task, err := tasks.NewFetchProductsTask(1130)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
info, err := client.Enqueue(task)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println("Task enqueued successfully:", info.ID, "with queue name:", info.Queue, "and payload size:", len(info.Payload), "bytes")
|
||||
}
|
||||
15
docker-compose.yml
Normal file
15
docker-compose.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
version: '3.8'
|
||||
services:
|
||||
app:
|
||||
image: git.denco.store/fakz9/sipro-marketplaces:latest
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- appnet
|
||||
redis:
|
||||
image: redis
|
||||
networks:
|
||||
- appnet
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
39
go.mod
39
go.mod
@@ -4,24 +4,55 @@ go 1.24
|
||||
|
||||
require (
|
||||
git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505
|
||||
github.com/go-faster/errors v0.7.1
|
||||
github.com/go-faster/jx v1.1.0
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hibiken/asynq v0.25.1
|
||||
github.com/jackc/pgx/v5 v5.7.5
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/ogen-go/ogen v1.14.0
|
||||
github.com/redis/rueidis v1.0.60
|
||||
github.com/samber/lo v1.50.0
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
go.opentelemetry.io/otel v1.36.0
|
||||
go.opentelemetry.io/otel/metric v1.36.0
|
||||
go.opentelemetry.io/otel/trace v1.36.0
|
||||
google.golang.org/grpc v1.72.2
|
||||
google.golang.org/protobuf v1.36.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-faster/yaml v0.4.6 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/redis/go-redis/v9 v9.7.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
104
go.sum
104
go.sum
@@ -1,18 +1,45 @@
|
||||
git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505 h1:5mviYMLXLIvsFEXLR0IlGuqMNzkB8X/yrmxZHYk0n84=
|
||||
git.denco.store/fakz9/ozon-api-client v1.18.1-0.20250526003754-c6c303092505/go.mod h1:1uPm278HN7mDkP507KHsLpnW+R9vWGEzp9BSMycjVbQ=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
|
||||
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
|
||||
github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg=
|
||||
github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg=
|
||||
github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I=
|
||||
github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw=
|
||||
github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
@@ -23,16 +50,37 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ogen-go/ogen v1.14.0 h1:TU1Nj4z9UBsAfTkf+IhuNNp7igdFQKqkk9+6/y4XuWg=
|
||||
github.com/ogen-go/ogen v1.14.0/go.mod h1:Iw1vkqkx6SU7I9th5ceP+fVPJ6Wge4e3kAVzAxJEpPE=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||
github.com/redis/rueidis v1.0.60 h1:MGZX8uNdw7iyWz22JhjA/9iXzddfCUE/EMK4VxKoKpA=
|
||||
github.com/redis/rueidis v1.0.60/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/samber/lo v1.50.0 h1:XrG0xOeHs+4FQ8gJR97zDz5uOFMW7OwFWiFVzqopKgY=
|
||||
github.com/samber/lo v1.50.0/go.mod h1:RjZyNk6WSnUFRKK6EyOhsRJMqft3G+pg7dCWHQCWvsc=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -47,26 +95,38 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY=
|
||||
golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
|
||||
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
|
||||
@@ -74,6 +134,10 @@ google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3i
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package config
|
||||
|
||||
import "github.com/joho/godotenv"
|
||||
|
||||
type Config struct {
|
||||
DB string
|
||||
HTTP string
|
||||
GRPC string
|
||||
Kafka string
|
||||
Redis *RedisConfig
|
||||
Database *DatabaseConfig
|
||||
}
|
||||
|
||||
func Load() Config {
|
||||
return Config{
|
||||
DB: "dbname=test password=GjitkYf[eq user=postgres sslmode=disable",
|
||||
HTTP: ":8080",
|
||||
GRPC: ":50051",
|
||||
Kafka: "localhost:9092",
|
||||
func LoadConfig() (*Config, error) {
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
redisConfig := LoadRedisConfig()
|
||||
databaseConfig := LoadDatabaseConfig()
|
||||
return &Config{Redis: redisConfig, Database: databaseConfig}, nil
|
||||
}
|
||||
|
||||
23
internal/config/database.go
Normal file
23
internal/config/database.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package config
|
||||
|
||||
import "os"
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Host string
|
||||
Port string
|
||||
Login string
|
||||
Password string
|
||||
Database string
|
||||
URL string
|
||||
}
|
||||
|
||||
func LoadDatabaseConfig() *DatabaseConfig {
|
||||
return &DatabaseConfig{
|
||||
Host: os.Getenv("POSTGRES_HOST"),
|
||||
Port: os.Getenv("POSTGRES_PORT"),
|
||||
Login: os.Getenv("POSTGRES_LOGIN"),
|
||||
Password: os.Getenv("POSTGRES_PASSWORD"),
|
||||
Database: os.Getenv("POSTGRES_DATABASE"),
|
||||
URL: os.Getenv("POSTGRES_URL"),
|
||||
}
|
||||
}
|
||||
23
internal/config/redis.go
Normal file
23
internal/config/redis.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package config
|
||||
|
||||
import "os"
|
||||
|
||||
type RedisConfig struct {
|
||||
Host string
|
||||
Port string
|
||||
Password string
|
||||
Addr string
|
||||
}
|
||||
|
||||
func LoadRedisConfig() *RedisConfig {
|
||||
host := os.Getenv("REDIS_HOST")
|
||||
port := os.Getenv("REDIS_PORT")
|
||||
password := os.Getenv("REDIS_PASSWORD")
|
||||
addr := os.Getenv("REDIS_ADDR")
|
||||
return &RedisConfig{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Password: password,
|
||||
Addr: addr,
|
||||
}
|
||||
}
|
||||
@@ -14,4 +14,5 @@ type Marketplace struct {
|
||||
Name string
|
||||
AuthData pgtype.Text
|
||||
WarehouseID pgtype.Text
|
||||
AuthDataJson []byte
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
const getMarketplaceByID = `-- name: GetMarketplaceByID :one
|
||||
SELECT id, base_marketplace, name, auth_data, warehouse_id FROM marketplaces
|
||||
SELECT id, base_marketplace, name, auth_data, warehouse_id, auth_data_json FROM marketplaces
|
||||
WHERE id = $1 LIMIT 1
|
||||
`
|
||||
|
||||
@@ -23,6 +23,7 @@ func (q *Queries) GetMarketplaceByID(ctx context.Context, id int32) (Marketplace
|
||||
&i.Name,
|
||||
&i.AuthData,
|
||||
&i.WarehouseID,
|
||||
&i.AuthDataJson,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
create table marketplaces
|
||||
(
|
||||
id serial
|
||||
id serial
|
||||
primary key,
|
||||
base_marketplace integer not null,
|
||||
name varchar not null,
|
||||
auth_data varchar,
|
||||
warehouse_id varchar
|
||||
base_marketplace integer not null,
|
||||
name varchar not null,
|
||||
auth_data varchar,
|
||||
warehouse_id varchar,
|
||||
auth_data_json jsonb generated always as (
|
||||
CASE
|
||||
WHEN ((auth_data)::text IS JSON) THEN (auth_data)::jsonb
|
||||
ELSE NULL::jsonb
|
||||
END) stored
|
||||
);
|
||||
@@ -5,4 +5,5 @@ type Marketplace struct {
|
||||
BaseMarketplace int `json:"base_marketplace"`
|
||||
AuthData string `json:"auth_data"`
|
||||
WarehouseID string `json:"warehouse_id"`
|
||||
AuthDataJson []byte `json:"auth_data_json,omitempty"`
|
||||
}
|
||||
|
||||
@@ -24,5 +24,6 @@ func (r *dbRepository) GetMarketplaceByID(ctx context.Context, id int) (*Marketp
|
||||
BaseMarketplace: int(marketplace.BaseMarketplace),
|
||||
AuthData: marketplace.AuthData.String,
|
||||
WarehouseID: marketplace.WarehouseID.String,
|
||||
AuthDataJson: marketplace.AuthDataJson,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
proto "sipro-mps/api/generated/v1/ozon/products"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/jmattheis/goverter/cmd/goverter gen -g 'ignoreUnexported yes' .
|
||||
//go:generate go run github.com/jmattheis/goverter/cmd/goverter gen -global "ignoreUnexported yes" .
|
||||
|
||||
// goverter:converter
|
||||
// goverter:extend Int632ToInt64
|
||||
|
||||
@@ -5,9 +5,8 @@ package generated
|
||||
|
||||
import (
|
||||
ozon "git.denco.store/fakz9/ozon-api-client/ozon"
|
||||
|
||||
products "sipro-mps/api/generated/v1/ozon/products"
|
||||
ozon "git.denco.store/fakz9/ozon-api-client/ozon"
|
||||
mapping "sipro-mps/internal/ozon/products/mapping"
|
||||
)
|
||||
|
||||
type ConverterImpl struct{}
|
||||
|
||||
@@ -85,7 +85,7 @@ func (a *apiRepository) GetAllProducts(ctx context.Context, marketplaceId int) (
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := []OzonProduct{}
|
||||
var items []OzonProduct
|
||||
productIdsChan := make(chan []int64)
|
||||
producsChan := make(chan []OzonProduct)
|
||||
errChan := make(chan error)
|
||||
|
||||
@@ -50,7 +50,7 @@ func (t *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, error
|
||||
waitTime, err := rateLimiterScript.Exec(ctx, *redis.Client, []string{clientId}, []string{
|
||||
fmt.Sprintf("%d", now),
|
||||
fmt.Sprintf("%d", int64(windowSize)),
|
||||
fmt.Sprintf("%d", 50),
|
||||
fmt.Sprintf("%d", rps),
|
||||
}).ToInt64()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute rate limit script: %w", err)
|
||||
|
||||
@@ -11,6 +11,7 @@ var Client *rueidis.Client
|
||||
func InitClient(ctx context.Context) error {
|
||||
var err error
|
||||
host := os.Getenv("REDIS_HOST")
|
||||
//host := "redis"
|
||||
port := os.Getenv("REDIS_PORT")
|
||||
password := os.Getenv("REDIS_PASSWORD")
|
||||
|
||||
|
||||
29
internal/redis/lock.go
Normal file
29
internal/redis/lock.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"github.com/redis/rueidis"
|
||||
"github.com/redis/rueidis/rueidislock"
|
||||
"os"
|
||||
)
|
||||
|
||||
var Locker *rueidislock.Locker
|
||||
|
||||
func InitLocker() error {
|
||||
redisAddr := os.Getenv("REDIS_ADDR")
|
||||
password := os.Getenv("REDIS_PASSWORD")
|
||||
locker, err := rueidislock.NewLocker(rueidislock.LockerOption{
|
||||
ClientOption: rueidis.ClientOption{InitAddress: []string{redisAddr}, Password: password},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Locker = &locker
|
||||
return nil
|
||||
}
|
||||
func CloseLocker() {
|
||||
if Locker != nil {
|
||||
(*Locker).Close()
|
||||
}
|
||||
Locker = nil
|
||||
|
||||
}
|
||||
25
internal/tasks/client/client.go
Normal file
25
internal/tasks/client/client.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/hibiken/asynq"
|
||||
"sipro-mps/internal/config"
|
||||
)
|
||||
|
||||
var Client *asynq.Client
|
||||
|
||||
// InitClient initializes the Asynq client with the provided Redis configuration.
|
||||
func InitClient(redisConfig config.RedisConfig) {
|
||||
client := asynq.NewClient(asynq.RedisClientOpt{
|
||||
Addr: redisConfig.Addr,
|
||||
Password: redisConfig.Password,
|
||||
})
|
||||
Client = client
|
||||
}
|
||||
|
||||
func CloseClient() {
|
||||
if Client != nil {
|
||||
if err := Client.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
39
internal/tasks/server/server.go
Normal file
39
internal/tasks/server/server.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"sipro-mps/internal/config"
|
||||
"sipro-mps/internal/tasks/types"
|
||||
"sipro-mps/internal/tasks/wb"
|
||||
)
|
||||
|
||||
type AsynqServer struct {
|
||||
redisConfig *config.RedisConfig
|
||||
dbpool *pgxpool.Pool
|
||||
}
|
||||
|
||||
func NewAsynqServer(redisConfig *config.RedisConfig, dbpool *pgxpool.Pool) *AsynqServer {
|
||||
return &AsynqServer{
|
||||
redisConfig: redisConfig,
|
||||
dbpool: dbpool,
|
||||
}
|
||||
}
|
||||
func (s *AsynqServer) createMux() *asynq.ServeMux {
|
||||
mux := asynq.NewServeMux()
|
||||
|
||||
// Register task handlers here
|
||||
mux.Handle(types.TypeWbFetchProducts, &wb.FetchProductsProcessor{Dbpool: s.dbpool})
|
||||
return mux
|
||||
}
|
||||
|
||||
func (s *AsynqServer) Run() {
|
||||
srv := asynq.NewServer(
|
||||
asynq.RedisClientOpt{Addr: s.redisConfig.Addr, Password: s.redisConfig.Password},
|
||||
asynq.Config{Concurrency: 10},
|
||||
)
|
||||
mux := s.createMux()
|
||||
if err := srv.Run(mux); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
5
internal/tasks/types/common.go
Normal file
5
internal/tasks/types/common.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package types
|
||||
|
||||
const (
|
||||
TypeWbFetchProducts = "wb:fetch_products"
|
||||
)
|
||||
19
internal/tasks/types/wb.go
Normal file
19
internal/tasks/types/wb.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/hibiken/asynq"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FetchProductsTask struct {
|
||||
MarketplaceId int
|
||||
}
|
||||
|
||||
func NewFetchProductsTask(marketplaceId int) (*asynq.Task, error) {
|
||||
payload, err := json.Marshal(&FetchProductsTask{MarketplaceId: marketplaceId})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asynq.NewTask(TypeWbFetchProducts, payload, asynq.MaxRetry(2), asynq.Timeout(20*time.Minute)), nil
|
||||
}
|
||||
65
internal/tasks/wb/wb.go
Normal file
65
internal/tasks/wb/wb.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package wb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/samber/lo"
|
||||
pb "sipro-mps/api/generated/v1/wb/products"
|
||||
mp_repo "sipro-mps/internal/marketplace"
|
||||
"sipro-mps/internal/redis"
|
||||
"sipro-mps/internal/tasks/types"
|
||||
wb_products_repo "sipro-mps/internal/wb/products"
|
||||
conv "sipro-mps/internal/wb/products/mapping/generated"
|
||||
)
|
||||
|
||||
type FetchProductsProcessor struct {
|
||||
Dbpool *pgxpool.Pool
|
||||
wbRepo wb_products_repo.Repository
|
||||
}
|
||||
|
||||
func (p *FetchProductsProcessor) ProcessTask(ctx context.Context, task *asynq.Task) error {
|
||||
var payload types.FetchProductsTask
|
||||
if err := json.Unmarshal(task.Payload(), &payload); err != nil {
|
||||
return asynq.SkipRetry
|
||||
}
|
||||
marketplaceRepo := mp_repo.NewDBRepository(p.Dbpool)
|
||||
repo := wb_products_repo.NewAPIRepository(marketplaceRepo)
|
||||
_, sellerId, err := repo.ParseMarketplace(ctx, payload.MarketplaceId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse marketplace %d: %w", payload.MarketplaceId, err)
|
||||
}
|
||||
locker := *redis.Locker
|
||||
_, cancel, err := locker.TryWithContext(ctx, fmt.Sprintf("wb:products:marketplace:%s:lock", sellerId))
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to acquire lock for marketplace %s: %v\n", sellerId, err)
|
||||
return asynq.SkipRetry
|
||||
|
||||
}
|
||||
fmt.Println("Working on marketplace", payload.MarketplaceId, "with seller ID", sellerId)
|
||||
|
||||
defer cancel()
|
||||
|
||||
redisKey := fmt.Sprintf("wb:products:%s", sellerId)
|
||||
productsRaw, err := repo.GetAllProducts(ctx, payload.MarketplaceId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch products for marketplace %d: %w", payload.MarketplaceId, err)
|
||||
}
|
||||
converter := conv.ConverterImpl{}
|
||||
products := lo.Map(productsRaw, func(item wb_products_repo.WbProduct, _ int) *pb.Product {
|
||||
return converter.ToProto(&item)
|
||||
})
|
||||
redisClient := *redis.Client
|
||||
productsJson, err := json.Marshal(products)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal products: %w", err)
|
||||
}
|
||||
err = redisClient.Do(ctx, redisClient.B().Set().Key(redisKey).Value(string(productsJson)).Build()).Error()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
59
internal/wb/common.go
Normal file
59
internal/wb/common.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package wb
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"net/http"
|
||||
"sipro-mps/internal/marketplace"
|
||||
wbclient "sipro-mps/pkg/api/wb/client"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WbAuthData struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func NewWbAuthData(token string) WbAuthData {
|
||||
return WbAuthData{
|
||||
Token: token,
|
||||
}
|
||||
}
|
||||
|
||||
func DecodeWildberriesJwt(token []byte) (WbAuthData, jwt.MapClaims, error) {
|
||||
var authData WbAuthData
|
||||
err := json.Unmarshal(token, &authData)
|
||||
if err != nil {
|
||||
return authData, nil, fmt.Errorf("failed to unmarshal JWT: %w", err)
|
||||
}
|
||||
claims := jwt.MapClaims{}
|
||||
_, _, err = jwt.NewParser().ParseUnverified(authData.Token, claims)
|
||||
if err != nil {
|
||||
return authData, nil, fmt.Errorf("invalid JWT: %w", err)
|
||||
}
|
||||
|
||||
return authData, claims, nil
|
||||
}
|
||||
|
||||
func GetClientFromMarketplace(mp *marketplace.Marketplace) (*wbclient.Client, error) {
|
||||
|
||||
authData, claims, err := DecodeWildberriesJwt(mp.AuthDataJson)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode Wildberries JWT")
|
||||
}
|
||||
exp := claims["exp"].(float64)
|
||||
// chec if token is expired, for now unix date
|
||||
now := float64(time.Now().Unix())
|
||||
if exp < now {
|
||||
return nil, fmt.Errorf("token is expired")
|
||||
}
|
||||
securityHandler := NewWildberriesSecurityHandler(authData.Token)
|
||||
httpClient := &http.Client{
|
||||
Transport: NewRateLimitTransport(),
|
||||
}
|
||||
client, err := wbclient.NewClient("https://content-api.wildberries.ru", securityHandler, wbclient.WithClient(httpClient))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create Wildberries client: %w", err)
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
63
internal/wb/products/adapter_grpc.go
Normal file
63
internal/wb/products/adapter_grpc.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/samber/lo"
|
||||
"google.golang.org/grpc"
|
||||
pb "sipro-mps/api/generated/v1/wb/products"
|
||||
"sipro-mps/internal/marketplace"
|
||||
)
|
||||
|
||||
type AdapterGRPC struct {
|
||||
pb.UnimplementedProductsServiceServer
|
||||
repo Repository
|
||||
}
|
||||
|
||||
func NewAdapterGRPC(repo Repository) *AdapterGRPC {
|
||||
return &AdapterGRPC{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterAdapterGRPC(server *grpc.Server, marketplacesRepository marketplace.Repository) (*Repository, error) {
|
||||
repo := NewAPIRepository(marketplacesRepository)
|
||||
adapter := NewAdapterGRPC(repo)
|
||||
pb.RegisterProductsServiceServer(server, adapter)
|
||||
return &repo, nil
|
||||
}
|
||||
func (a *AdapterGRPC) GetProducts(req *pb.GetProductsRequest, stream pb.ProductsService_GetProductsServer) error {
|
||||
ctx := stream.Context()
|
||||
resultChan := make(chan []pb.Product)
|
||||
errChan := make(chan error)
|
||||
go a.repo.StreamAllProductsCache(ctx, int(req.MarketplaceId), resultChan, errChan)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Println("context done")
|
||||
return ctx.Err()
|
||||
case products, ok := <-resultChan:
|
||||
if !ok {
|
||||
fmt.Println("result channel closed")
|
||||
return nil
|
||||
}
|
||||
resp := &pb.GetProductsResponse{
|
||||
Products: lo.Map(products, func(p pb.Product, _ int) *pb.Product {
|
||||
return &p
|
||||
}),
|
||||
}
|
||||
if err := stream.Send(resp); err != nil {
|
||||
fmt.Println("error sending response", err)
|
||||
return err
|
||||
}
|
||||
case err, ok := <-errChan:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if ok && err != nil {
|
||||
fmt.Println("error in channel", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
9
internal/wb/products/entities.go
Normal file
9
internal/wb/products/entities.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
pb "sipro-mps/api/generated/v1/wb/products"
|
||||
"sipro-mps/pkg/api/wb/client"
|
||||
)
|
||||
|
||||
type WbProduct = api.ContentV2GetCardsListPostOKCardsItem
|
||||
type PbProduct = pb.Product
|
||||
28
internal/wb/products/mapping/converter.go
Normal file
28
internal/wb/products/mapping/converter.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package mapping
|
||||
|
||||
import wbclient "sipro-mps/pkg/api/wb/client"
|
||||
|
||||
// import (
|
||||
//
|
||||
// proto "sipro-mps/api/generated/v1/wb/products"
|
||||
// internal "sipro-mps/internal/wb/products"
|
||||
// wbclient "sipro-mps/pkg/api/wb/client"
|
||||
//
|
||||
// )
|
||||
//
|
||||
// //go:generate go run github.com/jmattheis/goverter/cmd/goverter gen -global "ignoreUnexported yes" .
|
||||
//
|
||||
// // goverter:converter
|
||||
// // goverter:extend OptIntToInt64 OptStringToString
|
||||
//
|
||||
// type Converter interface {
|
||||
// // goverter:ignore state sizeCache unknownFields
|
||||
//
|
||||
// ToProto(details *internal.WbProduct) *proto.Product
|
||||
// }
|
||||
func OptIntToInt64(i wbclient.OptInt) int64 {
|
||||
return int64(i.Value)
|
||||
}
|
||||
func OptStringToString(s wbclient.OptString) string {
|
||||
return s.Value
|
||||
}
|
||||
40
internal/wb/products/mapping/generated/generated.go
Normal file
40
internal/wb/products/mapping/generated/generated.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Code generated by github.com/jmattheis/goverter, DO NOT EDIT.
|
||||
//go:build !goverter
|
||||
|
||||
package generated
|
||||
|
||||
import (
|
||||
products "sipro-mps/api/generated/v1/wb/products"
|
||||
mapping "sipro-mps/internal/wb/products/mapping"
|
||||
client "sipro-mps/pkg/api/wb/client"
|
||||
)
|
||||
|
||||
type ConverterImpl struct{}
|
||||
|
||||
func (c *ConverterImpl) ToProto(source *client.ContentV2GetCardsListPostOKCardsItem) *products.Product {
|
||||
var pProductsProduct *products.Product
|
||||
if source != nil {
|
||||
var productsProduct products.Product
|
||||
productsProduct.NmID = mapping.OptIntToInt64((*source).NmID)
|
||||
productsProduct.SubjectID = mapping.OptIntToInt64((*source).SubjectID)
|
||||
productsProduct.VendorCode = mapping.OptStringToString((*source).VendorCode)
|
||||
if (*source).Sizes != nil {
|
||||
productsProduct.Sizes = make([]*products.Product_Size, len((*source).Sizes))
|
||||
for i := 0; i < len((*source).Sizes); i++ {
|
||||
productsProduct.Sizes[i] = c.apiContentV2GetCardsListPostOKCardsItemSizesItemToPProductsProduct_Size((*source).Sizes[i])
|
||||
}
|
||||
}
|
||||
pProductsProduct = &productsProduct
|
||||
}
|
||||
return pProductsProduct
|
||||
}
|
||||
func (c *ConverterImpl) apiContentV2GetCardsListPostOKCardsItemSizesItemToPProductsProduct_Size(source client.ContentV2GetCardsListPostOKCardsItemSizesItem) *products.Product_Size {
|
||||
var productsProduct_Size products.Product_Size
|
||||
if source.Skus != nil {
|
||||
productsProduct_Size.Skus = make([]string, len(source.Skus))
|
||||
for i := 0; i < len(source.Skus); i++ {
|
||||
productsProduct_Size.Skus[i] = source.Skus[i]
|
||||
}
|
||||
}
|
||||
return &productsProduct_Size
|
||||
}
|
||||
13
internal/wb/products/repository.go
Normal file
13
internal/wb/products/repository.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sipro-mps/internal/marketplace"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
GetAllProducts(ctx context.Context, marketplaceId int) ([]WbProduct, error)
|
||||
StreamAllProducts(ctx context.Context, marketplaceId int, resultChan chan<- []WbProduct, errChan chan<- error)
|
||||
StreamAllProductsCache(ctx context.Context, marketplaceId int, resultChan chan<- []PbProduct, errChan chan<- error)
|
||||
ParseMarketplace(ctx context.Context, marketplaceId int) (*marketplace.Marketplace, string, error)
|
||||
}
|
||||
224
internal/wb/products/repository_api.go
Normal file
224
internal/wb/products/repository_api.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package products
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/redis/rueidis"
|
||||
"github.com/samber/lo"
|
||||
pb "sipro-mps/api/generated/v1/wb/products"
|
||||
"sipro-mps/internal/marketplace"
|
||||
"sipro-mps/internal/redis"
|
||||
"sipro-mps/internal/tasks/client"
|
||||
"sipro-mps/internal/tasks/types"
|
||||
"sipro-mps/internal/wb"
|
||||
"sipro-mps/internal/wb/products/mapping/generated"
|
||||
wbapi "sipro-mps/pkg/api/wb/client"
|
||||
)
|
||||
|
||||
const (
|
||||
maxRetries = 5
|
||||
maxProductsPerRequest = 100
|
||||
)
|
||||
|
||||
type apiRepository struct {
|
||||
marketplaceRepository marketplace.Repository
|
||||
}
|
||||
|
||||
func (a apiRepository) ParseMarketplace(ctx context.Context, marketplaceId int) (*marketplace.Marketplace, string, error) {
|
||||
marketplaceByID, err := a.marketplaceRepository.GetMarketplaceByID(ctx, marketplaceId)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
_, claims, err := wb.DecodeWildberriesJwt(marketplaceByID.AuthDataJson)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
sellerId := claims["sid"].(string)
|
||||
return marketplaceByID, sellerId, nil
|
||||
}
|
||||
|
||||
func fetchProducts(
|
||||
ctx context.Context,
|
||||
client *wbapi.Client,
|
||||
sellerId string,
|
||||
resultChan chan<- []WbProduct,
|
||||
errChan chan<- error,
|
||||
) {
|
||||
defer close(resultChan)
|
||||
defer close(errChan)
|
||||
request := wbapi.ContentV2GetCardsListPostReq{}
|
||||
request.Settings.SetTo(wbapi.ContentV2GetCardsListPostReqSettings{})
|
||||
|
||||
request.Settings.Value.Cursor.SetTo(wbapi.ContentV2GetCardsListPostReqSettingsCursor{})
|
||||
request.Settings.Value.Cursor.Value.Limit.SetTo(maxProductsPerRequest)
|
||||
|
||||
request.Settings.Value.Filter.SetTo(wbapi.ContentV2GetCardsListPostReqSettingsFilter{})
|
||||
request.Settings.Value.Filter.Value.WithPhoto.SetTo(-1)
|
||||
currentRetry := 0
|
||||
for {
|
||||
response, err := client.ContentV2GetCardsListPost(ctx, &request, wbapi.ContentV2GetCardsListPostParams{Locale: wbapi.NewOptString("ru")})
|
||||
if err != nil {
|
||||
currentRetry++
|
||||
if currentRetry >= maxRetries {
|
||||
errChan <- fmt.Errorf("fetching product IDs: %w", err)
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
currentRetry = 0
|
||||
|
||||
switch r := response.(type) {
|
||||
case *wbapi.ContentV2GetCardsListPostOKHeaders:
|
||||
err = wb.SyncRateLimitRemaining(ctx, sellerId, r.XRatelimitRemaining.Value)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("syncing rate limit: %w", err)
|
||||
return
|
||||
}
|
||||
resultChan <- r.Response.Cards
|
||||
if r.Response.Cursor.Value.Total.Value < maxProductsPerRequest {
|
||||
return
|
||||
}
|
||||
request.Settings.Value.Cursor.Value.UpdatedAt.SetTo(r.Response.Cursor.Value.UpdatedAt.Value)
|
||||
request.Settings.Value.Cursor.Value.NmID.SetTo(r.Response.Cursor.Value.NmID.Value)
|
||||
case *wbapi.R429Headers:
|
||||
err = wb.SetRateLimitRetry(ctx, sellerId, r.XRatelimitRetry.Value, r.XRatelimitLimit.Value, r.XRatelimitReset.Value)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("setting rate limit retry: %w", err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
errChan <- fmt.Errorf("unexpected response type: %T", r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a apiRepository) StreamAllProductsCache(ctx context.Context, marketplaceId int, resultChan chan<- []pb.Product, errChan chan<- error) {
|
||||
defer close(resultChan)
|
||||
defer close(errChan)
|
||||
_, sellerId, err := a.ParseMarketplace(ctx, marketplaceId)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
c := *redis.Client
|
||||
key := fmt.Sprintf("wb:products:%s", sellerId)
|
||||
jsonString, err := c.Do(ctx, c.B().Get().Key(key).Build()).ToString()
|
||||
if err == nil && jsonString != "null" {
|
||||
var result []pb.Product
|
||||
err = json.Unmarshal([]byte(jsonString), &result)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("unmarshalling products from cache: %w", err)
|
||||
return
|
||||
}
|
||||
task, err := types.NewFetchProductsTask(marketplaceId)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("creating fetch products task: %w", err)
|
||||
return
|
||||
}
|
||||
_, err = client.Client.Enqueue(task)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("enqueueing fetch products task: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
resultChan <- result
|
||||
return
|
||||
}
|
||||
if !errors.As(err, &rueidis.Nil) && err != nil {
|
||||
errChan <- fmt.Errorf("fetching products from cache: %w", err)
|
||||
return
|
||||
}
|
||||
converter := generated.ConverterImpl{}
|
||||
|
||||
innerResultChan := make(chan []WbProduct)
|
||||
innerErrChan := make(chan error)
|
||||
go a.StreamAllProducts(ctx, marketplaceId, innerResultChan, innerErrChan)
|
||||
var allProducts []pb.Product
|
||||
defer func() {
|
||||
jsonData, err := json.Marshal(allProducts)
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("marshalling products to cache: %w", err)
|
||||
return
|
||||
}
|
||||
err = c.Do(ctx, c.B().Set().Key(key).Value(string(jsonData)).Build()).Error()
|
||||
if err != nil {
|
||||
errChan <- fmt.Errorf("setting products to cache: %w", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
for {
|
||||
select {
|
||||
case err, ok := <-innerErrChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
errChan <- fmt.Errorf("streaming products: %w", err)
|
||||
return
|
||||
case products, ok := <-innerResultChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
pbProducts := lo.Map(products, func(p WbProduct, _ int) pb.Product {
|
||||
return *converter.ToProto(&p)
|
||||
})
|
||||
allProducts = append(allProducts, pbProducts...)
|
||||
resultChan <- pbProducts
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func (a apiRepository) GetAllProducts(ctx context.Context, marketplaceId int) ([]WbProduct, error) {
|
||||
marketplaceByID, sellerId, err := a.ParseMarketplace(ctx, marketplaceId)
|
||||
fromMarketplace, err := wb.GetClientFromMarketplace(marketplaceByID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultChan := make(chan []WbProduct)
|
||||
errChan := make(chan error)
|
||||
go fetchProducts(ctx, fromMarketplace, sellerId, resultChan, errChan)
|
||||
|
||||
var products []WbProduct
|
||||
isWaiting := true
|
||||
for {
|
||||
if !isWaiting {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case err, ok := <-errChan:
|
||||
if !ok {
|
||||
isWaiting = false
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
case newProducts, ok := <-resultChan:
|
||||
if !ok {
|
||||
isWaiting = false
|
||||
}
|
||||
products = append(products, newProducts...)
|
||||
}
|
||||
}
|
||||
return products, nil
|
||||
}
|
||||
|
||||
func (a apiRepository) StreamAllProducts(ctx context.Context, marketplaceId int, resultChan chan<- []WbProduct, errChan chan<- error) {
|
||||
marketplaceByID, sellerId, err := a.ParseMarketplace(ctx, marketplaceId)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
fromMarketplace, err := wb.GetClientFromMarketplace(marketplaceByID)
|
||||
if err != nil {
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
go fetchProducts(ctx, fromMarketplace, sellerId, resultChan, errChan)
|
||||
}
|
||||
|
||||
func NewAPIRepository(marketplaceRepository marketplace.Repository) Repository {
|
||||
return &apiRepository{
|
||||
marketplaceRepository: marketplaceRepository,
|
||||
}
|
||||
}
|
||||
170
internal/wb/rate_limiter.go
Normal file
170
internal/wb/rate_limiter.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package wb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/redis/rueidis"
|
||||
"net/http"
|
||||
"sipro-mps/internal/redis"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBucketCapacity = 10 // max burst size
|
||||
refillRate = 100.0 / 60000 // 300 requests per minute → 1 token per 200ms
|
||||
tokenTTLMillis = 60000 // Redis key TTL: 60s
|
||||
)
|
||||
|
||||
var tokenBucketScript = rueidis.NewLuaScript(`
|
||||
local key = KEYS[1]
|
||||
local now = tonumber(ARGV[1])
|
||||
local default_capacity = tonumber(ARGV[2])
|
||||
local refill_rate = tonumber(ARGV[3])
|
||||
local ttl = tonumber(ARGV[4])
|
||||
|
||||
-- Retry lock
|
||||
local retry_key = key .. ":retry_until"
|
||||
local retry_until = tonumber(redis.call("GET", retry_key))
|
||||
if retry_until and now < retry_until then
|
||||
return retry_until - now
|
||||
end
|
||||
|
||||
-- Token Bucket
|
||||
local capacity_key = key .. ":capacity"
|
||||
local token_key = key .. ":tokens"
|
||||
local time_key = key .. ":last_refill"
|
||||
|
||||
local capacity = tonumber(redis.call("GET", capacity_key)) or default_capacity
|
||||
local tokens = tonumber(redis.call("GET", token_key))
|
||||
local last_refill = tonumber(redis.call("GET", time_key))
|
||||
|
||||
if tokens == nil then tokens = capacity end
|
||||
if last_refill == nil then last_refill = now end
|
||||
|
||||
local elapsed = now - last_refill
|
||||
local refill = elapsed * refill_rate
|
||||
tokens = math.min(capacity, tokens + refill)
|
||||
last_refill = now
|
||||
|
||||
if tokens >= 1 then
|
||||
tokens = tokens - 1
|
||||
redis.call("SET", token_key, tokens)
|
||||
redis.call("SET", time_key, last_refill)
|
||||
redis.call("PEXPIRE", token_key, ttl)
|
||||
redis.call("PEXPIRE", time_key, ttl)
|
||||
return 0
|
||||
else
|
||||
local wait_time = math.ceil((1 - tokens) / refill_rate)
|
||||
return wait_time
|
||||
end
|
||||
`)
|
||||
|
||||
type RateLimitTransport struct {
|
||||
http.RoundTripper
|
||||
}
|
||||
|
||||
func (t *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
ctx := req.Context()
|
||||
|
||||
tokenString := req.Header.Get("Authorization")
|
||||
authData := NewWbAuthData(tokenString)
|
||||
authDataBytes, err := json.Marshal(authData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal Wildberries auth data: %w", err)
|
||||
}
|
||||
_, claims, err := DecodeWildberriesJwt(authDataBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode Wildberries JWT: %w", err)
|
||||
}
|
||||
sellerId := claims["sid"].(string)
|
||||
if sellerId == "" {
|
||||
return nil, fmt.Errorf("sellerId is required in JWT claims")
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
client := *redis.Client
|
||||
|
||||
waitTime, err := tokenBucketScript.Exec(ctx, client, []string{sellerId}, []string{
|
||||
fmt.Sprintf("%d", now),
|
||||
fmt.Sprintf("%d", defaultBucketCapacity),
|
||||
fmt.Sprintf("%f", refillRate),
|
||||
fmt.Sprintf("%d", tokenTTLMillis),
|
||||
}).ToInt64()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("rate limit script error: %w", err)
|
||||
}
|
||||
|
||||
if waitTime > 0 {
|
||||
select {
|
||||
case <-time.After(time.Duration(waitTime) * time.Millisecond):
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
return t.RoundTripper.RoundTrip(req)
|
||||
}
|
||||
|
||||
func SyncRateLimitRemaining(ctx context.Context, sellerId string, remaining int) error {
|
||||
if sellerId == "" || remaining < 0 {
|
||||
return fmt.Errorf("invalid sellerId or remaining")
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
client := *redis.Client
|
||||
|
||||
cmds := []rueidis.Completed{
|
||||
client.B().Set().Key(sellerId + ":capacity").Value(fmt.Sprintf("%d", defaultBucketCapacity)).Ex(time.Minute).Build(),
|
||||
client.B().Set().Key(sellerId + ":tokens").Value(fmt.Sprintf("%d", remaining)).Ex(time.Minute).Build(),
|
||||
client.B().Set().Key(sellerId + ":last_refill").Value(fmt.Sprintf("%d", now)).Ex(time.Minute).Build(),
|
||||
}
|
||||
|
||||
results := client.DoMulti(ctx, cmds...)
|
||||
for _, res := range results {
|
||||
if res.Error() != nil {
|
||||
return fmt.Errorf("failed to sync rate limit: %w", res.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetRateLimitRetry(ctx context.Context, sellerId string, retrySeconds int, limit int, resetSeconds int) error {
|
||||
if sellerId == "" {
|
||||
return fmt.Errorf("sellerId is required")
|
||||
}
|
||||
now := time.Now()
|
||||
retryUntil := now.Add(time.Duration(retrySeconds) * time.Second).UnixMilli()
|
||||
client := *redis.Client
|
||||
|
||||
cmds := []rueidis.Completed{
|
||||
client.B().Set().
|
||||
Key(sellerId + ":retry_until").
|
||||
Value(fmt.Sprintf("%d", retryUntil)).
|
||||
Px(time.Duration(retrySeconds+5) * time.Second).Build(),
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
cmds = append(cmds, client.B().Set().
|
||||
Key(sellerId+":capacity").
|
||||
Value(fmt.Sprintf("%d", limit)).
|
||||
Ex(time.Hour).Build())
|
||||
}
|
||||
|
||||
if resetSeconds > 0 {
|
||||
resetAt := now.Add(time.Duration(resetSeconds) * time.Second)
|
||||
fmt.Printf("Seller %s rate limit resets at %v (limit: %d)\n", sellerId, resetAt, limit)
|
||||
}
|
||||
|
||||
results := client.DoMulti(ctx, cmds...)
|
||||
for _, res := range results {
|
||||
if res.Error() != nil {
|
||||
return fmt.Errorf("failed to set retry info: %w", res.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewRateLimitTransport() *RateLimitTransport {
|
||||
return &RateLimitTransport{RoundTripper: http.DefaultTransport}
|
||||
}
|
||||
22
internal/wb/security_handler.go
Normal file
22
internal/wb/security_handler.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package wb
|
||||
|
||||
import (
|
||||
"context"
|
||||
wbclient "sipro-mps/pkg/api/wb/client"
|
||||
)
|
||||
|
||||
type WildberriesSecurityHandler struct {
|
||||
ApiKey string
|
||||
}
|
||||
|
||||
func (sh WildberriesSecurityHandler) HeaderApiKey(ctx context.Context, operationName wbclient.OperationName, client *wbclient.Client) (wbclient.HeaderApiKey, error) {
|
||||
return wbclient.HeaderApiKey{
|
||||
APIKey: sh.ApiKey,
|
||||
Roles: nil,
|
||||
}, nil
|
||||
}
|
||||
func NewWildberriesSecurityHandler(apiKey string) WildberriesSecurityHandler {
|
||||
return WildberriesSecurityHandler{
|
||||
ApiKey: apiKey,
|
||||
}
|
||||
}
|
||||
1
internal/wb/types.go
Normal file
1
internal/wb/types.go
Normal file
@@ -0,0 +1 @@
|
||||
package wb
|
||||
5572
pkg/api/wb/02-products.yaml
Normal file
5572
pkg/api/wb/02-products.yaml
Normal file
File diff suppressed because it is too large
Load Diff
283
pkg/api/wb/client/oas_cfg_gen.go
Normal file
283
pkg/api/wb/client/oas_cfg_gen.go
Normal file
@@ -0,0 +1,283 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
ht "github.com/ogen-go/ogen/http"
|
||||
"github.com/ogen-go/ogen/middleware"
|
||||
"github.com/ogen-go/ogen/ogenerrors"
|
||||
"github.com/ogen-go/ogen/otelogen"
|
||||
)
|
||||
|
||||
var (
|
||||
// Allocate option closure once.
|
||||
clientSpanKind = trace.WithSpanKind(trace.SpanKindClient)
|
||||
// Allocate option closure once.
|
||||
serverSpanKind = trace.WithSpanKind(trace.SpanKindServer)
|
||||
)
|
||||
|
||||
type (
|
||||
optionFunc[C any] func(*C)
|
||||
otelOptionFunc func(*otelConfig)
|
||||
)
|
||||
|
||||
type otelConfig struct {
|
||||
TracerProvider trace.TracerProvider
|
||||
Tracer trace.Tracer
|
||||
MeterProvider metric.MeterProvider
|
||||
Meter metric.Meter
|
||||
}
|
||||
|
||||
func (cfg *otelConfig) initOTEL() {
|
||||
if cfg.TracerProvider == nil {
|
||||
cfg.TracerProvider = otel.GetTracerProvider()
|
||||
}
|
||||
if cfg.MeterProvider == nil {
|
||||
cfg.MeterProvider = otel.GetMeterProvider()
|
||||
}
|
||||
cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name,
|
||||
trace.WithInstrumentationVersion(otelogen.SemVersion()),
|
||||
)
|
||||
cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name,
|
||||
metric.WithInstrumentationVersion(otelogen.SemVersion()),
|
||||
)
|
||||
}
|
||||
|
||||
// ErrorHandler is error handler.
|
||||
type ErrorHandler = ogenerrors.ErrorHandler
|
||||
|
||||
type serverConfig struct {
|
||||
otelConfig
|
||||
NotFound http.HandlerFunc
|
||||
MethodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)
|
||||
ErrorHandler ErrorHandler
|
||||
Prefix string
|
||||
Middleware Middleware
|
||||
MaxMultipartMemory int64
|
||||
}
|
||||
|
||||
// ServerOption is server config option.
|
||||
type ServerOption interface {
|
||||
applyServer(*serverConfig)
|
||||
}
|
||||
|
||||
var _ ServerOption = (optionFunc[serverConfig])(nil)
|
||||
|
||||
func (o optionFunc[C]) applyServer(c *C) {
|
||||
o(c)
|
||||
}
|
||||
|
||||
var _ ServerOption = (otelOptionFunc)(nil)
|
||||
|
||||
func (o otelOptionFunc) applyServer(c *serverConfig) {
|
||||
o(&c.otelConfig)
|
||||
}
|
||||
|
||||
func newServerConfig(opts ...ServerOption) serverConfig {
|
||||
cfg := serverConfig{
|
||||
NotFound: http.NotFound,
|
||||
MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) {
|
||||
status := http.StatusMethodNotAllowed
|
||||
if r.Method == "OPTIONS" {
|
||||
w.Header().Set("Access-Control-Allow-Methods", allowed)
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
status = http.StatusNoContent
|
||||
} else {
|
||||
w.Header().Set("Allow", allowed)
|
||||
}
|
||||
w.WriteHeader(status)
|
||||
},
|
||||
ErrorHandler: ogenerrors.DefaultErrorHandler,
|
||||
Middleware: nil,
|
||||
MaxMultipartMemory: 32 << 20, // 32 MB
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt.applyServer(&cfg)
|
||||
}
|
||||
cfg.initOTEL()
|
||||
return cfg
|
||||
}
|
||||
|
||||
type baseServer struct {
|
||||
cfg serverConfig
|
||||
requests metric.Int64Counter
|
||||
errors metric.Int64Counter
|
||||
duration metric.Float64Histogram
|
||||
}
|
||||
|
||||
func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) {
|
||||
s.cfg.NotFound(w, r)
|
||||
}
|
||||
|
||||
func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) {
|
||||
s.cfg.MethodNotAllowed(w, r, allowed)
|
||||
}
|
||||
|
||||
func (cfg serverConfig) baseServer() (s baseServer, err error) {
|
||||
s = baseServer{cfg: cfg}
|
||||
if s.requests, err = otelogen.ServerRequestCountCounter(s.cfg.Meter); err != nil {
|
||||
return s, err
|
||||
}
|
||||
if s.errors, err = otelogen.ServerErrorsCountCounter(s.cfg.Meter); err != nil {
|
||||
return s, err
|
||||
}
|
||||
if s.duration, err = otelogen.ServerDurationHistogram(s.cfg.Meter); err != nil {
|
||||
return s, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type clientConfig struct {
|
||||
otelConfig
|
||||
Client ht.Client
|
||||
}
|
||||
|
||||
// ClientOption is client config option.
|
||||
type ClientOption interface {
|
||||
applyClient(*clientConfig)
|
||||
}
|
||||
|
||||
var _ ClientOption = (optionFunc[clientConfig])(nil)
|
||||
|
||||
func (o optionFunc[C]) applyClient(c *C) {
|
||||
o(c)
|
||||
}
|
||||
|
||||
var _ ClientOption = (otelOptionFunc)(nil)
|
||||
|
||||
func (o otelOptionFunc) applyClient(c *clientConfig) {
|
||||
o(&c.otelConfig)
|
||||
}
|
||||
|
||||
func newClientConfig(opts ...ClientOption) clientConfig {
|
||||
cfg := clientConfig{
|
||||
Client: http.DefaultClient,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt.applyClient(&cfg)
|
||||
}
|
||||
cfg.initOTEL()
|
||||
return cfg
|
||||
}
|
||||
|
||||
type baseClient struct {
|
||||
cfg clientConfig
|
||||
requests metric.Int64Counter
|
||||
errors metric.Int64Counter
|
||||
duration metric.Float64Histogram
|
||||
}
|
||||
|
||||
func (cfg clientConfig) baseClient() (c baseClient, err error) {
|
||||
c = baseClient{cfg: cfg}
|
||||
if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil {
|
||||
return c, err
|
||||
}
|
||||
if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil {
|
||||
return c, err
|
||||
}
|
||||
if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil {
|
||||
return c, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Option is config option.
|
||||
type Option interface {
|
||||
ServerOption
|
||||
ClientOption
|
||||
}
|
||||
|
||||
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
|
||||
//
|
||||
// If none is specified, the global provider is used.
|
||||
func WithTracerProvider(provider trace.TracerProvider) Option {
|
||||
return otelOptionFunc(func(cfg *otelConfig) {
|
||||
if provider != nil {
|
||||
cfg.TracerProvider = provider
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithMeterProvider specifies a meter provider to use for creating a meter.
|
||||
//
|
||||
// If none is specified, the otel.GetMeterProvider() is used.
|
||||
func WithMeterProvider(provider metric.MeterProvider) Option {
|
||||
return otelOptionFunc(func(cfg *otelConfig) {
|
||||
if provider != nil {
|
||||
cfg.MeterProvider = provider
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithClient specifies http client to use.
|
||||
func WithClient(client ht.Client) ClientOption {
|
||||
return optionFunc[clientConfig](func(cfg *clientConfig) {
|
||||
if client != nil {
|
||||
cfg.Client = client
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithNotFound specifies Not Found handler to use.
|
||||
func WithNotFound(notFound http.HandlerFunc) ServerOption {
|
||||
return optionFunc[serverConfig](func(cfg *serverConfig) {
|
||||
if notFound != nil {
|
||||
cfg.NotFound = notFound
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithMethodNotAllowed specifies Method Not Allowed handler to use.
|
||||
func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption {
|
||||
return optionFunc[serverConfig](func(cfg *serverConfig) {
|
||||
if methodNotAllowed != nil {
|
||||
cfg.MethodNotAllowed = methodNotAllowed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithErrorHandler specifies error handler to use.
|
||||
func WithErrorHandler(h ErrorHandler) ServerOption {
|
||||
return optionFunc[serverConfig](func(cfg *serverConfig) {
|
||||
if h != nil {
|
||||
cfg.ErrorHandler = h
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithPathPrefix specifies server path prefix.
|
||||
func WithPathPrefix(prefix string) ServerOption {
|
||||
return optionFunc[serverConfig](func(cfg *serverConfig) {
|
||||
cfg.Prefix = prefix
|
||||
})
|
||||
}
|
||||
|
||||
// WithMiddleware specifies middlewares to use.
|
||||
func WithMiddleware(m ...Middleware) ServerOption {
|
||||
return optionFunc[serverConfig](func(cfg *serverConfig) {
|
||||
switch len(m) {
|
||||
case 0:
|
||||
cfg.Middleware = nil
|
||||
case 1:
|
||||
cfg.Middleware = m[0]
|
||||
default:
|
||||
cfg.Middleware = middleware.ChainMiddlewares(m...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// WithMaxMultipartMemory specifies limit of memory for storing file parts.
|
||||
// File parts which can't be stored in memory will be stored on disk in temporary files.
|
||||
func WithMaxMultipartMemory(max int64) ServerOption {
|
||||
return optionFunc[serverConfig](func(cfg *serverConfig) {
|
||||
if max > 0 {
|
||||
cfg.MaxMultipartMemory = max
|
||||
}
|
||||
})
|
||||
}
|
||||
6749
pkg/api/wb/client/oas_client_gen.go
Normal file
6749
pkg/api/wb/client/oas_client_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
8243
pkg/api/wb/client/oas_handlers_gen.go
Normal file
8243
pkg/api/wb/client/oas_handlers_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
166
pkg/api/wb/client/oas_interfaces_gen.go
Normal file
166
pkg/api/wb/client/oas_interfaces_gen.go
Normal file
@@ -0,0 +1,166 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
package api
|
||||
|
||||
type APIV2BufferGoodsTaskGetRes interface {
|
||||
aPIV2BufferGoodsTaskGetRes()
|
||||
}
|
||||
|
||||
type APIV2BufferTasksGetRes interface {
|
||||
aPIV2BufferTasksGetRes()
|
||||
}
|
||||
|
||||
type APIV2HistoryGoodsTaskGetRes interface {
|
||||
aPIV2HistoryGoodsTaskGetRes()
|
||||
}
|
||||
|
||||
type APIV2HistoryTasksGetRes interface {
|
||||
aPIV2HistoryTasksGetRes()
|
||||
}
|
||||
|
||||
type APIV2ListGoodsFilterGetRes interface {
|
||||
aPIV2ListGoodsFilterGetRes()
|
||||
}
|
||||
|
||||
type APIV2ListGoodsSizeNmGetRes interface {
|
||||
aPIV2ListGoodsSizeNmGetRes()
|
||||
}
|
||||
|
||||
type APIV2QuarantineGoodsGetRes interface {
|
||||
aPIV2QuarantineGoodsGetRes()
|
||||
}
|
||||
|
||||
type APIV2UploadTaskClubDiscountPostRes interface {
|
||||
aPIV2UploadTaskClubDiscountPostRes()
|
||||
}
|
||||
|
||||
type APIV2UploadTaskPostRes interface {
|
||||
aPIV2UploadTaskPostRes()
|
||||
}
|
||||
|
||||
type APIV2UploadTaskSizePostRes interface {
|
||||
aPIV2UploadTaskSizePostRes()
|
||||
}
|
||||
|
||||
type APIV3OfficesGetRes interface {
|
||||
aPIV3OfficesGetRes()
|
||||
}
|
||||
|
||||
type APIV3StocksWarehouseIdDeleteRes interface {
|
||||
aPIV3StocksWarehouseIdDeleteRes()
|
||||
}
|
||||
|
||||
type APIV3StocksWarehouseIdPostRes interface {
|
||||
aPIV3StocksWarehouseIdPostRes()
|
||||
}
|
||||
|
||||
type APIV3StocksWarehouseIdPutRes interface {
|
||||
aPIV3StocksWarehouseIdPutRes()
|
||||
}
|
||||
|
||||
type APIV3WarehousesGetRes interface {
|
||||
aPIV3WarehousesGetRes()
|
||||
}
|
||||
|
||||
type APIV3WarehousesPostRes interface {
|
||||
aPIV3WarehousesPostRes()
|
||||
}
|
||||
|
||||
type APIV3WarehousesWarehouseIdDeleteRes interface {
|
||||
aPIV3WarehousesWarehouseIdDeleteRes()
|
||||
}
|
||||
|
||||
type APIV3WarehousesWarehouseIdPutRes interface {
|
||||
aPIV3WarehousesWarehouseIdPutRes()
|
||||
}
|
||||
|
||||
type ContentV2BarcodesPostRes interface {
|
||||
contentV2BarcodesPostRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsDeleteTrashPostRes interface {
|
||||
contentV2CardsDeleteTrashPostRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsErrorListGetRes interface {
|
||||
contentV2CardsErrorListGetRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsLimitsGetRes interface {
|
||||
contentV2CardsLimitsGetRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsRecoverPostRes interface {
|
||||
contentV2CardsRecoverPostRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsUpdatePostRes interface {
|
||||
contentV2CardsUpdatePostRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsUploadAddPostRes interface {
|
||||
contentV2CardsUploadAddPostRes()
|
||||
}
|
||||
|
||||
type ContentV2CardsUploadPostRes interface {
|
||||
contentV2CardsUploadPostRes()
|
||||
}
|
||||
|
||||
type ContentV2DirectoryColorsGetRes interface {
|
||||
contentV2DirectoryColorsGetRes()
|
||||
}
|
||||
|
||||
type ContentV2DirectoryCountriesGetRes interface {
|
||||
contentV2DirectoryCountriesGetRes()
|
||||
}
|
||||
|
||||
type ContentV2DirectoryKindsGetRes interface {
|
||||
contentV2DirectoryKindsGetRes()
|
||||
}
|
||||
|
||||
type ContentV2DirectorySeasonsGetRes interface {
|
||||
contentV2DirectorySeasonsGetRes()
|
||||
}
|
||||
|
||||
type ContentV2DirectoryTnvedGetRes interface {
|
||||
contentV2DirectoryTnvedGetRes()
|
||||
}
|
||||
|
||||
type ContentV2DirectoryVatGetRes interface {
|
||||
contentV2DirectoryVatGetRes()
|
||||
}
|
||||
|
||||
type ContentV2GetCardsListPostRes interface {
|
||||
contentV2GetCardsListPostRes()
|
||||
}
|
||||
|
||||
type ContentV2GetCardsTrashPostRes interface {
|
||||
contentV2GetCardsTrashPostRes()
|
||||
}
|
||||
|
||||
type ContentV2ObjectAllGetRes interface {
|
||||
contentV2ObjectAllGetRes()
|
||||
}
|
||||
|
||||
type ContentV2ObjectCharcsSubjectIdGetRes interface {
|
||||
contentV2ObjectCharcsSubjectIdGetRes()
|
||||
}
|
||||
|
||||
type ContentV2ObjectParentAllGetRes interface {
|
||||
contentV2ObjectParentAllGetRes()
|
||||
}
|
||||
|
||||
type ContentV2TagNomenclatureLinkPostRes interface {
|
||||
contentV2TagNomenclatureLinkPostRes()
|
||||
}
|
||||
|
||||
type ContentV2TagsGetRes interface {
|
||||
contentV2TagsGetRes()
|
||||
}
|
||||
|
||||
type ContentV3MediaFilePostRes interface {
|
||||
contentV3MediaFilePostRes()
|
||||
}
|
||||
|
||||
type ContentV3MediaSavePostRes interface {
|
||||
contentV3MediaSavePostRes()
|
||||
}
|
||||
19793
pkg/api/wb/client/oas_json_gen.go
Normal file
19793
pkg/api/wb/client/oas_json_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
42
pkg/api/wb/client/oas_labeler_gen.go
Normal file
42
pkg/api/wb/client/oas_labeler_gen.go
Normal file
@@ -0,0 +1,42 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
)
|
||||
|
||||
// Labeler is used to allow adding custom attributes to the server request metrics.
|
||||
type Labeler struct {
|
||||
attrs []attribute.KeyValue
|
||||
}
|
||||
|
||||
// Add attributes to the Labeler.
|
||||
func (l *Labeler) Add(attrs ...attribute.KeyValue) {
|
||||
l.attrs = append(l.attrs, attrs...)
|
||||
}
|
||||
|
||||
// AttributeSet returns the attributes added to the Labeler as an attribute.Set.
|
||||
func (l *Labeler) AttributeSet() attribute.Set {
|
||||
return attribute.NewSet(l.attrs...)
|
||||
}
|
||||
|
||||
type labelerContextKey struct{}
|
||||
|
||||
// LabelerFromContext retrieves the Labeler from the provided context, if present.
|
||||
//
|
||||
// If no Labeler was found in the provided context a new, empty Labeler is returned and the second
|
||||
// return value is false. In this case it is safe to use the Labeler but any attributes added to
|
||||
// it will not be used.
|
||||
func LabelerFromContext(ctx context.Context) (*Labeler, bool) {
|
||||
if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok {
|
||||
return l, true
|
||||
}
|
||||
return &Labeler{}, false
|
||||
}
|
||||
|
||||
func contextWithLabeler(ctx context.Context, l *Labeler) context.Context {
|
||||
return context.WithValue(ctx, labelerContextKey{}, l)
|
||||
}
|
||||
10
pkg/api/wb/client/oas_middleware_gen.go
Normal file
10
pkg/api/wb/client/oas_middleware_gen.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/ogen-go/ogen/middleware"
|
||||
)
|
||||
|
||||
// Middleware is middleware type.
|
||||
type Middleware = middleware.Middleware
|
||||
50
pkg/api/wb/client/oas_operations_gen.go
Normal file
50
pkg/api/wb/client/oas_operations_gen.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
// OperationName is the ogen operation name
|
||||
type OperationName = string
|
||||
|
||||
const (
|
||||
APIV2BufferGoodsTaskGetOperation OperationName = "APIV2BufferGoodsTaskGet"
|
||||
APIV2BufferTasksGetOperation OperationName = "APIV2BufferTasksGet"
|
||||
APIV2HistoryGoodsTaskGetOperation OperationName = "APIV2HistoryGoodsTaskGet"
|
||||
APIV2HistoryTasksGetOperation OperationName = "APIV2HistoryTasksGet"
|
||||
APIV2ListGoodsFilterGetOperation OperationName = "APIV2ListGoodsFilterGet"
|
||||
APIV2ListGoodsSizeNmGetOperation OperationName = "APIV2ListGoodsSizeNmGet"
|
||||
APIV2QuarantineGoodsGetOperation OperationName = "APIV2QuarantineGoodsGet"
|
||||
APIV2UploadTaskClubDiscountPostOperation OperationName = "APIV2UploadTaskClubDiscountPost"
|
||||
APIV2UploadTaskPostOperation OperationName = "APIV2UploadTaskPost"
|
||||
APIV2UploadTaskSizePostOperation OperationName = "APIV2UploadTaskSizePost"
|
||||
APIV3OfficesGetOperation OperationName = "APIV3OfficesGet"
|
||||
APIV3StocksWarehouseIdDeleteOperation OperationName = "APIV3StocksWarehouseIdDelete"
|
||||
APIV3StocksWarehouseIdPostOperation OperationName = "APIV3StocksWarehouseIdPost"
|
||||
APIV3StocksWarehouseIdPutOperation OperationName = "APIV3StocksWarehouseIdPut"
|
||||
APIV3WarehousesGetOperation OperationName = "APIV3WarehousesGet"
|
||||
APIV3WarehousesPostOperation OperationName = "APIV3WarehousesPost"
|
||||
APIV3WarehousesWarehouseIdDeleteOperation OperationName = "APIV3WarehousesWarehouseIdDelete"
|
||||
APIV3WarehousesWarehouseIdPutOperation OperationName = "APIV3WarehousesWarehouseIdPut"
|
||||
ContentV2BarcodesPostOperation OperationName = "ContentV2BarcodesPost"
|
||||
ContentV2CardsDeleteTrashPostOperation OperationName = "ContentV2CardsDeleteTrashPost"
|
||||
ContentV2CardsErrorListGetOperation OperationName = "ContentV2CardsErrorListGet"
|
||||
ContentV2CardsLimitsGetOperation OperationName = "ContentV2CardsLimitsGet"
|
||||
ContentV2CardsRecoverPostOperation OperationName = "ContentV2CardsRecoverPost"
|
||||
ContentV2CardsUpdatePostOperation OperationName = "ContentV2CardsUpdatePost"
|
||||
ContentV2CardsUploadAddPostOperation OperationName = "ContentV2CardsUploadAddPost"
|
||||
ContentV2CardsUploadPostOperation OperationName = "ContentV2CardsUploadPost"
|
||||
ContentV2DirectoryColorsGetOperation OperationName = "ContentV2DirectoryColorsGet"
|
||||
ContentV2DirectoryCountriesGetOperation OperationName = "ContentV2DirectoryCountriesGet"
|
||||
ContentV2DirectoryKindsGetOperation OperationName = "ContentV2DirectoryKindsGet"
|
||||
ContentV2DirectorySeasonsGetOperation OperationName = "ContentV2DirectorySeasonsGet"
|
||||
ContentV2DirectoryTnvedGetOperation OperationName = "ContentV2DirectoryTnvedGet"
|
||||
ContentV2DirectoryVatGetOperation OperationName = "ContentV2DirectoryVatGet"
|
||||
ContentV2GetCardsListPostOperation OperationName = "ContentV2GetCardsListPost"
|
||||
ContentV2GetCardsTrashPostOperation OperationName = "ContentV2GetCardsTrashPost"
|
||||
ContentV2ObjectAllGetOperation OperationName = "ContentV2ObjectAllGet"
|
||||
ContentV2ObjectCharcsSubjectIdGetOperation OperationName = "ContentV2ObjectCharcsSubjectIdGet"
|
||||
ContentV2ObjectParentAllGetOperation OperationName = "ContentV2ObjectParentAllGet"
|
||||
ContentV2TagNomenclatureLinkPostOperation OperationName = "ContentV2TagNomenclatureLinkPost"
|
||||
ContentV2TagsGetOperation OperationName = "ContentV2TagsGet"
|
||||
ContentV3MediaFilePostOperation OperationName = "ContentV3MediaFilePost"
|
||||
ContentV3MediaSavePostOperation OperationName = "ContentV3MediaSavePost"
|
||||
)
|
||||
2634
pkg/api/wb/client/oas_parameters_gen.go
Normal file
2634
pkg/api/wb/client/oas_parameters_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
1360
pkg/api/wb/client/oas_request_decoders_gen.go
Normal file
1360
pkg/api/wb/client/oas_request_decoders_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
315
pkg/api/wb/client/oas_request_encoders_gen.go
Normal file
315
pkg/api/wb/client/oas_request_encoders_gen.go
Normal file
@@ -0,0 +1,315 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/go-faster/jx"
|
||||
|
||||
ht "github.com/ogen-go/ogen/http"
|
||||
"github.com/ogen-go/ogen/uri"
|
||||
)
|
||||
|
||||
func encodeAPIV2UploadTaskClubDiscountPostRequest(
|
||||
req *APIV2UploadTaskClubDiscountPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV2UploadTaskPostRequest(
|
||||
req *APIV2UploadTaskPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV2UploadTaskSizePostRequest(
|
||||
req *APIV2UploadTaskSizePostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV3StocksWarehouseIdDeleteRequest(
|
||||
req *APIV3StocksWarehouseIdDeleteReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV3StocksWarehouseIdPostRequest(
|
||||
req *APIV3StocksWarehouseIdPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV3StocksWarehouseIdPutRequest(
|
||||
req OptAPIV3StocksWarehouseIdPutReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
if !req.Set {
|
||||
// Keep request with empty body if value is not set.
|
||||
return nil
|
||||
}
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
if req.Set {
|
||||
req.Encode(e)
|
||||
}
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV3WarehousesPostRequest(
|
||||
req *APIV3WarehousesPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeAPIV3WarehousesWarehouseIdPutRequest(
|
||||
req *APIV3WarehousesWarehouseIdPutReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2BarcodesPostRequest(
|
||||
req *ContentV2BarcodesPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2CardsDeleteTrashPostRequest(
|
||||
req *ContentV2CardsDeleteTrashPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2CardsRecoverPostRequest(
|
||||
req *ContentV2CardsRecoverPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2CardsUpdatePostRequest(
|
||||
req []ContentV2CardsUpdatePostReqItem,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
if req != nil {
|
||||
e.ArrStart()
|
||||
for _, elem := range req {
|
||||
elem.Encode(e)
|
||||
}
|
||||
e.ArrEnd()
|
||||
}
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2CardsUploadAddPostRequest(
|
||||
req OptContentV2CardsUploadAddPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
if !req.Set {
|
||||
// Keep request with empty body if value is not set.
|
||||
return nil
|
||||
}
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
if req.Set {
|
||||
req.Encode(e)
|
||||
}
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2CardsUploadPostRequest(
|
||||
req []ContentV2CardsUploadPostReqItem,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
if req != nil {
|
||||
e.ArrStart()
|
||||
for _, elem := range req {
|
||||
elem.Encode(e)
|
||||
}
|
||||
e.ArrEnd()
|
||||
}
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2GetCardsListPostRequest(
|
||||
req *ContentV2GetCardsListPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2GetCardsTrashPostRequest(
|
||||
req *ContentV2GetCardsTrashPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV2TagNomenclatureLinkPostRequest(
|
||||
req *ContentV2TagNomenclatureLinkPostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV3MediaFilePostRequest(
|
||||
req *ContentV3MediaFilePostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "multipart/form-data"
|
||||
request := req
|
||||
|
||||
q := uri.NewFormEncoder(map[string]string{})
|
||||
body, boundary := ht.CreateMultipartBody(func(w *multipart.Writer) error {
|
||||
if val, ok := request.Uploadfile.Get(); ok {
|
||||
if err := val.WriteMultipart("uploadfile", w); err != nil {
|
||||
return errors.Wrap(err, "write \"uploadfile\"")
|
||||
}
|
||||
}
|
||||
if err := q.WriteMultipart(w); err != nil {
|
||||
return errors.Wrap(err, "write multipart")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
ht.SetCloserBody(r, body, mime.FormatMediaType(contentType, map[string]string{"boundary": boundary}))
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeContentV3MediaSavePostRequest(
|
||||
req *ContentV3MediaSavePostReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
12994
pkg/api/wb/client/oas_response_decoders_gen.go
Normal file
12994
pkg/api/wb/client/oas_response_decoders_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
5052
pkg/api/wb/client/oas_response_encoders_gen.go
Normal file
5052
pkg/api/wb/client/oas_response_encoders_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
2379
pkg/api/wb/client/oas_router_gen.go
Normal file
2379
pkg/api/wb/client/oas_router_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
10053
pkg/api/wb/client/oas_schemas_gen.go
Normal file
10053
pkg/api/wb/client/oas_schemas_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
111
pkg/api/wb/client/oas_security_gen.go
Normal file
111
pkg/api/wb/client/oas_security_gen.go
Normal file
@@ -0,0 +1,111 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
|
||||
"github.com/ogen-go/ogen/ogenerrors"
|
||||
)
|
||||
|
||||
// SecurityHandler is handler for security parameters.
|
||||
type SecurityHandler interface {
|
||||
// HandleHeaderApiKey handles HeaderApiKey security.
|
||||
HandleHeaderApiKey(ctx context.Context, operationName OperationName, t HeaderApiKey) (context.Context, error)
|
||||
}
|
||||
|
||||
func findAuthorization(h http.Header, prefix string) (string, bool) {
|
||||
v, ok := h["Authorization"]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
for _, vv := range v {
|
||||
scheme, value, ok := strings.Cut(vv, " ")
|
||||
if !ok || !strings.EqualFold(scheme, prefix) {
|
||||
continue
|
||||
}
|
||||
return value, true
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
var operationRolesHeaderApiKey = map[string][]string{
|
||||
APIV2BufferGoodsTaskGetOperation: []string{},
|
||||
APIV2BufferTasksGetOperation: []string{},
|
||||
APIV2HistoryGoodsTaskGetOperation: []string{},
|
||||
APIV2HistoryTasksGetOperation: []string{},
|
||||
APIV2ListGoodsFilterGetOperation: []string{},
|
||||
APIV2ListGoodsSizeNmGetOperation: []string{},
|
||||
APIV2QuarantineGoodsGetOperation: []string{},
|
||||
APIV2UploadTaskClubDiscountPostOperation: []string{},
|
||||
APIV2UploadTaskPostOperation: []string{},
|
||||
APIV2UploadTaskSizePostOperation: []string{},
|
||||
APIV3OfficesGetOperation: []string{},
|
||||
APIV3StocksWarehouseIdDeleteOperation: []string{},
|
||||
APIV3StocksWarehouseIdPostOperation: []string{},
|
||||
APIV3StocksWarehouseIdPutOperation: []string{},
|
||||
APIV3WarehousesGetOperation: []string{},
|
||||
APIV3WarehousesPostOperation: []string{},
|
||||
APIV3WarehousesWarehouseIdDeleteOperation: []string{},
|
||||
APIV3WarehousesWarehouseIdPutOperation: []string{},
|
||||
ContentV2BarcodesPostOperation: []string{},
|
||||
ContentV2CardsDeleteTrashPostOperation: []string{},
|
||||
ContentV2CardsErrorListGetOperation: []string{},
|
||||
ContentV2CardsLimitsGetOperation: []string{},
|
||||
ContentV2CardsRecoverPostOperation: []string{},
|
||||
ContentV2CardsUpdatePostOperation: []string{},
|
||||
ContentV2CardsUploadAddPostOperation: []string{},
|
||||
ContentV2CardsUploadPostOperation: []string{},
|
||||
ContentV2DirectoryColorsGetOperation: []string{},
|
||||
ContentV2DirectoryCountriesGetOperation: []string{},
|
||||
ContentV2DirectoryKindsGetOperation: []string{},
|
||||
ContentV2DirectorySeasonsGetOperation: []string{},
|
||||
ContentV2DirectoryTnvedGetOperation: []string{},
|
||||
ContentV2DirectoryVatGetOperation: []string{},
|
||||
ContentV2GetCardsListPostOperation: []string{},
|
||||
ContentV2GetCardsTrashPostOperation: []string{},
|
||||
ContentV2ObjectAllGetOperation: []string{},
|
||||
ContentV2ObjectCharcsSubjectIdGetOperation: []string{},
|
||||
ContentV2ObjectParentAllGetOperation: []string{},
|
||||
ContentV2TagNomenclatureLinkPostOperation: []string{},
|
||||
ContentV2TagsGetOperation: []string{},
|
||||
ContentV3MediaFilePostOperation: []string{},
|
||||
ContentV3MediaSavePostOperation: []string{},
|
||||
}
|
||||
|
||||
func (s *Server) securityHeaderApiKey(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) {
|
||||
var t HeaderApiKey
|
||||
const parameterName = "Authorization"
|
||||
value := req.Header.Get(parameterName)
|
||||
if value == "" {
|
||||
return ctx, false, nil
|
||||
}
|
||||
t.APIKey = value
|
||||
t.Roles = operationRolesHeaderApiKey[operationName]
|
||||
rctx, err := s.sec.HandleHeaderApiKey(ctx, operationName, t)
|
||||
if errors.Is(err, ogenerrors.ErrSkipServerSecurity) {
|
||||
return nil, false, nil
|
||||
} else if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return rctx, true, err
|
||||
}
|
||||
|
||||
// SecuritySource is provider of security values (tokens, passwords, etc.).
|
||||
type SecuritySource interface {
|
||||
// HeaderApiKey provides HeaderApiKey security value.
|
||||
HeaderApiKey(ctx context.Context, operationName OperationName, client *Client) (HeaderApiKey, error)
|
||||
}
|
||||
|
||||
func (s *Client) securityHeaderApiKey(ctx context.Context, operationName OperationName, req *http.Request) error {
|
||||
t, err := s.sec.HeaderApiKey(ctx, operationName, s)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "security source \"HeaderApiKey\"")
|
||||
}
|
||||
req.Header.Set("Authorization", t.APIKey)
|
||||
return nil
|
||||
}
|
||||
951
pkg/api/wb/client/oas_server_gen.go
Normal file
951
pkg/api/wb/client/oas_server_gen.go
Normal file
@@ -0,0 +1,951 @@
|
||||
// Code generated by ogen, DO NOT EDIT.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Handler handles operations described by OpenAPI v3 specification.
|
||||
type Handler interface {
|
||||
// APIV2BufferGoodsTaskGet implements GET /api/v2/buffer/goods/task operation.
|
||||
//
|
||||
// Метод предоставляет информацию о товарах и ошибках в
|
||||
// товарах из загрузки в обработке.
|
||||
// <div class="description_important">
|
||||
// Необработанная загрузка — это загрузка скидок для <a
|
||||
// href="/openapi/promotion#tag/Kalendar-akcij">календаря акций</a>. Такие
|
||||
// скидки применятся к товарам только в момент начала
|
||||
// акции.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/buffer/goods/task
|
||||
APIV2BufferGoodsTaskGet(ctx context.Context, params APIV2BufferGoodsTaskGetParams) (APIV2BufferGoodsTaskGetRes, error)
|
||||
// APIV2BufferTasksGet implements GET /api/v2/buffer/tasks operation.
|
||||
//
|
||||
// Метод предоставляет информацию про загрузку скидок в
|
||||
// обработке.
|
||||
// <div class="description_important">
|
||||
// Необработанная загрузка — это загрузка скидок для <a
|
||||
// href="/openapi/promotion#tag/Kalendar-akcij">календаря акций</a>. Такие
|
||||
// скидки применятся к товарам только в момент начала
|
||||
// акции.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/buffer/tasks
|
||||
APIV2BufferTasksGet(ctx context.Context, params APIV2BufferTasksGetParams) (APIV2BufferTasksGetRes, error)
|
||||
// APIV2HistoryGoodsTaskGet implements GET /api/v2/history/goods/task operation.
|
||||
//
|
||||
// Метод предоставляет информацию о товарах и об
|
||||
// ошибках в товарах в обработанной загрузке.
|
||||
// <div class="description_important">
|
||||
// Обработанная загрузка — это загрузка цен и скидок
|
||||
// для <a
|
||||
// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post">товаров</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post">размеров товаров</a>, а также скидок <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post">WB Клуба</a>.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/history/goods/task
|
||||
APIV2HistoryGoodsTaskGet(ctx context.Context, params APIV2HistoryGoodsTaskGetParams) (APIV2HistoryGoodsTaskGetRes, error)
|
||||
// APIV2HistoryTasksGet implements GET /api/v2/history/tasks operation.
|
||||
//
|
||||
// Метод предоставляет информацию об обработанной
|
||||
// загрузке цен и скидок.
|
||||
// <div class="description_important">
|
||||
// Обработанная загрузка — это загрузка цен и скидок
|
||||
// для <a
|
||||
// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post">товаров</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post">размеров товаров</a>, а также скидок <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post">WB Клуба</a>.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/history/tasks
|
||||
APIV2HistoryTasksGet(ctx context.Context, params APIV2HistoryTasksGetParams) (APIV2HistoryTasksGetRes, error)
|
||||
// APIV2ListGoodsFilterGet implements GET /api/v2/list/goods/filter operation.
|
||||
//
|
||||
// Метод предоставляет информацию о товарах по их
|
||||
// артикулам: цены, валюту, общие скидки и скидки для [WB
|
||||
// Клуба](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post).
|
||||
// <br><br>
|
||||
// Чтобы получить информацию обо всех товарах продавца,
|
||||
// оставьте артикул пустым, установите `limit=1000`, в
|
||||
// параметре `offset` установите смещение по количеству
|
||||
// записей. Количество нужно рассчитать по формуле: `offset`
|
||||
// плюс `limit` из предыдущего запроса. Повторяйте запрос,
|
||||
// пока вы не получите ответ с пустым массивом.<br> Чтобы
|
||||
// получить информацию о размерах товара, используйте
|
||||
// [отдельный
|
||||
// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1size~1nm/get).
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/list/goods/filter
|
||||
APIV2ListGoodsFilterGet(ctx context.Context, params APIV2ListGoodsFilterGetParams) (APIV2ListGoodsFilterGetRes, error)
|
||||
// APIV2ListGoodsSizeNmGet implements GET /api/v2/list/goods/size/nm operation.
|
||||
//
|
||||
// Метод предоставляет информацию обо всех размерах
|
||||
// одного товарам: цены, валюту, общие скидки и скидки
|
||||
// для [WB
|
||||
// Клуба](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1club-discount/post).
|
||||
// <br><br>
|
||||
// Работает только для товаров из категорий, где можно
|
||||
// устанавливать цены отдельно для разных размеров. Для
|
||||
// таких товаров `editableSizePrice: true`.
|
||||
// <br><br>
|
||||
// Чтобы получить информацию о самом товаре,
|
||||
// используйте [отдельный
|
||||
// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1filter/get).
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/list/goods/size/nm
|
||||
APIV2ListGoodsSizeNmGet(ctx context.Context, params APIV2ListGoodsSizeNmGetParams) (APIV2ListGoodsSizeNmGetRes, error)
|
||||
// APIV2QuarantineGoodsGet implements GET /api/v2/quarantine/goods operation.
|
||||
//
|
||||
// Метод предоставляет информацию о товарах в карантине.
|
||||
// <br><br>
|
||||
// Если новая цена товара со скидкой будет минимум в 3
|
||||
// раза меньше старой, товар попадёт [в
|
||||
// карантин](https://seller.wildberries.ru/discount-and-prices/quarantine) и будет
|
||||
// продаваться по старой цене. Ошибка об этом будет в
|
||||
// ответах методов [состояний
|
||||
// загрузок](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get).
|
||||
// <br><br>
|
||||
// Вы можете изменить цену или скидку с помощью API либо
|
||||
// вывести товар из карантина [в личном
|
||||
// кабинете](https://seller.wildberries.ru/discount-and-prices/quarantine).
|
||||
// <br><br>
|
||||
// Для товаров с [поразмерной установкой
|
||||
// цен](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post)
|
||||
// карантин не применяется.
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v2/quarantine/goods
|
||||
APIV2QuarantineGoodsGet(ctx context.Context, params APIV2QuarantineGoodsGetParams) (APIV2QuarantineGoodsGetRes, error)
|
||||
// APIV2UploadTaskClubDiscountPost implements POST /api/v2/upload/task/club-discount operation.
|
||||
//
|
||||
// Устанавливает скидки для товаров в рамках подписки [WB
|
||||
// Клуб](https://seller.wildberries.ru/help-center/article/A-337).
|
||||
// <div class="description_important">
|
||||
// Получить информацию о процессе установки цен и
|
||||
// скидок можно с помощью методов <a
|
||||
// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get">состояния</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1goods~1task/get">детализации</a> обработанной загрузки.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// POST /api/v2/upload/task/club-discount
|
||||
APIV2UploadTaskClubDiscountPost(ctx context.Context, req *APIV2UploadTaskClubDiscountPostReq) (APIV2UploadTaskClubDiscountPostRes, error)
|
||||
// APIV2UploadTaskPost implements POST /api/v2/upload/task operation.
|
||||
//
|
||||
// Метод устанавливает цены и скидки для товаров.
|
||||
// <br><br>
|
||||
// Чтобы установить цены и скидки для размеров товара,
|
||||
// используйте [отдельный
|
||||
// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task~1size/post).
|
||||
// <div class="description_important">
|
||||
// Получить информацию о процессе установки цен и
|
||||
// скидок можно с помощью методов <a
|
||||
// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get">состояния</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1goods~1task/get">детализации</a> обработанной загрузки.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// POST /api/v2/upload/task
|
||||
APIV2UploadTaskPost(ctx context.Context, req *APIV2UploadTaskPostReq) (APIV2UploadTaskPostRes, error)
|
||||
// APIV2UploadTaskSizePost implements POST /api/v2/upload/task/size operation.
|
||||
//
|
||||
// Метод устанавливает цены отдельно для размеров
|
||||
// товаров.
|
||||
// Работает только для товаров из категорий, где можно
|
||||
// устанавливать цены отдельно для разных размеров. Для
|
||||
// [таких
|
||||
// товаров](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1list~1goods~1size~1nm/get) `editableSizePrice: true`.
|
||||
// Чтобы установить цены и скидки для самих товаров,
|
||||
// используйте [отдельный
|
||||
// метод](/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1upload~1task/post).
|
||||
// <div class="description_important">
|
||||
// Получить информацию о процессе установки цен и
|
||||
// скидок можно с помощью методов <a
|
||||
// href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1tasks/get">состояния</a> и <a href="/openapi/work-with-products#tag/Ceny-i-skidki/paths/~1api~1v2~1history~1goods~1task/get">детализации</a> обработанной загрузки.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 10 запросов за 6 <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">секунд</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Цены и скидки</a>
|
||||
// на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// POST /api/v2/upload/task/size
|
||||
APIV2UploadTaskSizePost(ctx context.Context, req *APIV2UploadTaskSizePostReq) (APIV2UploadTaskSizePostRes, error)
|
||||
// APIV3OfficesGet implements GET /api/v3/offices operation.
|
||||
//
|
||||
// Метод предоставляет список всех складов WB для
|
||||
// привязки к складам продавца. Предназначен для
|
||||
// определения складов WB, чтобы сдавать готовые заказы
|
||||
// по схеме [FBS](/openapi/orders-fbs#tag/Zakazy-FBS) (Fulfillment by Seller).
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v3/offices
|
||||
APIV3OfficesGet(ctx context.Context) (APIV3OfficesGetRes, error)
|
||||
// APIV3StocksWarehouseIdDelete implements DELETE /api/v3/stocks/{warehouseId} operation.
|
||||
//
|
||||
// Метод удаляет запись об остатках товаров продавца из
|
||||
// [списка
|
||||
// остатков](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post).
|
||||
// <div class="description_important">
|
||||
// <strong>Действие необратимо</strong>. Удаленный остаток
|
||||
// будет необходимо загрузить повторно для
|
||||
// возобновления продаж.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// DELETE /api/v3/stocks/{warehouseId}
|
||||
APIV3StocksWarehouseIdDelete(ctx context.Context, req *APIV3StocksWarehouseIdDeleteReq, params APIV3StocksWarehouseIdDeleteParams) (APIV3StocksWarehouseIdDeleteRes, error)
|
||||
// APIV3StocksWarehouseIdPost implements POST /api/v3/stocks/{warehouseId} operation.
|
||||
//
|
||||
// Метод предоставляет данные об остатках товаров на
|
||||
// [складах продавца](/openapi/work-with-products#tag/Sklady-prodavca).
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// POST /api/v3/stocks/{warehouseId}
|
||||
APIV3StocksWarehouseIdPost(ctx context.Context, req *APIV3StocksWarehouseIdPostReq, params APIV3StocksWarehouseIdPostParams) (APIV3StocksWarehouseIdPostRes, error)
|
||||
// APIV3StocksWarehouseIdPut implements PUT /api/v3/stocks/{warehouseId} operation.
|
||||
//
|
||||
// Метод обновляет количество остатков товаров
|
||||
// продавца [в
|
||||
// списке](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post).
|
||||
// <div class="description_important">
|
||||
// Названия параметров запроса не валидируются. При
|
||||
// отправке некорректных названий вы получите успешный
|
||||
// ответ (<code>204</code>), но остатки не обновятся.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// PUT /api/v3/stocks/{warehouseId}
|
||||
APIV3StocksWarehouseIdPut(ctx context.Context, req OptAPIV3StocksWarehouseIdPutReq, params APIV3StocksWarehouseIdPutParams) (APIV3StocksWarehouseIdPutRes, error)
|
||||
// APIV3WarehousesGet implements GET /api/v3/warehouses operation.
|
||||
//
|
||||
// Метод предоставляет список всех складов продавца.
|
||||
// Может использоваться для получения [остатков
|
||||
// товаров](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post).
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// GET /api/v3/warehouses
|
||||
APIV3WarehousesGet(ctx context.Context) (APIV3WarehousesGetRes, error)
|
||||
// APIV3WarehousesPost implements POST /api/v3/warehouses operation.
|
||||
//
|
||||
// Метод создаёт склад продавца для работы с [остатками
|
||||
// товаров](/openapi/work-with-products#tag/Ostatki-na-skladah-prodavca/paths/~1api~1v3~1stocks~1%7BwarehouseId%7D/post). Нужно привязать к складу продавца [склад WB](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1offices/get) для работы по схеме [FBS](/openapi/orders-fbs#tag/Zakazy-FBS) (Fulfillment by Seller).
|
||||
// <div class="description_important">
|
||||
// Нельзя привязывать склад WB, который уже используется
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// POST /api/v3/warehouses
|
||||
APIV3WarehousesPost(ctx context.Context, req *APIV3WarehousesPostReq) (APIV3WarehousesPostRes, error)
|
||||
// APIV3WarehousesWarehouseIdDelete implements DELETE /api/v3/warehouses/{warehouseId} operation.
|
||||
//
|
||||
// Метод удаляет склад продавца из [списка
|
||||
// складов](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1warehouses/get).
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// DELETE /api/v3/warehouses/{warehouseId}
|
||||
APIV3WarehousesWarehouseIdDelete(ctx context.Context, params APIV3WarehousesWarehouseIdDeleteParams) (APIV3WarehousesWarehouseIdDeleteRes, error)
|
||||
// APIV3WarehousesWarehouseIdPut implements PUT /api/v3/warehouses/{warehouseId} operation.
|
||||
//
|
||||
// Метод обновляет данные склада продавца в [списке
|
||||
// складов](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1warehouses/get).
|
||||
// Данные о привязанном [складе
|
||||
// WB](/openapi/work-with-products#tag/Sklady-prodavca/paths/~1api~1v3~1offices/get) можно
|
||||
// изменить один раз в сутки.
|
||||
// <div class="description_important">
|
||||
// Нельзя привязывать склад WB, который уже используется
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 300 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Маркетплейс</a> на
|
||||
// один аккаунт продавца.
|
||||
// <br><br>
|
||||
// Один запрос с кодом ответа <code>409</code> учитывается как 5
|
||||
// запросов
|
||||
// </div>.
|
||||
//
|
||||
// PUT /api/v3/warehouses/{warehouseId}
|
||||
APIV3WarehousesWarehouseIdPut(ctx context.Context, req *APIV3WarehousesWarehouseIdPutReq, params APIV3WarehousesWarehouseIdPutParams) (APIV3WarehousesWarehouseIdPutRes, error)
|
||||
// ContentV2BarcodesPost implements POST /content/v2/barcodes operation.
|
||||
//
|
||||
// Метод генерирует массив уникальных баркодов для
|
||||
// создания размера в [карточке
|
||||
// товара](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post). Можно использовать, если у вас нет собственных баркодов.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/barcodes
|
||||
ContentV2BarcodesPost(ctx context.Context, req *ContentV2BarcodesPostReq) (ContentV2BarcodesPostRes, error)
|
||||
// ContentV2CardsDeleteTrashPost implements POST /content/v2/cards/delete/trash operation.
|
||||
//
|
||||
// Метод переносит [карточки товаров в
|
||||
// корзину](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post). При этом карточки товаров не удаляются, их можно [восстановить](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1recover/post).
|
||||
// <div class="description_important">
|
||||
// После переноса в корзину карточке товара
|
||||
// присваивается новый <code>imtID</code>.
|
||||
// </div>
|
||||
// Карточки товаров удаляются автоматически, если лежат
|
||||
// в корзине больше 30 дней. Очистка корзины происходит
|
||||
// каждую ночь по московскому времени.<br>
|
||||
// Карточки товаров можно удалить в любое время в
|
||||
// [личном кабинете](https://seller.wildberries.ru/new-goods/basket-cards).
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/cards/delete/trash
|
||||
ContentV2CardsDeleteTrashPost(ctx context.Context, req *ContentV2CardsDeleteTrashPostReq) (ContentV2CardsDeleteTrashPostRes, error)
|
||||
// ContentV2CardsErrorListGet implements GET /content/v2/cards/error/list operation.
|
||||
//
|
||||
// Метод предоставляет список карточек товаров, при
|
||||
// создании или редактировании которых произошли
|
||||
// ошибки, с описанием этих ошибок.
|
||||
// <div class="description_important">
|
||||
// Чтобы убрать карточку товара из списка, нужно
|
||||
// повторно сделать запрос на <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создание</a> или редактирование карточки товара с исправленными ошибками.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/cards/error/list
|
||||
ContentV2CardsErrorListGet(ctx context.Context, params ContentV2CardsErrorListGetParams) (ContentV2CardsErrorListGetRes, error)
|
||||
// ContentV2CardsLimitsGet implements GET /content/v2/cards/limits operation.
|
||||
//
|
||||
// Возвращает бесплатные и платные лимиты продавца на
|
||||
// [создание карточек
|
||||
// товаров](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post).<br><br>
|
||||
// Формула для получения количества карточек, которые
|
||||
// можно создать:
|
||||
// > (`freeLimits` + `paidLimits`) - количество созданных карточек
|
||||
// Созданными считаются карточки, которые можно
|
||||
// получить через методы [список карточек
|
||||
// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1list/post) и [список карточек товаров в корзине](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post).
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/cards/limits
|
||||
ContentV2CardsLimitsGet(ctx context.Context) (ContentV2CardsLimitsGetRes, error)
|
||||
// ContentV2CardsRecoverPost implements POST /content/v2/cards/recover operation.
|
||||
//
|
||||
// Метод восстанавливает [карточки товаров из
|
||||
// корзины](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post).
|
||||
// <div class="description_important">
|
||||
// Карточка товара сохраняет тот же <code>imtID</code>, что был
|
||||
// присвоен ей при <a
|
||||
// href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1delete~1trash/post">перемещении в корзину</a>.
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/cards/recover
|
||||
ContentV2CardsRecoverPost(ctx context.Context, req *ContentV2CardsRecoverPostReq) (ContentV2CardsRecoverPostRes, error)
|
||||
// ContentV2CardsUpdatePost implements POST /content/v2/cards/update operation.
|
||||
//
|
||||
// Метод обновляет карточки товаров. Данные для
|
||||
// обновления можно получить через [список карточек
|
||||
// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1list/post) и [список карточек товаров в корзине](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post).
|
||||
// <div class="description_important">
|
||||
// Карточка товара перезаписывается при обновлении.
|
||||
// Поэтому в запросе нужно передать <strong>все</strong>
|
||||
// параметры карточки, в том числе те, которые вы не
|
||||
// собираетесь обновлять.
|
||||
// </div>
|
||||
// Нельзя редактировать или удалять баркоды, но можно
|
||||
// добавить дополнительный баркод к карточке товара.
|
||||
// Параметры `photos`, `video` и `tags` редактировать или удалять
|
||||
// через данный метод нельзя.<br>
|
||||
// Габариты товаров можно указать только в `сантиметрах`,
|
||||
// вес товара с упаковкой — в `килограммах`.
|
||||
// <br><br>
|
||||
// В одном запросе можно отредактировать максимум 3000
|
||||
// карточек товаров (`nmID`). Максимальный размер запроса 10
|
||||
// Мб.<br>
|
||||
// Если ответ `Успешно` (`200`), но какие-то карточки не
|
||||
// обновились, получите [список несозданных карточек
|
||||
// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get).
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня для метода будет отдельный
|
||||
// лимит — 10 запросов в минуту на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/cards/update
|
||||
ContentV2CardsUpdatePost(ctx context.Context, req []ContentV2CardsUpdatePostReqItem) (ContentV2CardsUpdatePostRes, error)
|
||||
// ContentV2CardsUploadAddPost implements POST /content/v2/cards/upload/add operation.
|
||||
//
|
||||
// Метод создаёт новые карточки товаров, присоединяя их
|
||||
// к существующим карточкам.
|
||||
// Габариты товаров можно указать только в `сантиметрах`,
|
||||
// вес товара с упаковкой — в `килограммах`.
|
||||
// <br><br>
|
||||
// Создание карточки товара происходит асинхронно.
|
||||
// После отправки запрос становится в очередь на
|
||||
// обработку.<br>Максимальный размер запроса 10 Мб.<br>
|
||||
// Если ответ `Успешно` (`200`), но какие-то карточки не
|
||||
// обновились, получите [список несозданных карточек
|
||||
// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get).
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня для метода будет отдельный
|
||||
// лимит — 10 запросов в минуту на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/cards/upload/add
|
||||
ContentV2CardsUploadAddPost(ctx context.Context, req OptContentV2CardsUploadAddPostReq) (ContentV2CardsUploadAddPostRes, error)
|
||||
// ContentV2CardsUploadPost implements POST /content/v2/cards/upload operation.
|
||||
//
|
||||
// Метод создаёт карточки товаров c указанием описаний и
|
||||
// характеристик товаров.<br>
|
||||
// <div class="description_important">
|
||||
// Есть две формы запроса: для создания отдельных и
|
||||
// объединённых карточек товаров.
|
||||
// </div>
|
||||
// Габариты товаров можно указать только в `сантиметрах`,
|
||||
// вес товара с упаковкой — в `килограммах`.
|
||||
// <br><br>
|
||||
// Создание карточки товара происходит асинхронно.
|
||||
// После отправки запрос становится в очередь на
|
||||
// обработку.<br>
|
||||
// В одном запросе можно создать максимум 100
|
||||
// объединённых карточек товаров (`imtID`), по 30 карточек
|
||||
// товаров в каждой. Максимальный размер запроса 10 Мб.<br>
|
||||
// Если ответ `Успешно` (`200`), но какие-то карточки не
|
||||
// обновились, получите [список несозданных карточек
|
||||
// товаров](/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1error~1list/get).
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня для метода будет отдельный
|
||||
// лимит — 10 запросов в минуту на один аккаунт продавца
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/cards/upload
|
||||
ContentV2CardsUploadPost(ctx context.Context, req []ContentV2CardsUploadPostReqItem) (ContentV2CardsUploadPostRes, error)
|
||||
// ContentV2DirectoryColorsGet implements GET /content/v2/directory/colors operation.
|
||||
//
|
||||
// Метод предоставляет возможные значения
|
||||
// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Цвет`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/directory/colors
|
||||
ContentV2DirectoryColorsGet(ctx context.Context, params ContentV2DirectoryColorsGetParams) (ContentV2DirectoryColorsGetRes, error)
|
||||
// ContentV2DirectoryCountriesGet implements GET /content/v2/directory/countries operation.
|
||||
//
|
||||
// Метод предоставляет возможные значения
|
||||
// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Страна производства`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/directory/countries
|
||||
ContentV2DirectoryCountriesGet(ctx context.Context, params ContentV2DirectoryCountriesGetParams) (ContentV2DirectoryCountriesGetRes, error)
|
||||
// ContentV2DirectoryKindsGet implements GET /content/v2/directory/kinds operation.
|
||||
//
|
||||
// Метод предоставляет возможные значения
|
||||
// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Пол`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/directory/kinds
|
||||
ContentV2DirectoryKindsGet(ctx context.Context, params ContentV2DirectoryKindsGetParams) (ContentV2DirectoryKindsGetRes, error)
|
||||
// ContentV2DirectorySeasonsGet implements GET /content/v2/directory/seasons operation.
|
||||
//
|
||||
// Метод предоставляет возможные значения
|
||||
// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Сезон`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/directory/seasons
|
||||
ContentV2DirectorySeasonsGet(ctx context.Context, params ContentV2DirectorySeasonsGetParams) (ContentV2DirectorySeasonsGetRes, error)
|
||||
// ContentV2DirectoryTnvedGet implements GET /content/v2/directory/tnved operation.
|
||||
//
|
||||
// Метод предоставляет список ТНВЭД-кодов по ID
|
||||
// [предмета](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1all/get) и фрагменту ТНВЭД-кода.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/directory/tnved
|
||||
ContentV2DirectoryTnvedGet(ctx context.Context, params ContentV2DirectoryTnvedGetParams) (ContentV2DirectoryTnvedGetRes, error)
|
||||
// ContentV2DirectoryVatGet implements GET /content/v2/directory/vat operation.
|
||||
//
|
||||
// Метод предоставляет возможные значения
|
||||
// [характеристики](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1charcs~1%7BsubjectId%7D/get) предмета `Ставка НДС`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/directory/vat
|
||||
ContentV2DirectoryVatGet(ctx context.Context, params ContentV2DirectoryVatGetParams) (ContentV2DirectoryVatGetRes, error)
|
||||
// ContentV2GetCardsListPost implements POST /content/v2/get/cards/list operation.
|
||||
//
|
||||
// <div class="description_auth">
|
||||
// Метод доступен по <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">токену</a> с
|
||||
// категорией <strong>Контент</strong> или <strong>Продвижение</strong>
|
||||
// </div>
|
||||
// Метод предоставляет список созданных карточек
|
||||
// товаров.
|
||||
// <div class="description_important">
|
||||
// В ответе метода не будет карточек, находящихся в
|
||||
// корзине. Получить такие карточки можно через <a
|
||||
// href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1get~1cards~1trash/post">отдельный метод</a>.
|
||||
// </div>
|
||||
// Чтобы получить **больше 100** карточек товаров,
|
||||
// воспользуйтесь пагинацией:
|
||||
// <ol>
|
||||
// <li>Сделайте первый запрос: <br>
|
||||
// <pre style="background-color: rgb(38 50 56 / 5%); color: #e53935">
|
||||
// {
|
||||
// "settings": {
|
||||
// "cursor": {
|
||||
// "limit": 100
|
||||
// },
|
||||
// "filter": {
|
||||
// "withPhoto": -1
|
||||
// }
|
||||
// }
|
||||
// }</pre>
|
||||
// </li>
|
||||
// <li>Пройдите в конец полученного списка карточек
|
||||
// товаров.</li>
|
||||
// <li>Скопируйте из <code>cursor</code> две строки:
|
||||
// <ul>
|
||||
// <li><code>"updatedAt": "***"</code></li>
|
||||
// <li><code>"nmID": ***</code></li>
|
||||
// </ul></li>
|
||||
// <li>Вставьте скопированные строки в параметр запроса
|
||||
// <code>cursor</code>.</li>
|
||||
// <li>Повторите запрос. </li>
|
||||
// <li>Повторяйте пункты со <b>2</b> по <b>5</b>, пока поле
|
||||
// <code>total</code> в ответе не станет меньше чем параметр
|
||||
// <code>limit</code> в запросе. Это будет означать, что вы
|
||||
// получили все карточки.
|
||||
// </ol>
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/get/cards/list
|
||||
ContentV2GetCardsListPost(ctx context.Context, req *ContentV2GetCardsListPostReq, params ContentV2GetCardsListPostParams) (ContentV2GetCardsListPostRes, error)
|
||||
// ContentV2GetCardsTrashPost implements POST /content/v2/get/cards/trash operation.
|
||||
//
|
||||
// <div class="description_auth">
|
||||
// Метод доступен по <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">токену</a> с
|
||||
// категорией <strong>Контент</strong> или <strong>Продвижение</strong>
|
||||
// </div>
|
||||
// Метод предоставляет список карточек товаров в
|
||||
// корзине.<br><br>
|
||||
// Чтобы получить **больше 100** карточек товаров,
|
||||
// воспользуйтесь пагинацией:
|
||||
// <ol>
|
||||
// <li>Сделайте первый запрос: <br>
|
||||
// <pre style="background-color: rgb(38 50 56 / 5%); color: #e53935">
|
||||
// {
|
||||
// "settings": {
|
||||
// "cursor": {
|
||||
// "limit": 100
|
||||
// },
|
||||
// "filter": {
|
||||
// "withPhoto": -1
|
||||
// }
|
||||
// }
|
||||
// }</pre>
|
||||
// </li>
|
||||
// <li>Пройдите в конец полученного списка карточек
|
||||
// товаров.</li>
|
||||
// <li>Скопируйте из <code>cursor</code> две строки:
|
||||
// <ul>
|
||||
// <li><code>"trashedAt": "***"</code></li>
|
||||
// <li><code>"nmID": ***</code></li>
|
||||
// </ul></li>
|
||||
// <li>Вставьте скопированные строки в параметр запроса
|
||||
// <code>cursor</code>.</li>
|
||||
// <li>Повторите запрос. </li>
|
||||
// <li>Повторяйте пункты со <b>2</b> по <b>5</b>, пока поле
|
||||
// <code>total</code> в ответе не станет меньше чем параметр
|
||||
// <code>limit</code> в запросе. Это будет означать, что вы
|
||||
// получили все карточки.
|
||||
// </ol>
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/get/cards/trash
|
||||
ContentV2GetCardsTrashPost(ctx context.Context, req *ContentV2GetCardsTrashPostReq, params ContentV2GetCardsTrashPostParams) (ContentV2GetCardsTrashPostRes, error)
|
||||
// ContentV2ObjectAllGet implements GET /content/v2/object/all operation.
|
||||
//
|
||||
// Метод предоставляет список названий [родительских
|
||||
// категорий
|
||||
// предметов](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1parent~1all/get) и их предметов с ID. Например, у категории `Игрушки` будут предметы `Калейдоскопы`, `Куклы`, `Мячики`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/object/all
|
||||
ContentV2ObjectAllGet(ctx context.Context, params ContentV2ObjectAllGetParams) (ContentV2ObjectAllGetRes, error)
|
||||
// ContentV2ObjectCharcsSubjectIdGet implements GET /content/v2/object/charcs/{subjectId} operation.
|
||||
//
|
||||
// Метод предоставляет параметры характеристик
|
||||
// предмета: названия, типы данных, единицы измерения и
|
||||
// так далее. В запросе необходимо указать ID
|
||||
// [предмета](/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1object~1all/get).
|
||||
// <div class="description_important">
|
||||
// Для получения характеристик <a
|
||||
// href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1colors/get">Цвет</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1kinds/get">Пол</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1countries/get">Страна производства</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1seasons/get">Сезон</a>, <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1vat/get">Ставка НДС</a> и <a href="/openapi/work-with-products#tag/Kategorii-predmety-i-harakteristiki/paths/~1content~1v2~1directory~1tnved/get">ТНВЭД-код</a> используйте отдельные методы
|
||||
// </div>
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/object/charcs/{subjectId}
|
||||
ContentV2ObjectCharcsSubjectIdGet(ctx context.Context, params ContentV2ObjectCharcsSubjectIdGetParams) (ContentV2ObjectCharcsSubjectIdGetRes, error)
|
||||
// ContentV2ObjectParentAllGet implements GET /content/v2/object/parent/all operation.
|
||||
//
|
||||
// Метод предоставляет названия и ID всех родительских
|
||||
// категорий для [создания карточек
|
||||
// товаров](/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov): например,
|
||||
// `Электроника`, `Бытовая химия`, `Рукоделие`.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/object/parent/all
|
||||
ContentV2ObjectParentAllGet(ctx context.Context, params ContentV2ObjectParentAllGetParams) (ContentV2ObjectParentAllGetRes, error)
|
||||
// ContentV2TagNomenclatureLinkPost implements POST /content/v2/tag/nomenclature/link operation.
|
||||
//
|
||||
// Метод добавляет или снимает ярлык с карточки товара.
|
||||
// К карточке можно добавить максимум 15 ярлыков.<br>
|
||||
// При удалении ярлыка из карточки товара он не
|
||||
// удаляется из [списка
|
||||
// ярлыков](/openapi/work-with-products#tag/Yarlyki/paths/~1content~1v2~1tags/get)
|
||||
// продавца.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v2/tag/nomenclature/link
|
||||
ContentV2TagNomenclatureLinkPost(ctx context.Context, req *ContentV2TagNomenclatureLinkPostReq) (ContentV2TagNomenclatureLinkPostRes, error)
|
||||
// ContentV2TagsGet implements GET /content/v2/tags operation.
|
||||
//
|
||||
// Метод предоставляет список и характеристики всех
|
||||
// ярлыков продавца для группировки и фильтрации
|
||||
// товаров.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// GET /content/v2/tags
|
||||
ContentV2TagsGet(ctx context.Context) (ContentV2TagsGetRes, error)
|
||||
// ContentV3MediaFilePost implements POST /content/v3/media/file operation.
|
||||
//
|
||||
// Метод загружает и добавляет один медиафайл к
|
||||
// карточке товара.
|
||||
// Требования к изображениям:
|
||||
// * максимум изображений для одной карточки товара — 30
|
||||
// * минимальное разрешение — 700x900 px
|
||||
// * максимальный размер — 32 Мб
|
||||
// * минимальное качество — 65%
|
||||
// * форматы — JPG, PNG, BMP, GIF (статичные), WebP
|
||||
// Требования к видео:
|
||||
// * максимум одно видео для одной карточки товара
|
||||
// * максимальный размер — 50 Мб
|
||||
// * форматы — MOV, MP4
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v3/media/file
|
||||
ContentV3MediaFilePost(ctx context.Context, req *ContentV3MediaFilePostReq, params ContentV3MediaFilePostParams) (ContentV3MediaFilePostRes, error)
|
||||
// ContentV3MediaSavePost implements POST /content/v3/media/save operation.
|
||||
//
|
||||
// Метод загружает набор медиафайлов в карточку товара
|
||||
// через указание ссылок в запросе.
|
||||
// <div class="description_important">
|
||||
// Новые медиафайлы полностью заменяют старые. Чтобы
|
||||
// добавить новые медиафайлы, укажите в запросе ссылки
|
||||
// одновременно на новые и старые медиафайлы.
|
||||
// </div>
|
||||
// Требования к изображениям:
|
||||
// * максимум изображений для одной карточки товара — 30
|
||||
// * минимальное разрешение — 700×900 px
|
||||
// * максимальный размер — 32 Мб
|
||||
// * минимальное качество — 65%
|
||||
// * форматы — JPG, PNG, BMP, GIF (статичные), WebP
|
||||
// Требования к видео:
|
||||
// * максимум одно видео для одной карточки товара
|
||||
// * максимальный размер — 50 Мб
|
||||
// * форматы — MOV, MP4
|
||||
// Если видео или хотя бы одно изображение в запросе не
|
||||
// соответствует требованиям, то даже при успешном
|
||||
// ответе ни одно изображение/видео не загрузится.
|
||||
// <div class="description_limit">
|
||||
// Максимум 100 запросов в <a
|
||||
// href="/openapi/api-information#tag/Vvedenie/Limity-zaprosov">минуту</a> для всех
|
||||
// методов категории <a
|
||||
// href="/openapi/api-information#tag/Avtorizaciya/Kak-sozdat-token">Контент</a> на один
|
||||
// аккаунт продавца. С 5 июня — за исключением методов <a
|
||||
// href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload/post">создания</a>, <a href="/openapi/work-with-products#tag/Sozdanie-kartochek-tovarov/paths/~1content~1v2~1cards~1upload~1add/post">создания с присоединением</a> и <a href="/openapi/work-with-products#tag/Kartochki-tovarov/paths/~1content~1v2~1cards~1update/post">редактирования</a> карточек товаров
|
||||
// </div>.
|
||||
//
|
||||
// POST /content/v3/media/save
|
||||
ContentV3MediaSavePost(ctx context.Context, req *ContentV3MediaSavePostReq) (ContentV3MediaSavePostRes, error)
|
||||
}
|
||||
|
||||
// Server implements http server based on OpenAPI v3 specification and
|
||||
// calls Handler to handle requests.
|
||||
type Server struct {
|
||||
h Handler
|
||||
sec SecurityHandler
|
||||
baseServer
|
||||
}
|
||||
|
||||
// NewServer creates new Server.
|
||||
func NewServer(h Handler, sec SecurityHandler, opts ...ServerOption) (*Server, error) {
|
||||
s, err := newServerConfig(opts...).baseServer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Server{
|
||||
h: h,
|
||||
sec: sec,
|
||||
baseServer: s,
|
||||
}, nil
|
||||
}
|
||||
1062
pkg/api/wb/client/oas_unimplemented_gen.go
Normal file
1062
pkg/api/wb/client/oas_unimplemented_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
1661
pkg/api/wb/client/oas_validators_gen.go
Normal file
1661
pkg/api/wb/client/oas_validators_gen.go
Normal file
File diff suppressed because it is too large
Load Diff
3
pkg/api/wb/generate.go
Normal file
3
pkg/api/wb/generate.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package wb
|
||||
|
||||
//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target client --clean 02-products.yaml
|
||||
7
pkg/api/wb/ogen.yml
Normal file
7
pkg/api/wb/ogen.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
generator:
|
||||
ignore_not_implemented: [ "all" ]
|
||||
content_type_aliases:
|
||||
"application/problem+json": "application/json"
|
||||
features:
|
||||
enable:
|
||||
- 'client/security/reentrant'
|
||||
Reference in New Issue
Block a user