From 7491635a7582c17c3d92e87b603e44743508b9f8 Mon Sep 17 00:00:00 2001
From: WuYuuuub <625806558@qq.com>
Date: Sun, 29 Mar 2026 11:50:43 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4?=
=?UTF-8?q?=E4=BA=91=E5=8D=B0=E4=BA=AB=E4=BB=98=E8=B4=B9=E6=89=93=E5=8D=B0?=
=?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=90=8E=E7=AB=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
architecture-design.md | 801 +++
cloudprint-backend/README.md | 236 +
cloudprint-backend/cmd/server/main.go | 163 +
cloudprint-backend/config/config.go | 98 +
cloudprint-backend/docs/openapi.yaml | 1132 ++++
cloudprint-backend/go.mod | 43 +
cloudprint-backend/go.sum | 303 ++
.../internal/grpc/interceptor/auth.go | 125 +
cloudprint-backend/internal/grpc/server.go | 92 +
.../internal/grpc/service/admin_service.go | 68 +
.../internal/grpc/service/auth_service.go | 63 +
.../internal/grpc/service/file_service.go | 141 +
.../internal/grpc/service/library_service.go | 91 +
.../internal/grpc/service/order_service.go | 98 +
.../internal/grpc/service/pay_service.go | 201 +
.../internal/grpc/service/price_service.go | 96 +
.../internal/grpc/service/print_service.go | 136 +
cloudprint-backend/internal/model/model.go | 224 +
.../internal/repository/admin_repository.go | 49 +
.../internal/repository/file_repository.go | 67 +
.../internal/repository/library_repository.go | 108 +
.../internal/repository/order_repository.go | 162 +
.../internal/repository/price_repository.go | 80 +
.../internal/repository/printer_repository.go | 150 +
.../internal/repository/user_repository.go | 64 +
.../internal/service/auth_service.go | 189 +
.../internal/service/file_service.go | 105 +
.../internal/service/order_service.go | 218 +
.../internal/service/print_service.go | 194 +
cloudprint-backend/pkg/jwt/jwt.go | 105 +
cloudprint-backend/pkg/pay/wechat.go | 200 +
cloudprint-backend/pkg/upload/upload.go | 196 +
cloudprint-backend/proto/cloudprint.proto | 502 ++
.../proto/generated/cloudprint.pb.go | 4785 +++++++++++++++++
.../proto/generated/cloudprint_grpc.pb.go | 1856 +++++++
cloudprint-backend/scripts/db.sql | 182 +
36 files changed, 13323 insertions(+)
create mode 100644 architecture-design.md
create mode 100644 cloudprint-backend/README.md
create mode 100644 cloudprint-backend/cmd/server/main.go
create mode 100644 cloudprint-backend/config/config.go
create mode 100644 cloudprint-backend/docs/openapi.yaml
create mode 100644 cloudprint-backend/go.mod
create mode 100644 cloudprint-backend/go.sum
create mode 100644 cloudprint-backend/internal/grpc/interceptor/auth.go
create mode 100644 cloudprint-backend/internal/grpc/server.go
create mode 100644 cloudprint-backend/internal/grpc/service/admin_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/auth_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/file_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/library_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/order_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/pay_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/price_service.go
create mode 100644 cloudprint-backend/internal/grpc/service/print_service.go
create mode 100644 cloudprint-backend/internal/model/model.go
create mode 100644 cloudprint-backend/internal/repository/admin_repository.go
create mode 100644 cloudprint-backend/internal/repository/file_repository.go
create mode 100644 cloudprint-backend/internal/repository/library_repository.go
create mode 100644 cloudprint-backend/internal/repository/order_repository.go
create mode 100644 cloudprint-backend/internal/repository/price_repository.go
create mode 100644 cloudprint-backend/internal/repository/printer_repository.go
create mode 100644 cloudprint-backend/internal/repository/user_repository.go
create mode 100644 cloudprint-backend/internal/service/auth_service.go
create mode 100644 cloudprint-backend/internal/service/file_service.go
create mode 100644 cloudprint-backend/internal/service/order_service.go
create mode 100644 cloudprint-backend/internal/service/print_service.go
create mode 100644 cloudprint-backend/pkg/jwt/jwt.go
create mode 100644 cloudprint-backend/pkg/pay/wechat.go
create mode 100644 cloudprint-backend/pkg/upload/upload.go
create mode 100644 cloudprint-backend/proto/cloudprint.proto
create mode 100644 cloudprint-backend/proto/generated/cloudprint.pb.go
create mode 100644 cloudprint-backend/proto/generated/cloudprint_grpc.pb.go
create mode 100644 cloudprint-backend/scripts/db.sql
diff --git a/architecture-design.md b/architecture-design.md
new file mode 100644
index 0000000..2f600cb
--- /dev/null
+++ b/architecture-design.md
@@ -0,0 +1,801 @@
+99# 云印享 - 付费打印服务系统架构设计
+
+## 1. 项目概述
+
+### 1.1 项目背景
+构建一个提供付费打印服务的微信小程序系统,用户可通过小程序上传文档/图片/压缩包,选择打印机并完成打印。系统包含用户端小程序、管理员端(Windows客户端)和后端服务。
+
+### 1.2 核心功能需求
+
+| 模块 | 功能点 |
+|------|--------|
+| 用户端小程序 | 上传文件(文档/图片/压缩包)、价目表展示、选择打印机、文件编辑(预览/水印/合并)、聊天记录选择文件、打印订单管理 |
+| 管理员端 | 文库管理(上传资料供用户打印)、订单处理、打印机管理、用户管理 |
+| 后端服务 | 用户认证、文件存储、订单处理、API网关 |
+| Windows客户端 | 调用Windows API连接打印机、执行打印任务、文件预处理 |
+
+### 1.3 技术栈
+
+- **小程序端**:Taro(跨平台框架)+ React技术栈
+- **后端**:Go + gRPC + MySQL + go-pay(微信支付)
+- **Windows客户端**:C# (.NET 8) + WPF
+- **管理后台**:React + Ant Design(网页端)
+- **文件存储**:本地存储 + MinIO(可选)
+- **通信**:gRPC + WebSocket
+
+---
+
+## 2. 系统架构
+
+### 2.1 整体架构图
+
+```mermaid
+flowchart TB
+ subgraph Client["客户端层"]
+ MiniApp["Taro微信小程序
用户端"]
+ AdminWeb["React管理后台
网页端"]
+ end
+
+ subgraph Backend["后端服务层"]
+ GRPC["gRPC Gateway
:8080"]
+ Auth["认证服务"]
+ File["文件服务"]
+ Order["订单服务"]
+ Print["打印服务"]
+ Pay["支付服务
go-pay"]
+ end
+
+ subgraph Data["数据层"]
+ MySQL["MySQL
数据库"]
+ Redis["Redis
缓存"]
+ MinIO["MinIO
文件存储"]
+ end
+
+ subgraph PrintShop["打印店内部署"]
+ WinClient["C# WPF客户端
打印管理程序"]
+ Printers["打印机列表"]
+ LocalFiles["本地文库"]
+ end
+
+ MiniApp -->|"HTTPS/gRPC"| GRPC
+ AdminWeb -->|"HTTPS/gRPC"| GRPC
+ WinClient -->|"gRPC| WebSocket"| GRPC
+
+ GRPC --> Auth
+ GRPC --> File
+ GRPC --> Order
+ GRPC --> Print
+ GRPC --> Pay
+
+ Auth --> Redis
+ Order --> MySQL
+ File --> MinIO
+ File --> MySQL
+ Pay --> WeChat["微信支付"]
+
+ WinClient --> Printers
+ WinClient --> LocalFiles
+```
+
+### 2.2 部署架构
+
+```mermaid
+flowchart LR
+ subgraph Internet["互联网"]
+ User["用户
微信小程序"]
+ end
+
+ subgraph Cloud["云服务器"]
+ API_Server["Go API Server"]
+ DB["MySQL + Redis"]
+ File_Storage["文件存储服务"]
+ end
+
+ subgraph Local["打印店本地"]
+ PC["Windows电脑
C# WPF客户端"]
+ Printer["打印机"]
+ end
+
+ User -->|"上传文件/下单"| Cloud
+ Cloud -->|"转发打印任务"| PC
+ PC -->|"执行打印"| Printer
+```
+
+---
+
+## 3. 模块详细设计
+
+### 3.1 微信小程序端
+
+#### 3.1.1 页面结构
+
+```
+pages/
+├── index/ # 首页
+│ ├──价目表展示
+│ ├──快捷上传入口
+│ └──最近的打印历史
+├── upload/ # 文件上传
+│ ├──文件选择(支持聊天记录)
+│ ├──上传进度
+│ └──文件预览
+├── editor/ # 文件编辑
+│ ├──PDF预览
+│ ├──水印设置
+│ ├──页面合并
+│ └──打印参数设置
+├── printer/ # 打印机选择
+│ ├──打印机列表
+│ ├──打印机状态
+│ └──价格显示
+├── order/ # 订单管理
+│ ├──订单列表
+│ ├──订单详情
+│ └──支付
+├── library/ # 文库(用户浏览)
+│ ├──分类列表
+│ ├──文件搜索
+│ └──文件详情
+└── my/ # 个人中心
+ ├──打印记录
+ ├──账户余额
+ └──设置
+```
+
+#### 3.1.2 核心页面流程
+
+```mermaid
+flowchart TD
+ Start["首页"] --> Upload{"选择上传方式"}
+ Upload -->|"本地上传"| SelectFile["选择文件"]
+ Upload -->|"聊天记录"| ChatFile["从聊天选择"]
+ SelectFile --> Preview["文件预览"]
+ ChatFile --> Preview
+ Preview --> Edit{"需要编辑?"}
+ Edit -->|"是"| Editor["编辑页面"]
+ Edit -->|"否"| SelectPrinter["选择打印机"]
+ Editor --> SelectPrinter
+ SelectPrinter --> Confirm["确认订单"]
+ Confirm --> Pay["支付"]
+ Pay --> Success["下单成功"]
+ Success --> Notify["通知打印店"]
+```
+
+#### 3.1.3 文件编辑功能设计
+
+| 功能 | 实现方式 | 说明 |
+|------|----------|------|
+| PDF预览 | pdf.js | 轻量级PDF预览,支持缩放、翻页 |
+| 添加水印 | 前端Canvas + 后端PDF处理 | 支持文字水印、位置、透明度 |
+| 页面合并 | pdf-lib | 合并多个PDF页面 |
+| 打印参数 | 份数、纸张大小、单双面、彩色/黑白 | 传递给Windows客户端 |
+
+### 3.2 C# WPF打印客户端
+
+#### 3.2.1 核心模块
+
+```csharp
+// 项目结构
+CloudPrint.Client/
+├── App.xaml # 应用程序入口
+├── Services/
+│ ├── PrintService.cs # 打印服务(调用Windows API)
+│ ├── FileService.cs # 文件处理服务
+│ ├── GrpcService.cs # gRPC通信服务
+│ └── WebSocketService.cs # WebSocket备用通信
+├── ViewModels/
+│ ├── MainViewModel.cs # 主窗口
+│ ├── PrintQueueViewModel.cs # 打印队列
+│ ├── LibraryViewModel.cs # 文库管理
+│ └── SettingsViewModel.cs # 设置
+├── Views/
+│ ├── MainWindow.xaml
+│ ├── PrintQueueView.xaml
+│ ├── LibraryView.xaml
+│ └── SettingsView.xaml
+├── Models/
+│ ├── PrintJob.cs
+│ ├── Printer.cs
+│ └── Document.cs
+└── Helpers/
+ ├── WindowsPrintApi.cs # Windows打印API封装
+ └── PdfProcessor.cs # PDF处理
+```
+
+#### 3.2.2 Windows打印API集成
+
+使用 P/Invoke 调用 Windows Print Spooler API:
+- `OpenPrinter`
+- `StartDocPrinter`
+- `StartPagePrinter`
+- `WritePrinter`
+- `EndPagePrinter`
+- `EndDocPrinter`
+- `ClosePrinter`
+
+```csharp
+// 核心打印服务类
+public class PrintService
+{
+ // 获取系统打印机列表
+ public List GetPrinters();
+
+ // 获取打印机状态
+ public PrinterStatus GetPrinterStatus(string printerName);
+
+ // 提交打印任务
+ public string SubmitPrintJob(PrintJob job);
+
+ // 取消打印任务
+ public bool CancelPrintJob(string jobId);
+
+ // 获取打印任务状态
+ public PrintJobStatus GetJobStatus(string jobId);
+}
+```
+
+#### 3.2.3 gRPC通信
+
+```csharp
+// 与后端gRPC服务通信
+public class GrpcService
+{
+ // 连接gRPC服务器
+ public async Task ConnectAsync(string address);
+
+ // 订阅打印任务流
+ public async Task SubscribePrintJobsAsync(string printerName);
+
+ // 发送状态更新
+ public async Task SendStatusUpdateAsync(PrintJobStatus status);
+}
+```
+
+### 3.3 后端服务(Go + gRPC + go-pay)
+
+#### 3.3.1 项目结构
+
+```text
+cloudprint-backend/
+├── cmd/
+│ └── server/
+│ └── main.go # 入口
+├── config/
+│ └── config.go # 配置
+├── internal/
+│ ├── grpc/ # gRPC服务
+│ │ ├── server.go # gRPC服务器入口
+│ │ ├── interceptor/ # 拦截器
+│ │ └── service/ # 服务实现
+│ │ ├── auth.go
+│ │ ├── file.go
+│ │ ├── order.go
+│ │ ├── print.go
+│ │ └── library.go
+│ ├── model/ # 数据模型
+│ ├── repository/ # 数据访问
+│ └── service/ # 业务逻辑
+├── pkg/
+│ ├── jwt/ # JWT认证
+│ ├── pay/ # 支付服务 (go-pay)
+│ └── upload/ # 文件上传
+├── proto/ # Protobuf定义
+│ ├── cloudprint.proto
+│ └── generated/ # 生成的代码
+├── scripts/
+│ └── db.sql # 数据库脚本
+└── go.mod
+```
+
+#### 3.3.2 gRPC 服务设计
+
+**认证服务 (AuthService)**
+
+```protobuf
+service AuthService {
+ rpc Login(LoginRequest) returns (LoginResponse);
+ rpc RefreshToken(RefreshRequest) returns (RefreshResponse);
+ rpc Logout(LogoutRequest) returns (Empty);
+}
+```
+
+**文件服务 (FileService)**
+
+```protobuf
+service FileService {
+ rpc Upload(stream UploadRequest) returns (UploadResponse);
+ rpc GetFile(GetFileRequest) returns (stream FileData);
+ rpc DeleteFile(DeleteRequest) returns (Empty);
+ rpc AddWatermark(WatermarkRequest) returns (WatermarkResponse);
+}
+```
+
+**订单服务 (OrderService)**
+
+```protobuf
+service OrderService {
+ rpc CreateOrder(CreateOrderRequest) returns (OrderResponse);
+ rpc GetOrderList(GetOrderListRequest) returns (OrderListResponse);
+ rpc GetOrder(GetOrderRequest) returns (OrderResponse);
+ rpc UpdateOrderStatus(UpdateStatusRequest) returns (Empty);
+ rpc PayOrder(PayRequest) returns (PayResponse);
+}
+```
+
+**打印服务 (PrintService)**
+
+```protobuf
+service PrintService {
+ rpc GetPrinters(Empty) returns (PrinterListResponse);
+ rpc GetPrinterStatus(PrinterRequest) returns (PrinterStatusResponse);
+ rpc SubmitPrintJob(PrintJobRequest) returns (PrintJobResponse);
+ rpc CancelPrintJob(CancelRequest) returns (Empty);
+ rpc SubscribeJobs(SubscriberRequest) returns (stream PrintJob);
+ rpc ReportJobStatus(JobStatusReport) returns (Empty);
+}
+```
+
+**文库服务 (LibraryService)**
+
+```protobuf
+service LibraryService {
+ rpc GetCategories(Empty) returns (CategoryListResponse);
+ rpc GetFiles(GetFilesRequest) returns (FileListResponse);
+ rpc UploadFile(stream UploadRequest) returns (UploadResponse);
+ rpc DeleteFile(DeleteRequest) returns (Empty);
+}
+```
+
+**支付服务 (PayService)**
+
+```protobuf
+service PayService {
+ rpc CreateWxPayOrder(WxPayRequest) returns (WxPayResponse);
+ rpc QueryWxPayStatus(QueryRequest) returns (PayStatusResponse);
+ rpc HandleWxPayCallback(CallbackRequest) returns (CallbackResponse);
+}
+```
+
+#### 3.3.3 gRPC 通信流程
+
+```mermaid
+sequenceDiagram
+ participant CSharp as C# WPF客户端
+ participant Go as Go gRPC服务器
+ participant DB as MySQL/Redis
+
+ CSharp->>Go: 连接gRPC服务 (认证)
+ Go-->>CSharp: 连接成功
+ CSharp->>Go: 注册打印机 (SubscribeJobs)
+ Go->>DB: 查询待打印任务
+ DB-->>Go: 任务列表
+
+ loop 等待新任务
+ Go-->>CSharp: 推送新打印任务 (stream)
+ CSharp->>CSharp: 处理文件/调用打印API
+ CSharp->>Go: 上报状态 (ReportJobStatus)
+ Go->>DB: 更新任务状态
+ end
+```
+
+### 3.4 数据库设计
+
+#### 3.4.1 ER 图
+
+```mermaid
+erDiagram
+ User ||--o{ Order : places
+ User {
+ int id PK
+ string openid UK
+ string nickname
+ decimal balance
+ datetime created_at
+ }
+
+ Order ||--|{ OrderItem : contains
+ Order ||--o{ Payment : has
+ Order {
+ int id PK
+ string order_no UK
+ int user_id FK
+ int status
+ decimal total_amount
+ datetime created_at
+ }
+
+ OrderItem {
+ int id PK
+ int order_id FK
+ int file_id FK
+ string printer_name
+ int copies
+ bool color
+ bool duplex
+ string page_range
+ decimal price
+ }
+
+ Payment {
+ int id PK
+ string order_no UK
+ int pay_status
+ string transaction_id
+ datetime paid_at
+ }
+
+ File {
+ int id PK
+ string file_name
+ string file_path
+ string file_type
+ int file_size
+ string uploader_type
+ int uploader_id
+ datetime created_at
+ }
+
+ Library |||--|{ LibraryFile : contains
+ Library {
+ int id PK
+ string name
+ string description
+ int sort_order
+ }
+
+ LibraryFile ||--o{ File : references
+ LibraryFile {
+ int id PK
+ int library_id FK
+ int file_id FK
+ string title
+ string description
+ }
+
+ Printer |||--o{ PrintJob : receives
+ Printer {
+ int id PK
+ string name UK
+ string display_name
+ bool is_active
+ string api_key UK
+ }
+
+ PrintJob {
+ int id PK
+ string job_no UK
+ int printer_id FK
+ int order_item_id FK
+ string status
+ int progress
+ datetime started_at
+ datetime completed_at
+ }
+
+ PriceList {
+ int id PK
+ string name
+ string type
+ decimal price
+ string unit
+ bool is_active
+ }
+```
+
+#### 3.4.2 主要表结构
+
+```sql
+-- 用户表
+CREATE TABLE `user` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `openid` VARCHAR(64) UNIQUE NOT NULL COMMENT '微信OpenID',
+ `nickname` VARCHAR(128) DEFAULT '',
+ `avatar` VARCHAR(512) DEFAULT '',
+ `balance` DECIMAL(10,2) DEFAULT 0.00 COMMENT '余额',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+);
+
+-- 管理员表
+CREATE TABLE `admin` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `username` VARCHAR(64) UNIQUE NOT NULL,
+ `password_hash` VARCHAR(256) NOT NULL,
+ `nickname` VARCHAR(128) DEFAULT '',
+ `role` TINYINT DEFAULT 1 COMMENT '1:普通管理员 2:超级管理员',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 打印机表
+CREATE TABLE `printer` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `name` VARCHAR(128) UNIQUE NOT NULL COMMENT '系统打印机名',
+ `display_name` VARCHAR(128) NOT NULL COMMENT '显示名称',
+ `api_key` VARCHAR(64) UNIQUE NOT NULL COMMENT '客户端认证Key',
+ `is_active` TINYINT DEFAULT 1,
+ `status` TINYINT DEFAULT 0 COMMENT '0:空闲 1:打印中 2:离线',
+ `last_heartbeat` DATETIME,
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 订单表
+CREATE TABLE `order` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `order_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '订单号',
+ `user_id` INT NOT NULL,
+ `status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:已支付 2:打印中 3:已完成 4:已取消',
+ `total_amount` DECIMAL(10,2) NOT NULL,
+ `remark` VARCHAR(512) DEFAULT '',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `paid_at` DATETIME,
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`)
+);
+
+-- 订单明细表
+CREATE TABLE `order_item` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `order_id` INT NOT NULL,
+ `file_id` INT NOT NULL,
+ `printer_id` INT,
+ `copies` INT DEFAULT 1,
+ `color` TINYINT DEFAULT 0,
+ `duplex` TINYINT DEFAULT 0,
+ `page_range` VARCHAR(64) DEFAULT 'all',
+ `price` DECIMAL(10,2) NOT NULL,
+ FOREIGN KEY (`order_id`) REFERENCES `order`(`id`),
+ FOREIGN KEY (`file_id`) REFERENCES `file`(`id`)
+);
+
+-- 文件表
+CREATE TABLE `file` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `file_name` VARCHAR(256) NOT NULL,
+ `file_path` VARCHAR(512) NOT NULL,
+ `file_type` VARCHAR(32) NOT NULL COMMENT 'pdf/doc/docx/xls/xlsx/ppt/pptx/txt/jpg/png/zip',
+ `file_size` BIGINT NOT NULL COMMENT '字节',
+ `uploader_type` VARCHAR(16) NOT NULL COMMENT 'user/admin/system',
+ `uploader_id` INT NOT NULL,
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 文库分类表
+CREATE TABLE `library_category` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `name` VARCHAR(128) NOT NULL,
+ `icon` VARCHAR(128) DEFAULT '',
+ `sort_order` INT DEFAULT 0,
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 文库文件表
+CREATE TABLE `library_file` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `category_id` INT NOT NULL,
+ `file_id` INT NOT NULL,
+ `title` VARCHAR(256) NOT NULL,
+ `description` VARCHAR(512) DEFAULT '',
+ `page_count` INT DEFAULT 0,
+ `download_count` INT DEFAULT 0,
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ FOREIGN KEY (`category_id`) REFERENCES `library_category`(`id`),
+ FOREIGN KEY (`file_id`) REFERENCES `file`(`id`)
+);
+
+-- 打印任务表
+CREATE TABLE `print_job` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `job_no` VARCHAR(32) UNIQUE NOT NULL,
+ `printer_id` INT NOT NULL,
+ `order_item_id` INT NOT NULL,
+ `status` VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/printing/completed/failed/cancelled',
+ `progress` INT DEFAULT 0,
+ `error_msg` VARCHAR(512) DEFAULT '',
+ `started_at` DATETIME,
+ `completed_at` DATETIME,
+ FOREIGN KEY (`printer_id`) REFERENCES `printer`(`id`)
+);
+
+-- 价目表
+CREATE TABLE `price_list` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `name` VARCHAR(128) NOT NULL COMMENT '项目名称',
+ `type` VARCHAR(32) NOT NULL COMMENT '纸张类型: A4/A3/照片纸',
+ `price` DECIMAL(10,2) NOT NULL COMMENT '单价',
+ `unit` VARCHAR(16) NOT NULL COMMENT '单位: 页/张/份',
+ `color_enabled` TINYINT DEFAULT 1 COMMENT '是否支持彩色',
+ `is_active` TINYINT DEFAULT 1,
+ `sort_order` INT DEFAULT 0,
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 支付记录表
+CREATE TABLE `payment` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `order_no` VARCHAR(32) UNIQUE NOT NULL,
+ `pay_type` VARCHAR(16) DEFAULT 'wechat' COMMENT 'wechat/balance',
+ `pay_status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:支付中 2:成功 3:失败',
+ `transaction_id` VARCHAR(64) DEFAULT '',
+ `paid_at` DATETIME,
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+);
+```
+
+---
+
+## 4. 核心流程
+
+### 4.1 用户打印流程
+
+```mermaid
+sequenceDiagram
+ participant User as 用户
+ participant MiniApp as 微信小程序
+ participant Backend as Go后端
+ participant Windows as Windows客户端
+ participant Printer as 打印机
+
+ User->>MiniApp: 选择文件上传
+ MiniApp->>MiniApp: 文件预览/编辑
+ User->>MiniApp: 确认打印参数
+ MiniApp->>Backend: 创建订单
+ Backend-->>MiniApp: 订单信息
+ User->>MiniApp: 支付订单
+ MiniApp->>Backend: 支付回调
+ Backend->>Windows: WebSocket推送打印任务
+ Windows->>Backend: 下载文件
+ Windows->>Windows: PDF预处理
+ Windows->>Printer: 发送打印指令
+ Printer-->>Windows: 打印中
+ Windows->>Backend: 更新任务状态
+ Backend->>MiniApp: 推送状态更新
+ Printer-->>User: 输出打印件
+```
+
+### 4.2 管理员上传文库流程
+
+```mermaid
+flowchart TD
+ Admin["管理员登录Windows客户端"] --> Navigate["进入文库管理"]
+ Navigate --> SelectCategory["选择分类"]
+ SelectCategory --> Upload["上传文件"]
+ Upload --> SetInfo["设置文件标题描述"]
+ SetInfo --> Confirm["确认上传"]
+ Confirm --> Save["保存到数据库"]
+ Save --> Sync["同步到云端"]
+ Sync --> Success["上传成功"]
+```
+
+---
+
+## 5. 文件处理
+
+### 5.1 支持的文件格式
+
+| 类型 | 格式 | 处理方式 |
+|------|------|----------|
+| 文档 | doc, docx, txt | 转为PDF后打印 |
+| 表格 | xls, xlsx | 转为PDF后打印 |
+| 演示 | ppt, pptx | 转为PDF后打印 |
+| 图片 | jpg, png, bmp, gif | 直接打印或转PDF |
+| 压缩包 | zip, rar | 解压后处理内部文件 |
+| PDF | pdf | 直接打印 |
+
+### 5.2 C#端文件转换
+
+使用以下库/工具进行文件转换:
+- **Word/Excel/PowerPoint**: Microsoft Office COM Automation 或 LibreOffice Headless
+- **图片**: System.Drawing
+- **压缩包**: SharpCompress
+- **PDF合并/水印**: PDFsharp 或 iTextSharp
+
+---
+
+## 6. 安全设计
+
+### 6.1 认证授权
+
+- **用户端**: 微信 OAuth2.0 获取 OpenID
+- **管理后台**: 用户名密码 + JWT Token
+- **打印客户端**: API Key 认证 + gRPC TLS加密连接
+
+### 6.2 数据安全
+
+- 文件上传: 大小限制 (单文件 50MB)
+- 文件类型白名单验证
+- SQL注入防护: 使用参数化查询
+- XSS防护: 输出编码
+- gRPC传输加密: TLS 1.3
+
+### 6.3 打印客户端认证
+
+gRPC认证流程:
+1. 客户端使用API Key获取临时凭证
+2. 使用凭证建立gRPC TLS连接
+3. 服务端验证客户端身份
+4. 建立长连接后订阅打印任务流
+
+---
+
+## 7. 开发计划
+
+### 7.1 项目模块划分
+
+1. **cloudprint-miniapp** - Taro微信小程序用户端
+2. **cloudprint-backend** - Go + gRPC 后端服务
+3. **cloudprint-client** - C# (.NET 8) + WPF 打印客户端
+4. **cloudprint-admin** - React 管理后台网页端
+5. **cloudprint-proto** - Protobuf 定义共享库
+
+### 7.2 开发顺序
+
+```
+1. cloudprint-proto (公共协议定义)
+ ├── 定义所有 gRPC 服务和消息类型
+ ├── 生成 Go、C#、TypeScript 代码
+
+2. cloudprint-backend (Go + gRPC + go-pay)
+ ├── 数据库设计与初始化
+ ├── 基础框架搭建
+ ├── 认证模块 (JWT)
+ ├── 文件服务
+ ├── 订单服务
+ ├── 打印服务
+ ├── 文库服务
+ └── 微信支付集成 (go-pay)
+
+3. cloudprint-client (C# WPF)
+ ├── 项目初始化 (.NET 8)
+ ├── 打印服务开发 (P/Invoke Windows API)
+ ├── gRPC 通信 (Grpc.Net)
+ ├── WebSocket 通信 (用于推送)
+ ├── 文件处理
+ └── 文库管理
+
+4. cloudprint-admin (React + Ant Design)
+ ├── 项目初始化
+ ├── 登录认证
+ ├── 订单管理
+ ├── 用户管理
+ ├── 价目表管理
+ └── 数据统计
+
+5. cloudprint-miniapp (Taro)
+ ├── 项目初始化 (@tarojs/cli)
+ ├── 用户端页面开发
+ ├── 文件上传与编辑
+ ├── 订单流程
+ └── 与后端 gRPC 对接
+```
+
+---
+
+## 8. 部署方案
+
+### 8.1 云服务器要求
+
+- **配置**: 2核4G起步
+- **系统**: Ubuntu 22.04 / CentOS 8
+- **数据库**: MySQL 8.0
+- **缓存**: Redis 6.0
+- **文件存储**: 本地磁盘或 MinIO
+
+### 8.2 打印店客户端部署
+
+1. 在打印店电脑安装 Windows 10/11 + .NET 8 Runtime
+2. 运行 C# WPF 客户端程序,配置服务器地址
+3. 登录管理员账号
+4. 配置打印机
+5. 保持客户端在线
+
+---
+
+## 9. 风险与注意事项
+
+| 风险 | 应对措施 |
+|------|----------|
+| 文件格式兼容 | C#客户端集成LibreOffice转换 |
+| 打印质量差异 | 客户端提供打印参数调试 |
+| 大文件传输 | 分片上传、断点续传 |
+| 客户端掉线 | gRPC心跳检测、自动重连 |
+| 支付安全 | 微信支付官方SDK (go-pay) |
+| 并发打印 | 任务队列、打印机组 |
diff --git a/cloudprint-backend/README.md b/cloudprint-backend/README.md
new file mode 100644
index 0000000..a68f2da
--- /dev/null
+++ b/cloudprint-backend/README.md
@@ -0,0 +1,236 @@
+# 云印享 - 付费打印服务系统
+
+## 项目简介
+
+云印享是一个基于 gRPC 的付费打印服务后端系统,支持用户管理、文件上传下载、订单处理、打印任务调度、微信支付、文库管理等核心功能。
+
+## 技术栈
+
+- **语言**: Go 1.21+
+- **框架**: gRPC + Protobuf
+- **数据库**: MySQL + GORM
+- **认证**: JWT (JSON Web Token)
+- **支付**: 微信支付 (gopay)
+- **配置**: Viper
+
+## 项目结构
+
+```
+cloudprint-backend/
+├── cmd/server/ # 应用入口
+│ └── main.go
+├── config/ # 配置管理
+│ └── config.go
+├── internal/
+│ ├── grpc/ # gRPC 服务层
+│ │ ├── interceptor/ # 拦截器 (认证)
+│ │ └── service/ # gRPC 服务实现
+│ ├── model/ # 数据模型
+│ ├── repository/ # 数据访问层
+│ └── service/ # 业务逻辑层
+├── pkg/ # 公共工具包
+│ ├── jwt/ # JWT 认证
+│ ├── pay/ # 微信支付
+│ └── upload/ # 文件上传
+├── proto/ # Protobuf 定义
+│ ├── cloudprint.proto
+│ └── generated/ # 生成的代码
+├── scripts/ # 数据库脚本
+│ └── db.sql
+├── config.yaml # 配置文件
+├── go.mod
+└── go.sum
+```
+
+## 服务列表
+
+| 服务 | 端口 | 描述 |
+|------|------|------|
+| gRPC Server | 8080 | 主服务端口 |
+
+## 快速开始
+
+### 1. 环境要求
+
+- Go 1.21+
+- MySQL 5.7+
+- protoc (Protocol Buffer 编译器)
+
+### 2. 数据库初始化
+
+```bash
+mysql -u root -p < scripts/db.sql
+```
+
+### 3. 配置修改
+
+编辑 `config.yaml` 文件,修改以下配置:
+
+```yaml
+database:
+ host: "localhost"
+ port: 3306
+ username: "root"
+ password: "your-password"
+ database: "cloudprint"
+
+jwt:
+ secret: "your-secret-key-change-in-production"
+
+wechat:
+ app_id: "your-app-id"
+ app_secret: "your-app-secret"
+ mch_id: "your-merchant-id"
+ api_key: "your-api-key"
+ notify_url: "http://your-domain.com/pay/callback"
+```
+
+### 4. 编译生成 gRPC 代码
+
+```bash
+cd cloudprint-backend
+protoc --go_out=./proto/generated --go_opt=paths=source_relative \
+ --go-grpc_out=./proto/generated --go-grpc_opt=paths=source_relative \
+ proto/cloudprint.proto
+```
+
+### 5. 运行服务
+
+```bash
+go run cmd/server/main.go -config config.yaml
+```
+
+## API 文档
+
+### AuthService (用户认证服务)
+
+| 方法 | 描述 |
+|------|------|
+| Login | 微信登录,获取 AccessToken 和 RefreshToken |
+| RefreshToken | 刷新 AccessToken |
+| GetUserInfo | 获取用户信息 |
+| UpdateUser | 更新用户信息(昵称、头像) |
+
+### FileService (文件管理服务)
+
+| 方法 | 描述 |
+|------|------|
+| Upload | 流式上传文件(支持分片) |
+| GetFile | 流式下载文件 |
+| DeleteFile | 删除文件 |
+| AddWatermark | 添加水印 |
+| GetFileList | 获取文件列表 |
+
+### OrderService (订单服务)
+
+| 方法 | 描述 |
+|------|------|
+| CreateOrder | 创建订单 |
+| GetOrder | 获取订单详情 |
+| GetOrderList | 获取订单列表 |
+| UpdateOrderStatus | 更新订单状态 |
+| CancelOrder | 取消订单 |
+
+### PrintService (打印服务)
+
+| 方法 | 描述 |
+|------|------|
+| GetPrinters | 获取打印机列表 |
+| GetPrinterStatus | 获取打印机状态 |
+| RegisterPrinter | 注册打印机 |
+| PrinterHeartbeat | 打印机心跳 |
+| SubmitPrintJob | 提交打印任务 |
+| CancelPrintJob | 取消打印任务 |
+| SubscribeJobs | 订阅打印任务(流式) |
+| ReportJobStatus | 上报任务状态 |
+
+### LibraryService (文库服务)
+
+| 方法 | 描述 |
+|------|------|
+| GetCategories | 获取文库分类 |
+| GetFiles | 获取文库文件列表 |
+| UploadFile | 上传文库文件 |
+| DeleteFile | 删除文库文件 |
+
+### PriceService (价目表服务)
+
+| 方法 | 描述 |
+|------|------|
+| GetPriceList | 获取价目表 |
+| CreatePriceItem | 创建价目项 |
+| UpdatePriceItem | 更新价目项 |
+
+### PayService (支付服务)
+
+| 方法 | 描述 |
+|------|------|
+| CreateWxPayOrder | 创建微信支付订单 |
+| QueryPayStatus | 查询支付状态 |
+| HandlePayCallback | 处理支付回调 |
+| PayByBalance | 余额支付 |
+
+### AdminService (管理后台服务)
+
+| 方法 | 描述 |
+|------|------|
+| Login | 管理员登录 |
+| GetStatistics | 获取统计数据 |
+
+## 数据模型
+
+### 订单状态
+
+| 值 | 状态 |
+|----|------|
+| 0 | 待支付 |
+| 1 | 已支付 |
+| 2 | 打印中 |
+| 3 | 已完成 |
+| 4 | 已取消 |
+
+### 支付状态
+
+| 值 | 状态 |
+|----|------|
+| 0 | 待支付 |
+| 1 | 支付中 |
+| 2 | 成功 |
+| 3 | 失败 |
+
+### 打印机状态
+
+| 值 | 状态 |
+|----|------|
+| 0 | 空闲 |
+| 1 | 打印中 |
+| 2 | 离线 |
+
+### 打印任务状态
+
+| 值 | 状态 |
+|----|------|
+| pending | 等待中 |
+| printing | 打印中 |
+| completed | 已完成 |
+| failed | 失败 |
+| cancelled | 已取消 |
+
+## 默认账号
+
+- 管理员用户名: `admin`
+- 管理员密码: `admin123` (需在生产环境修改)
+
+## 初始价目表
+
+| 名称 | 类型 | 价格 | 单位 |
+|------|------|------|------|
+| A4黑白打印 | A4 | 0.10元 | 页 |
+| A4彩色打印 | A4 | 0.30元 | 页 |
+| A3黑白打印 | A3 | 0.20元 | 页 |
+| A3彩色打印 | A3 | 0.60元 | 页 |
+| 照片打印 | 照片纸 | 2.00元 | 张 |
+
+## 许可证
+
+MIT License
diff --git a/cloudprint-backend/cmd/server/main.go b/cloudprint-backend/cmd/server/main.go
new file mode 100644
index 0000000..a0a0dc4
--- /dev/null
+++ b/cloudprint-backend/cmd/server/main.go
@@ -0,0 +1,163 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "os/signal"
+ "syscall"
+
+ "github.com/cloudprint/cloudprint-backend/config"
+ "github.com/cloudprint/cloudprint-backend/internal/grpc"
+ "github.com/cloudprint/cloudprint-backend/internal/grpc/interceptor"
+ "github.com/cloudprint/cloudprint-backend/internal/grpc/service"
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ "github.com/cloudprint/cloudprint-backend/pkg/jwt"
+ "github.com/cloudprint/cloudprint-backend/pkg/pay"
+ "github.com/cloudprint/cloudprint-backend/pkg/upload"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "go.uber.org/zap"
+ "google.golang.org/grpc"
+ "gorm.io/driver/mysql"
+ "gorm.io/gorm"
+ "gorm.io/gorm/logger"
+)
+
+func main() {
+ configPath := flag.String("config", "config.yaml", "path to config file")
+ flag.Parse()
+
+ // Load configuration
+ cfg, err := config.LoadConfig(*configPath)
+ if err != nil {
+ log.Fatalf("Failed to load config: %v", err)
+ }
+
+ // Initialize logger
+ zapLogger, _ := zap.NewProduction()
+ defer zapLogger.Sync()
+
+ // Initialize database
+ db, err := initDB(cfg)
+ if err != nil {
+ log.Fatalf("Failed to initialize database: %v", err)
+ }
+
+ // Auto migrate
+ if err := db.AutoMigrate(
+ &model.User{},
+ &model.Admin{},
+ &model.Printer{},
+ &model.Order{},
+ &model.OrderItem{},
+ &model.File{},
+ &model.LibraryCategory{},
+ &model.LibraryFile{},
+ &model.PrintJob{},
+ &model.PriceList{},
+ &model.Payment{},
+ ); err != nil {
+ log.Fatalf("Failed to migrate database: %v", err)
+ }
+
+ // Initialize repositories
+ userRepo := repository.NewUserRepository(db)
+ adminRepo := repository.NewAdminRepository(db)
+ fileRepo := repository.NewFileRepository(db)
+ orderRepo := repository.NewOrderRepository(db)
+ orderItemRepo := repository.NewOrderItemRepository(db)
+ printerRepo := repository.NewPrinterRepository(db)
+ printJobRepo := repository.NewPrintJobRepository(db)
+ libraryRepo := repository.NewLibraryRepository(db)
+ priceRepo := repository.NewPriceRepository(db)
+ paymentRepo := repository.NewPaymentRepository(db)
+
+ // Initialize JWT manager
+ jwtManager := jwt.NewJWTManager(
+ cfg.JWT.Secret,
+ cfg.JWT.AccessTokenTTL,
+ cfg.JWT.RefreshTokenTTL,
+ )
+
+ // Initialize file uploader
+ fileUploader := upload.NewFileUploader(
+ cfg.Upload.Path,
+ cfg.Upload.ChunkPath,
+ cfg.Upload.MaxSize,
+ )
+
+ // Initialize WeChat pay
+ weChatPay := pay.NewWeChatPay(&cfg.WeChat)
+
+ // Initialize services
+ authService := service.NewAuthService(userRepo, adminRepo, jwtManager, nil, &cfg.WeChat)
+ fileService := service.NewFileService(fileRepo, fileUploader, cfg.Upload.Path)
+ orderService := service.NewOrderService(orderRepo, orderItemRepo, fileRepo, priceRepo, userRepo, printerRepo, printJobRepo)
+ printService := service.NewPrintService(printerRepo, printJobRepo, orderRepo)
+
+ // Initialize gRPC server
+ grpcServer := grpc.NewServer(
+ grpc.UnaryInterceptor(interceptor.NewAuthInterceptor(jwtManager).UnaryServerInterceptor()),
+ )
+
+ // Register gRPC services
+ pb.RegisterAuthServiceServer(grpcServer, service.NewAuthServiceServer(authService))
+ pb.RegisterFileServiceServer(grpcServer, service.NewFileServiceServer(fileService))
+ pb.RegisterOrderServiceServer(grpcServer, service.NewOrderServiceServer(orderService))
+ pb.RegisterPrintServiceServer(grpcServer, service.NewPrintServiceServer(printService))
+ pb.RegisterLibraryServiceServer(grpcServer, service.NewLibraryServiceServer(libraryRepo, fileRepo))
+ pb.RegisterPriceServiceServer(grpcServer, service.NewPriceServiceServer(priceRepo))
+ pb.RegisterPayServiceServer(grpcServer, service.NewPayServiceServer(orderService, paymentRepo, weChatPay, userRepo))
+ pb.RegisterAdminServiceServer(grpcServer, service.NewAdminServiceServer(authService, orderRepo, printerRepo))
+
+ // Start server
+ addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port)
+ lis, err := net.Listen("tcp", addr)
+ if err != nil {
+ log.Fatalf("Failed to listen: %v", err)
+ }
+
+ // Graceful shutdown
+ sigCh := make(chan os.Signal, 1)
+ signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
+
+ go func() {
+ <-sigCh
+ grpcServer.GracefulStop()
+ }()
+
+ zapLogger.Info("Starting gRPC server", zap.String("address", addr))
+ if err := grpcServer.Serve(lis); err != nil {
+ log.Fatalf("Failed to serve: %v", err)
+ }
+}
+
+func initDB(cfg *config.Config) (*gorm.DB, error) {
+ gormLogger := logger.New(
+ log.New(os.Stdout, "\r\n", log.LstdFlags),
+ logger.Config{
+ LogLevel: logger.Info,
+ },
+ )
+
+ db, err := gorm.Open(mysql.Open(cfg.Database.DSN()), &gorm.Config{
+ Logger: gormLogger,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ sqlDB, err := db.DB()
+ if err != nil {
+ return nil, err
+ }
+
+ sqlDB.SetMaxOpenConns(cfg.Database.MaxOpenConns)
+ sqlDB.SetMaxIdleConns(cfg.Database.MaxIdleConns)
+
+ return db, nil
+}
diff --git a/cloudprint-backend/config/config.go b/cloudprint-backend/config/config.go
new file mode 100644
index 0000000..c167f90
--- /dev/null
+++ b/cloudprint-backend/config/config.go
@@ -0,0 +1,98 @@
+package config
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/spf13/viper"
+)
+
+type Config struct {
+ Server ServerConfig `mapstructure:"server"`
+ Database DatabaseConfig `mapstructure:"database"`
+ Redis RedisConfig `mapstructure:"redis"`
+ JWT JWTConfig `mapstructure:"jwt"`
+ WeChat WeChatConfig `mapstructure:"wechat"`
+ Upload UploadConfig `mapstructure:"upload"`
+}
+
+type ServerConfig struct {
+ Host string `mapstructure:"host"`
+ Port int `mapstructure:"port"`
+}
+
+type DatabaseConfig struct {
+ Host string `mapstructure:"host"`
+ Port int `mapstructure:"port"`
+ Username string `mapstructure:"username"`
+ Password string `mapstructure:"password"`
+ Database string `mapstructure:"database"`
+ MaxOpenConns int `mapstructure:"max_open_conns"`
+ MaxIdleConns int `mapstructure:"max_idle_conns"`
+}
+
+func (d *DatabaseConfig) DSN() string {
+ return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
+ d.Username, d.Password, d.Host, d.Port, d.Database)
+}
+
+type RedisConfig struct {
+ Host string `mapstructure:"host"`
+ Port int `mapstructure:"port"`
+ Password string `mapstructure:"password"`
+ DB int `mapstructure:"db"`
+}
+
+func (r *RedisConfig) Addr() string {
+ return fmt.Sprintf("%s:%d", r.Host, r.Port)
+}
+
+type JWTConfig struct {
+ Secret string `mapstructure:"secret"`
+ AccessTokenTTL time.Duration `mapstructure:"access_token_ttl"`
+ RefreshTokenTTL time.Duration `mapstructure:"refresh_token_ttl"`
+}
+
+type WeChatConfig struct {
+ AppID string `mapstructure:"app_id"`
+ AppSecret string `mapstructure:"app_secret"`
+ MchID string `mapstructure:"mch_id"`
+ ApiKey string `mapstructure:"api_key"`
+ NotifyURL string `mapstructure:"notify_url"`
+ CertPath string `mapstructure:"cert_path"`
+ CertContent string `mapstructure:"cert_content"`
+}
+
+type UploadConfig struct {
+ Path string `mapstructure:"path"`
+ MaxSize int64 `mapstructure:"max_size"`
+ ChunkPath string `mapstructure:"chunk_path"`
+}
+
+var GlobalConfig *Config
+
+func LoadConfig(path string) (*Config, error) {
+ viper.SetConfigFile(path)
+ viper.SetConfigType("yaml")
+
+ viper.SetDefault("server.host", "0.0.0.0")
+ viper.SetDefault("server.port", 8080)
+ viper.SetDefault("database.max_open_conns", 100)
+ viper.SetDefault("database.max_idle_conns", 10)
+ viper.SetDefault("jwt.access_token_ttl", "24h")
+ viper.SetDefault("jwt.refresh_token_ttl", "7d")
+ viper.SetDefault("upload.max_size", 52428800) // 50MB
+ viper.SetDefault("upload.chunk_path", "./uploads/chunks")
+
+ if err := viper.ReadInConfig(); err != nil {
+ return nil, fmt.Errorf("failed to read config: %w", err)
+ }
+
+ var cfg Config
+ if err := viper.Unmarshal(&cfg); err != nil {
+ return nil, fmt.Errorf("failed to unmarshal config: %w", err)
+ }
+
+ GlobalConfig = &cfg
+ return &cfg, nil
+}
diff --git a/cloudprint-backend/docs/openapi.yaml b/cloudprint-backend/docs/openapi.yaml
new file mode 100644
index 0000000..a3b591c
--- /dev/null
+++ b/cloudprint-backend/docs/openapi.yaml
@@ -0,0 +1,1132 @@
+openapi: 3.0.3
+info:
+ title: 云印享 - 付费打印服务 API
+ description: |
+ 云印享是一个基于 gRPC 的付费打印服务后端系统 API 文档。
+
+ ## 认证说明
+ - 大多数接口需要在请求头中携带 `Authorization: Bearer `
+ - Login 和 Admin.Login 接口不需要认证
+ version: 1.0.0
+ contact:
+ name: CloudPrint Support
+
+servers:
+ - url: http://localhost:8080
+ description: gRPC Server (需通过 gRPC gateway 转换)
+
+tags:
+ - name: Auth
+ description: 用户认证相关接口
+ - name: File
+ description: 文件管理相关接口
+ - name: Order
+ description: 订单相关接口
+ - name: Print
+ description: 打印服务相关接口
+ - name: Library
+ description: 文库相关接口
+ - name: Price
+ description: 价目表相关接口
+ - name: Pay
+ description: 支付相关接口
+ - name: Admin
+ description: 管理后台相关接口
+
+paths:
+ # ==================== Auth Service ====================
+ /cloudprint.AuthService/Login:
+ post:
+ tags: [Auth]
+ summary: 微信登录
+ description: 用户通过微信授权码登录系统
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ description: 微信授权码
+ example: "xxxxx"
+ responses:
+ "200":
+ description: 登录成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ access_token:
+ type: string
+ description: 访问令牌
+ refresh_token:
+ type: string
+ description: 刷新令牌
+ user:
+ type: object
+ properties:
+ id:
+ type: integer
+ description: 用户ID
+ openid:
+ type: string
+ description: 微信OpenID
+ nickname:
+ type: string
+ description: 昵称
+ avatar:
+ type: string
+ description: 头像URL
+ balance:
+ type: number
+ description: 余额
+ created_at:
+ type: string
+ format: date-time
+
+ /cloudprint.AuthService/RefreshToken:
+ post:
+ tags: [Auth]
+ summary: 刷新令牌
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ refresh_token:
+ type: string
+ responses:
+ "200":
+ description: 刷新成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ access_token:
+ type: string
+
+ /cloudprint.AuthService/GetUserInfo:
+ post:
+ tags: [Auth]
+ summary: 获取用户信息
+ security:
+ - bearerAuth: []
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+
+ /cloudprint.AuthService/UpdateUser:
+ post:
+ tags: [Auth]
+ summary: 更新用户信息
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ nickname:
+ type: string
+ avatar:
+ type: string
+ responses:
+ "200":
+ description: 更新成功
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+
+ # ==================== File Service ====================
+ /cloudprint.FileService/Upload:
+ post:
+ tags: [File]
+ summary: 上传文件(流式)
+ description: 支持分片上传,用于大文件传输
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ file_name:
+ type: string
+ description: 文件名
+ file_type:
+ type: string
+ description: 文件类型
+ file_size:
+ type: integer
+ format: int64
+ description: 文件大小
+ data:
+ type: string
+ format: binary
+ description: 文件数据(base64)
+ is_last_chunk:
+ type: boolean
+ description: 是否最后一块
+ chunk_id:
+ type: string
+ description: 分片ID
+ chunk_index:
+ type: integer
+ description: 分片索引
+ total_chunks:
+ type: integer
+ description: 总分片数
+ responses:
+ "200":
+ description: 上传成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ file_id:
+ type: integer
+ file_path:
+ type: string
+ file_url:
+ type: string
+
+ /cloudprint.FileService/GetFileList:
+ post:
+ tags: [File]
+ summary: 获取文件列表
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ uploader_type:
+ type: string
+ uploader_id:
+ type: integer
+ page:
+ type: integer
+ page_size:
+ type: integer
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ files:
+ type: array
+ items:
+ $ref: '#/components/schemas/FileInfo'
+ total:
+ type: integer
+
+ /cloudprint.FileService/DeleteFile:
+ post:
+ tags: [File]
+ summary: 删除文件
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ file_id:
+ type: integer
+ responses:
+ "200":
+ description: 删除成功
+
+ /cloudprint.FileService/AddWatermark:
+ post:
+ tags: [File]
+ summary: 添加水印
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ file_id:
+ type: integer
+ text:
+ type: string
+ opacity:
+ type: number
+ format: float
+ position:
+ type: integer
+ enum: [1, 2, 3, 4, 5]
+ description: "1: 左上 2: 右上 3: 左下 4: 右下 5: 居中"
+ font_size:
+ type: integer
+ responses:
+ "200":
+ description: 成功
+
+ # ==================== Order Service ====================
+ /cloudprint.OrderService/CreateOrder:
+ post:
+ tags: [Order]
+ summary: 创建订单
+ security:
+ - bearerAuth: []
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ items:
+ type: array
+ items:
+ type: object
+ properties:
+ file_id:
+ type: integer
+ printer_id:
+ type: integer
+ copies:
+ type: integer
+ color:
+ type: boolean
+ duplex:
+ type: boolean
+ page_range:
+ type: string
+ remark:
+ type: string
+ responses:
+ "200":
+ description: 创建成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ total_amount:
+ type: number
+
+ /cloudprint.OrderService/GetOrder:
+ post:
+ tags: [Order]
+ summary: 获取订单详情
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+
+ /cloudprint.OrderService/GetOrderList:
+ post:
+ tags: [Order]
+ summary: 获取订单列表
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ user_id:
+ type: integer
+ status:
+ type: integer
+ page:
+ type: integer
+ page_size:
+ type: integer
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ orders:
+ type: array
+ items:
+ $ref: '#/components/schemas/Order'
+ total:
+ type: integer
+
+ /cloudprint.OrderService/UpdateOrderStatus:
+ post:
+ tags: [Order]
+ summary: 更新订单状态
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ status:
+ type: integer
+ enum: [0, 1, 2, 3, 4]
+ responses:
+ "200":
+ description: 更新成功
+
+ /cloudprint.OrderService/CancelOrder:
+ post:
+ tags: [Order]
+ summary: 取消订单
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ responses:
+ "200":
+ description: 取消成功
+
+ # ==================== Print Service ====================
+ /cloudprint.PrintService/GetPrinters:
+ post:
+ tags: [Print]
+ summary: 获取打印机列表
+ security:
+ - bearerAuth: []
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ printers:
+ type: array
+ items:
+ $ref: '#/components/schemas/Printer'
+
+ /cloudprint.PrintService/GetPrinterStatus:
+ post:
+ tags: [Print]
+ summary: 获取打印机状态
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ printer_id:
+ type: integer
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ printer:
+ $ref: '#/components/schemas/Printer'
+ queue_count:
+ type: integer
+
+ /cloudprint.PrintService/RegisterPrinter:
+ post:
+ tags: [Print]
+ summary: 注册打印机
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ name:
+ type: string
+ display_name:
+ type: string
+ api_key:
+ type: string
+ responses:
+ "200":
+ description: 注册成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ printer_id:
+ type: integer
+ token:
+ type: string
+
+ /cloudprint.PrintService/PrinterHeartbeat:
+ post:
+ tags: [Print]
+ summary: 打印机心跳
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ printer_id:
+ type: integer
+ status:
+ type: integer
+ enum: [0, 1, 2]
+ token:
+ type: string
+ responses:
+ "200":
+ description: 成功
+
+ /cloudprint.PrintService/SubmitPrintJob:
+ post:
+ tags: [Print]
+ summary: 提交打印任务
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_item_id:
+ type: integer
+ printer_id:
+ type: integer
+ file_path:
+ type: string
+ copies:
+ type: integer
+ color:
+ type: boolean
+ duplex:
+ type: boolean
+ page_range:
+ type: string
+ responses:
+ "200":
+ description: 提交成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ job_no:
+ type: string
+
+ /cloudprint.PrintService/CancelPrintJob:
+ post:
+ tags: [Print]
+ summary: 取消打印任务
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ job_no:
+ type: string
+ responses:
+ "200":
+ description: 取消成功
+
+ /cloudprint.PrintService/ReportJobStatus:
+ post:
+ tags: [Print]
+ summary: 上报任务状态
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ job_no:
+ type: string
+ status:
+ type: string
+ enum: [pending, printing, completed, failed, cancelled]
+ progress:
+ type: integer
+ error_msg:
+ type: string
+ responses:
+ "200":
+ description: 上报成功
+
+ # ==================== Library Service ====================
+ /cloudprint.LibraryService/GetCategories:
+ post:
+ tags: [Library]
+ summary: 获取文库分类
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ categories:
+ type: array
+ items:
+ $ref: '#/components/schemas/LibraryCategory'
+
+ /cloudprint.LibraryService/GetFiles:
+ post:
+ tags: [Library]
+ summary: 获取文库文件列表
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ category_id:
+ type: integer
+ page:
+ type: integer
+ page_size:
+ type: integer
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ files:
+ type: array
+ items:
+ $ref: '#/components/schemas/LibraryFile'
+ total:
+ type: integer
+
+ /cloudprint.LibraryService/UploadFile:
+ post:
+ tags: [Library]
+ summary: 上传文库文件
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ category_id:
+ type: integer
+ title:
+ type: string
+ description:
+ type: string
+ data:
+ type: string
+ format: binary
+ file_name:
+ type: string
+ file_type:
+ type: string
+ responses:
+ "200":
+ description: 上传成功
+
+ /cloudprint.LibraryService/DeleteFile:
+ post:
+ tags: [Library]
+ summary: 删除文库文件
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ library_file_id:
+ type: integer
+ responses:
+ "200":
+ description: 删除成功
+
+ # ==================== Price Service ====================
+ /cloudprint.PriceService/GetPriceList:
+ post:
+ tags: [Price]
+ summary: 获取价目表
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ items:
+ type: array
+ items:
+ $ref: '#/components/schemas/PriceItem'
+
+ /cloudprint.PriceService/CreatePriceItem:
+ post:
+ tags: [Price]
+ summary: 创建价目项
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ name:
+ type: string
+ type:
+ type: string
+ price:
+ type: number
+ unit:
+ type: string
+ color_enabled:
+ type: boolean
+ responses:
+ "200":
+ description: 创建成功
+
+ /cloudprint.PriceService/UpdatePriceItem:
+ post:
+ tags: [Price]
+ summary: 更新价目项
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/PriceItem'
+ responses:
+ "200":
+ description: 更新成功
+
+ # ==================== Pay Service ====================
+ /cloudprint.PayService/CreateWxPayOrder:
+ post:
+ tags: [Pay]
+ summary: 创建微信支付订单
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ amount:
+ type: number
+ description:
+ type: string
+ openid:
+ type: string
+ client_ip:
+ type: string
+ responses:
+ "200":
+ description: 创建成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ prepay_id:
+ type: string
+ code_url:
+ type: string
+ mweb_url:
+ type: string
+
+ /cloudprint.PayService/QueryPayStatus:
+ post:
+ tags: [Pay]
+ summary: 查询支付状态
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ status:
+ type: integer
+ enum: [0, 1, 2, 3]
+ description: "0: 待支付 1: 支付中 2: 成功 3: 失败"
+ transaction_id:
+ type: string
+
+ /cloudprint.PayService/HandlePayCallback:
+ post:
+ tags: [Pay]
+ summary: 处理支付回调
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ body:
+ type: string
+ description: 微信支付回调XML内容
+ responses:
+ "200":
+ description: 处理成功
+
+ /cloudprint.PayService/PayByBalance:
+ post:
+ tags: [Pay]
+ summary: 余额支付
+ security:
+ - bearerAuth: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ order_no:
+ type: string
+ user_id:
+ type: integer
+ responses:
+ "200":
+ description: 支付成功
+
+ # ==================== Admin Service ====================
+ /cloudprint.AdminService/Login:
+ post:
+ tags: [Admin]
+ summary: 管理员登录
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ username:
+ type: string
+ password:
+ type: string
+ responses:
+ "200":
+ description: 登录成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ access_token:
+ type: string
+ admin:
+ $ref: '#/components/schemas/Admin'
+
+ /cloudprint.AdminService/GetStatistics:
+ post:
+ tags: [Admin]
+ summary: 获取统计数据
+ security:
+ - bearerAuth: []
+ responses:
+ "200":
+ description: 成功
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ total_users:
+ type: integer
+ total_orders:
+ type: integer
+ today_orders:
+ type: integer
+ today_revenue:
+ type: number
+ pending_orders:
+ type: integer
+ active_printers:
+ type: integer
+
+components:
+ securitySchemes:
+ bearerAuth:
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+
+ schemas:
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ openid:
+ type: string
+ nickname:
+ type: string
+ avatar:
+ type: string
+ balance:
+ type: number
+ created_at:
+ type: string
+ format: date-time
+
+ Admin:
+ type: object
+ properties:
+ id:
+ type: integer
+ username:
+ type: string
+ nickname:
+ type: string
+ role:
+ type: integer
+ enum: [1, 2]
+ description: "1: 普通管理员 2: 超级管理员"
+ created_at:
+ type: string
+ format: date-time
+
+ FileInfo:
+ type: object
+ properties:
+ id:
+ type: integer
+ file_name:
+ type: string
+ file_path:
+ type: string
+ file_type:
+ type: string
+ file_size:
+ type: integer
+ format: int64
+ uploader_type:
+ type: string
+ uploader_id:
+ type: integer
+ created_at:
+ type: string
+ format: date-time
+
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ order_no:
+ type: string
+ user_id:
+ type: integer
+ status:
+ type: integer
+ enum: [0, 1, 2, 3, 4]
+ description: "0: 待支付 1: 已支付 2: 打印中 3: 已完成 4: 已取消"
+ total_amount:
+ type: number
+ remark:
+ type: string
+ created_at:
+ type: string
+ format: date-time
+ paid_at:
+ type: string
+ format: date-time
+ items:
+ type: array
+ items:
+ $ref: '#/components/schemas/OrderItem'
+
+ OrderItem:
+ type: object
+ properties:
+ id:
+ type: integer
+ order_id:
+ type: integer
+ file_id:
+ type: integer
+ printer_id:
+ type: integer
+ copies:
+ type: integer
+ color:
+ type: boolean
+ duplex:
+ type: boolean
+ page_range:
+ type: string
+ price:
+ type: number
+
+ Printer:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+ display_name:
+ type: string
+ is_active:
+ type: boolean
+ status:
+ type: integer
+ enum: [0, 1, 2]
+ description: "0: 空闲 1: 打印中 2: 离线"
+ last_heartbeat:
+ type: string
+ format: date-time
+
+ PrintJob:
+ type: object
+ properties:
+ id:
+ type: integer
+ job_no:
+ type: string
+ printer_id:
+ type: integer
+ order_item_id:
+ type: integer
+ status:
+ type: string
+ enum: [pending, printing, completed, failed, cancelled]
+ progress:
+ type: integer
+ error_msg:
+ type: string
+ started_at:
+ type: string
+ format: date-time
+ completed_at:
+ type: string
+ format: date-time
+
+ LibraryCategory:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+ icon:
+ type: string
+ sort_order:
+ type: integer
+
+ LibraryFile:
+ type: object
+ properties:
+ id:
+ type: integer
+ category_id:
+ type: integer
+ file_id:
+ type: integer
+ title:
+ type: string
+ description:
+ type: string
+ page_count:
+ type: integer
+ download_count:
+ type: integer
+ created_at:
+ type: string
+ format: date-time
+
+ PriceItem:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+ type:
+ type: string
+ description: 纸张类型 A4/A3/照片纸
+ price:
+ type: number
+ unit:
+ type: string
+ color_enabled:
+ type: boolean
+ is_active:
+ type: boolean
diff --git a/cloudprint-backend/go.mod b/cloudprint-backend/go.mod
new file mode 100644
index 0000000..c14c7f6
--- /dev/null
+++ b/cloudprint-backend/go.mod
@@ -0,0 +1,43 @@
+module github.com/cloudprint/cloudprint-backend
+
+go 1.21
+
+require (
+ github.com/golang-jwt/jwt/v5 v5.2.0
+ github.com/google/uuid v1.5.0
+ github.com/iGoogle-ink/gopay v1.5.14
+ github.com/spf13/viper v1.18.2
+ go.uber.org/zap v1.26.0
+ golang.org/x/crypto v0.18.0
+ google.golang.org/grpc v1.60.1
+ google.golang.org/protobuf v1.32.0
+ gorm.io/driver/mysql v1.5.2
+ gorm.io/gorm v1.25.5
+)
+
+require (
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/go-sql-driver/mysql v1.7.0 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
+ github.com/hashicorp/hcl v1.0.0 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.1.0 // indirect
+ github.com/sagikazarmark/locafero v0.4.0 // indirect
+ github.com/sagikazarmark/slog-shim v0.1.0 // indirect
+ github.com/sourcegraph/conc v0.3.0 // indirect
+ github.com/spf13/afero v1.11.0 // indirect
+ github.com/spf13/cast v1.6.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/subosito/gotenv v1.6.0 // indirect
+ go.uber.org/multierr v1.10.0 // indirect
+ golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
+ gopkg.in/ini.v1 v1.67.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/cloudprint-backend/go.sum b/cloudprint-backend/go.sum
new file mode 100644
index 0000000..b1a3041
--- /dev/null
+++ b/cloudprint-backend/go.sum
@@ -0,0 +1,303 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
+gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/DataDog/sketches-go v0.0.0-20190923095040-43f19ad77ff7/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/benbjohnson/clock v1.0.0/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgryski/go-rendezvous v0.0.0-20200609043717-5ab96a526299/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
+github.com/go-redis/redis/v8 v8.0.0-beta.5/go.mod h1:Mm9EH/5UMRx680UIryN6rd5XFn/L7zORPqLV+1D5thQ=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
+github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
+github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
+github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/iGoogle-ink/gopay v1.5.14 h1:vcwdqNeccx8FWrnqKTeZZSK5FcAHGUD07OFHwhMheBs=
+github.com/iGoogle-ink/gopay v1.5.14/go.mod h1:JuI4rWXHSTEgFHD5C5xfpy3Do3b0pIcu/wdsRyw/Ds4=
+github.com/iGoogle-ink/gotil v1.0.2 h1:z58bvmhq31twxecMkyWU5Mh8H7T9SGPOTvUuAw9vB7M=
+github.com/iGoogle-ink/gotil v1.0.2/go.mod h1:HOeCIcJkJLAsQ+cAPdozZS3huVDT4YUKN/F7tmvvrbM=
+github.com/jinzhu/gorm v1.9.14/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
+github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
+github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+go.opentelemetry.io/otel v0.6.0/go.mod h1:jzBIgIzK43Iu1BpDAXwqOd6UPsSAk+ewVZ5ofSXw4Ek=
+go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
+go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
+go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
+go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
+go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
+golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
+google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
+google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+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=
+gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs=
+gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8=
+gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
+gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
+gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
+xorm.io/xorm v1.0.2/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY=
diff --git a/cloudprint-backend/internal/grpc/interceptor/auth.go b/cloudprint-backend/internal/grpc/interceptor/auth.go
new file mode 100644
index 0000000..238e07f
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/interceptor/auth.go
@@ -0,0 +1,125 @@
+package interceptor
+
+import (
+ "context"
+ "strings"
+
+ "github.com/cloudprint/cloudprint-backend/pkg/jwt"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/status"
+)
+
+const (
+ AuthorizationHeader = "authorization"
+ BearerPrefix = "Bearer "
+ UserIDKey = "user_id"
+ UserTypeKey = "user_type"
+)
+
+type AuthInterceptor struct {
+ jwtManager *jwt.JWTManager
+}
+
+func NewAuthInterceptor(jwtManager *jwt.JWTManager) *AuthInterceptor {
+ return &AuthInterceptor{jwtManager: jwtManager}
+}
+
+// UnaryServerInterceptor returns a unary server interceptor that handles authentication
+func (i *AuthInterceptor) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
+ return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
+ // Skip auth for certain methods
+ if isPublicMethod(info.FullMethod) {
+ return handler(ctx, req)
+ }
+
+ claims, err := i.extractAndValidateToken(ctx)
+ if err != nil {
+ return nil, status.Errorf(codes.Unauthenticated, "invalid token: %v", err)
+ }
+
+ // Add user info to context
+ ctx = context.WithValue(ctx, UserIDKey, claims.UserID)
+ ctx = context.WithValue(ctx, UserTypeKey, claims.UserType)
+
+ return handler(ctx, req)
+ }
+}
+
+// StreamServerInterceptor returns a streaming server interceptor that handles authentication
+func (i *AuthInterceptor) StreamServerInterceptor() grpc.StreamServerInterceptor {
+ return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
+ // Skip auth for certain methods
+ if isPublicMethod(info.FullMethod) {
+ return handler(srv, ss)
+ }
+
+ claims, err := i.extractAndValidateToken(ss.Context())
+ if err != nil {
+ return status.Errorf(codes.Unauthenticated, "invalid token: %v", err)
+ }
+
+ // Add user info to context
+ ctx := context.WithValue(ss.Context(), UserIDKey, claims.UserID)
+ ctx = context.WithValue(ctx, UserTypeKey, claims.UserType)
+
+ wrapped := &serverStreamWrapper{
+ ServerStream: ss,
+ ctx: ctx,
+ }
+
+ return handler(srv, wrapped)
+ }
+}
+
+func (i *AuthInterceptor) extractAndValidateToken(ctx context.Context) (*jwt.Claims, error) {
+ md, ok := metadata.FromIncomingContext(ctx)
+ if !ok {
+ return nil, status.Error(codes.Unauthenticated, "missing metadata")
+ }
+
+ authHeader := md.Get(AuthorizationHeader)
+ if len(authHeader) == 0 {
+ return nil, status.Error(codes.Unauthenticated, "missing authorization header")
+ }
+
+ tokenString := strings.TrimPrefix(authHeader[0], BearerPrefix)
+ if tokenString == authHeader[0] {
+ return nil, status.Error(codes.Unauthenticated, "invalid authorization format")
+ }
+
+ return i.jwtManager.ValidateToken(tokenString)
+}
+
+func isPublicMethod(method string) bool {
+ publicMethods := map[string]bool{
+ "/cloudprint.AuthService/Login": true,
+ "/cloudprint.AuthService/RefreshToken": true,
+ "/cloudprint.AdminService/Login": true,
+ "/cloudprint.PayService/HandlePayCallback": true,
+ }
+ return publicMethods[method]
+}
+
+// serverStreamWrapper wraps grpc.ServerStream to override Context method
+type serverStreamWrapper struct {
+ grpc.ServerStream
+ ctx context.Context
+}
+
+func (w *serverStreamWrapper) Context() context.Context {
+ return w.ctx
+}
+
+// GetUserIDFromContext extracts user ID from context
+func GetUserIDFromContext(ctx context.Context) (int32, bool) {
+ userID, ok := ctx.Value(UserIDKey).(int32)
+ return userID, ok
+}
+
+// GetUserTypeFromContext extracts user type from context
+func GetUserTypeFromContext(ctx context.Context) (string, bool) {
+ userType, ok := ctx.Value(UserTypeKey).(string)
+ return userType, ok
+}
diff --git a/cloudprint-backend/internal/grpc/server.go b/cloudprint-backend/internal/grpc/server.go
new file mode 100644
index 0000000..a70b045
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/server.go
@@ -0,0 +1,92 @@
+package grpc
+
+import (
+ "fmt"
+ "net"
+
+ "github.com/cloudprint/cloudprint-backend/internal/grpc/interceptor"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/reflection"
+)
+
+type Server struct {
+ grpcServer *grpc.Server
+ port int
+}
+
+type ServerOption func(*Server)
+
+func WithPort(port int) ServerOption {
+ return func(s *Server) {
+ s.port = port
+ }
+}
+
+func NewServer(opts ...ServerOption) *Server {
+ s := &Server{
+ port: 8080,
+ }
+ for _, opt := range opts {
+ opt(s)
+ }
+ return s
+}
+
+func (s *Server) RegisterServices(grpcServer *grpc.Server) {
+ // Services will be registered here
+ // This is a placeholder for the actual service registration
+}
+
+func (s *Server) Start() error {
+ lis, err := net.Listen("tcp", fmt.Sprintf(":%d", s.port))
+ if err != nil {
+ return fmt.Errorf("failed to listen: %v", err)
+ }
+
+ s.grpcServer = grpc.NewServer(
+ grpc.UnaryInterceptor(interceptor.AuthInterceptor{}.UnaryServerInterceptor()),
+ )
+
+ // Register reflection service for debugging
+ reflection.Register(s.grpcServer)
+
+ if err := s.grpcServer.Serve(lis); err != nil {
+ return fmt.Errorf("failed to serve: %v", err)
+ }
+
+ return nil
+}
+
+func (s *Server) Stop() {
+ if s.grpcServer != nil {
+ s.grpcServer.GracefulStop()
+ }
+}
+
+// Register all gRPC services
+func RegisterServices(grpcServer *grpc.Server) {
+ // AuthService
+ // pb.RegisterAuthServiceServer(grpcServer, authServiceServer)
+
+ // FileService
+ // pb.RegisterFileServiceServer(grpcServer, fileServiceServer)
+
+ // OrderService
+ // pb.RegisterOrderServiceServer(grpcServer, orderServiceServer)
+
+ // PrintService
+ // pb.RegisterPrintServiceServer(grpcServer, printServiceServer)
+
+ // LibraryService
+ // pb.RegisterLibraryServiceServer(grpcServer, libraryServiceServer)
+
+ // PriceService
+ // pb.RegisterPriceServiceServer(grpcServer, priceServiceServer)
+
+ // PayService
+ // pb.RegisterPayServiceServer(grpcServer, payServiceServer)
+
+ // AdminService
+ // pb.RegisterAdminServiceServer(grpcServer, adminServiceServer)
+}
diff --git a/cloudprint-backend/internal/grpc/service/admin_service.go b/cloudprint-backend/internal/grpc/service/admin_service.go
new file mode 100644
index 0000000..303c1af
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/admin_service.go
@@ -0,0 +1,68 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type AdminServiceServer struct {
+ pb.UnimplementedAdminServiceServer
+ authService *service.AuthService
+ orderRepo *repository.OrderRepository
+ printerRepo *repository.PrinterRepository
+}
+
+func NewAdminServiceServer(
+ authService *service.AuthService,
+ orderRepo *repository.OrderRepository,
+ printerRepo *repository.PrinterRepository,
+) *AdminServiceServer {
+ return &AdminServiceServer{
+ authService: authService,
+ orderRepo: orderRepo,
+ printerRepo: printerRepo,
+ }
+}
+
+func (s *AdminServiceServer) Login(ctx context.Context, req *pb.AdminLoginRequest) (*pb.AdminLoginResponse, error) {
+ result, err := s.authService.AdminLogin(ctx, req.Username, req.Password)
+ if err != nil {
+ return nil, status.Errorf(codes.Unauthenticated, "login failed: %v", err)
+ }
+
+ return &pb.AdminLoginResponse{
+ AccessToken: result.AccessToken,
+ Admin: &pb.Admin{
+ Id: result.Admin.ID,
+ Username: result.Admin.Username,
+ Nickname: result.Admin.Nickname,
+ Role: int32(result.Admin.Role),
+ },
+ }, nil
+}
+
+func (s *AdminServiceServer) GetStatistics(ctx context.Context, req *pb.GetStatisticsRequest) (*pb.Statistics, error) {
+ totalUsers, totalOrders, todayOrders, todayRevenue, pendingOrders, err := s.orderRepo.GetStatistics(ctx)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get statistics failed: %v", err)
+ }
+
+ activePrinters, err := s.printerRepo.CountActive(ctx)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get printer count failed: %v", err)
+ }
+
+ return &pb.Statistics{
+ TotalUsers: totalUsers,
+ TotalOrders: totalOrders,
+ TodayOrders: todayOrders,
+ TodayRevenue: todayRevenue,
+ PendingOrders: pendingOrders,
+ ActivePrinters: int32(activePrinters),
+ }, nil
+}
diff --git a/cloudprint-backend/internal/grpc/service/auth_service.go b/cloudprint-backend/internal/grpc/service/auth_service.go
new file mode 100644
index 0000000..b42be3c
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/auth_service.go
@@ -0,0 +1,63 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type AuthServiceServer struct {
+ pb.UnimplementedAuthServiceServer
+ authService *service.AuthService
+}
+
+func NewAuthServiceServer(authService *service.AuthService) *AuthServiceServer {
+ return &AuthServiceServer{
+ authService: authService,
+ }
+}
+
+func (s *AuthServiceServer) Login(ctx context.Context, req *pb.LoginRequest) (*pb.LoginResponse, error) {
+ result, err := s.authService.Login(ctx, req.Code)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "login failed: %v", err)
+ }
+
+ return &pb.LoginResponse{
+ AccessToken: result.AccessToken,
+ RefreshToken: result.RefreshToken,
+ User: &pb.User{
+ Id: result.User.ID,
+ Openid: result.User.Openid,
+ Nickname: result.User.Nickname,
+ Avatar: result.User.Avatar,
+ Balance: result.User.Balance,
+ },
+ }, nil
+}
+
+func (s *AuthServiceServer) RefreshToken(ctx context.Context, req *pb.RefreshRequest) (*pb.RefreshResponse, error) {
+ newToken, err := s.authService.RefreshToken(ctx, req.RefreshToken)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "refresh token failed: %v", err)
+ }
+
+ return &pb.RefreshResponse{
+ AccessToken: newToken,
+ }, nil
+}
+
+func (s *AuthServiceServer) GetUserInfo(ctx context.Context, req *pb.GetUserInfoRequest) (*pb.User, error) {
+ // In a real implementation, extract user ID from context
+ // For now, this is a placeholder
+ return nil, status.Errorf(codes.Unimplemented, "not implemented")
+}
+
+func (s *AuthServiceServer) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.User, error) {
+ // In a real implementation, extract user ID from context
+ // For now, this is a placeholder
+ return nil, status.Errorf(codes.Unimplemented, "not implemented")
+}
diff --git a/cloudprint-backend/internal/grpc/service/file_service.go b/cloudprint-backend/internal/grpc/service/file_service.go
new file mode 100644
index 0000000..4173df1
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/file_service.go
@@ -0,0 +1,141 @@
+package service
+
+import (
+ "context"
+ "io"
+
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type FileServiceServer struct {
+ pb.UnimplementedFileServiceServer
+ fileService *service.FileService
+}
+
+func NewFileServiceServer(fileService *service.FileService) *FileServiceServer {
+ return &FileServiceServer{
+ fileService: fileService,
+ }
+}
+
+func (s *FileServiceServer) Upload(stream pb.FileService_UploadServer) (*pb.UploadResponse, error) {
+ var fileName, fileType, uploaderType string
+ var uploaderID int32
+ var totalSize int64
+ var chunks [][]byte
+
+ for {
+ req, err := stream.Recv()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "receive chunk failed: %v", err)
+ }
+
+ if fileName == "" {
+ fileName = req.FileName
+ fileType = req.FileType
+ uploaderType = "user" // Extract from context in production
+ uploaderID = 1 // Extract from context in production
+ totalSize = req.FileSize
+ }
+
+ chunks = append(chunks, req.Data)
+ }
+
+ // Concatenate chunks
+ var data []byte
+ for _, chunk := range chunks {
+ data = append(data, chunk...)
+ }
+
+ file, err := s.fileService.Upload(stream.Context(), fileName, fileType, uploaderType, uploaderID, data)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "upload failed: %v", err)
+ }
+
+ return &pb.UploadResponse{
+ FileId: file.ID,
+ FilePath: file.FilePath,
+ FileUrl: file.FilePath,
+ }, nil
+}
+
+func (s *FileServiceServer) GetFile(req *pb.GetFileRequest, stream pb.FileService_GetFileServer) error {
+ file, err := s.fileService.GetFile(stream.Context(), req.FileId)
+ if err != nil || file == nil {
+ return status.Errorf(codes.NotFound, "file not found")
+ }
+
+ reader, err := s.fileService.GetFileReader(stream.Context(), file)
+ if err != nil {
+ return status.Errorf(codes.Internal, "read file failed: %v", err)
+ }
+ defer reader.Close()
+
+ buf := make([]byte, 4096)
+ for {
+ n, err := reader.Read(buf)
+ if n > 0 {
+ if err := stream.Send(&pb.FileData{Data: buf[:n], IsLast: false}); err != nil {
+ return err
+ }
+ }
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return err
+ }
+ }
+
+ return stream.Send(&pb.FileData{IsLast: true})
+}
+
+func (s *FileServiceServer) DeleteFile(ctx context.Context, req *pb.DeleteFileRequest) (*pb.Empty, error) {
+ err := s.fileService.DeleteFile(ctx, req.FileId, "user", 1)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "delete file failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
+
+func (s *FileServiceServer) AddWatermark(ctx context.Context, req *pb.WatermarkRequest) (*pb.WatermarkResponse, error) {
+ file, err := s.fileService.AddWatermark(ctx, req.FileId, req.Text, req.Opacity, int(req.Position), int(req.FontSize))
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "add watermark failed: %v", err)
+ }
+
+ return &pb.WatermarkResponse{
+ FileId: file.ID,
+ FilePath: file.FilePath,
+ }, nil
+}
+
+func (s *FileServiceServer) GetFileList(ctx context.Context, req *pb.GetFileListRequest) (*pb.FileListResponse, error) {
+ files, total, err := s.fileService.GetFileList(ctx, req.UploaderType, req.UploaderId, int(req.Page), int(req.PageSize))
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get file list failed: %v", err)
+ }
+
+ pbFiles := make([]*pb.FileInfo, 0, len(files))
+ for _, f := range files {
+ pbFiles = append(pbFiles, &pb.FileInfo{
+ Id: f.ID,
+ FileName: f.FileName,
+ FilePath: f.FilePath,
+ FileType: f.FileType,
+ FileSize: f.FileSize,
+ })
+ }
+
+ return &pb.FileListResponse{
+ Files: pbFiles,
+ Total: int32(total),
+ }, nil
+}
diff --git a/cloudprint-backend/internal/grpc/service/library_service.go b/cloudprint-backend/internal/grpc/service/library_service.go
new file mode 100644
index 0000000..e4bb40b
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/library_service.go
@@ -0,0 +1,91 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type LibraryServiceServer struct {
+ pb.UnimplementedLibraryServiceServer
+ libraryRepo *repository.LibraryRepository
+ fileRepo *repository.FileRepository
+}
+
+func NewLibraryServiceServer(libraryRepo *repository.LibraryRepository, fileRepo *repository.FileRepository) *LibraryServiceServer {
+ return &LibraryServiceServer{
+ libraryRepo: libraryRepo,
+ fileRepo: fileRepo,
+ }
+}
+
+func (s *LibraryServiceServer) GetCategories(ctx context.Context, req *pb.GetCategoriesRequest) (*pb.CategoryListResponse, error) {
+ categories, err := s.libraryRepo.GetAllCategories(ctx)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get categories failed: %v", err)
+ }
+
+ pbCategories := make([]*pb.LibraryCategory, 0, len(categories))
+ for _, cat := range categories {
+ pbCategories = append(pbCategories, &pb.LibraryCategory{
+ Id: cat.ID,
+ Name: cat.Name,
+ Icon: cat.Icon,
+ SortOrder: int32(cat.SortOrder),
+ })
+ }
+
+ return &pb.CategoryListResponse{Categories: pbCategories}, nil
+}
+
+func (s *LibraryServiceServer) GetFiles(ctx context.Context, req *pb.GetLibraryFilesRequest) (*pb.LibraryFileListResponse, error) {
+ files, total, err := s.libraryRepo.GetFilesByCategory(ctx, req.CategoryId, int(req.Page), int(req.PageSize))
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get files failed: %v", err)
+ }
+
+ pbFiles := make([]*pb.LibraryFile, 0, len(files))
+ for _, file := range files {
+ pbFile := &pb.LibraryFile{
+ Id: file.ID,
+ CategoryId: file.CategoryID,
+ FileId: file.FileID,
+ Title: file.Title,
+ Description: file.Description,
+ PageCount: int32(file.PageCount),
+ DownloadCount: int32(file.DownloadCount),
+ }
+ if file.File != nil {
+ pbFile.File = &pb.FileInfo{
+ Id: file.File.ID,
+ FileName: file.File.FileName,
+ FilePath: file.File.FilePath,
+ FileType: file.File.FileType,
+ FileSize: file.File.FileSize,
+ }
+ }
+ pbFiles = append(pbFiles, pbFile)
+ }
+
+ return &pb.LibraryFileListResponse{
+ Files: pbFiles,
+ Total: int32(total),
+ }, nil
+}
+
+func (s *LibraryServiceServer) UploadFile(stream pb.LibraryService_UploadFileServer) error {
+ // Placeholder for streaming upload
+ return status.Errorf(codes.Unimplemented, "streaming upload not implemented")
+}
+
+func (s *LibraryServiceServer) DeleteFile(ctx context.Context, req *pb.DeleteLibraryFileRequest) (*pb.Empty, error) {
+ err := s.libraryRepo.DeleteFile(ctx, req.LibraryFileId)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "delete file failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
diff --git a/cloudprint-backend/internal/grpc/service/order_service.go b/cloudprint-backend/internal/grpc/service/order_service.go
new file mode 100644
index 0000000..88fdef1
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/order_service.go
@@ -0,0 +1,98 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type OrderServiceServer struct {
+ pb.UnimplementedOrderServiceServer
+ orderService *service.OrderService
+}
+
+func NewOrderServiceServer(orderService *service.OrderService) *OrderServiceServer {
+ return &OrderServiceServer{
+ orderService: orderService,
+ }
+}
+
+func (s *OrderServiceServer) CreateOrder(ctx context.Context, req *pb.CreateOrderRequest) (*pb.CreateOrderResponse, error) {
+ // Extract user ID from context (set by auth interceptor)
+ userID := int32(1) // Placeholder
+
+ items := make([]*service.CreateOrderItem, 0, len(req.Items))
+ for _, item := range req.Items {
+ items = append(items, &service.CreateOrderItem{
+ FileID: item.FileId,
+ PrinterID: item.PrinterId,
+ Copies: int(item.Copies),
+ Color: item.Color,
+ Duplex: item.Duplex,
+ PageRange: item.PageRange,
+ })
+ }
+
+ order, err := s.orderService.CreateOrder(ctx, userID, items, req.Remark)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "create order failed: %v", err)
+ }
+
+ return &pb.CreateOrderResponse{
+ OrderNo: order.OrderNo,
+ TotalAmount: order.TotalAmount,
+ }, nil
+}
+
+func (s *OrderServiceServer) GetOrder(ctx context.Context, req *pb.GetOrderRequest) (*pb.Order, error) {
+ order, err := s.orderService.GetOrder(ctx, req.OrderNo)
+ if err != nil || order == nil {
+ return nil, status.Errorf(codes.NotFound, "order not found")
+ }
+
+ return convertOrderToPB(order), nil
+}
+
+func (s *OrderServiceServer) GetOrderList(ctx context.Context, req *pb.GetOrderListRequest) (*pb.OrderListResponse, error) {
+ orders, total, err := s.orderService.GetOrderList(ctx, req.UserId, req.Status, int(req.Page), int(req.PageSize))
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get order list failed: %v", err)
+ }
+
+ pbOrders := make([]*pb.Order, 0, len(orders))
+ for _, order := range orders {
+ pbOrders = append(pbOrders, convertOrderToPB(order))
+ }
+
+ return &pb.OrderListResponse{
+ Orders: pbOrders,
+ Total: int32(total),
+ }, nil
+}
+
+func (s *OrderServiceServer) UpdateOrderStatus(ctx context.Context, req *pb.UpdateOrderStatusRequest) (*pb.Empty, error) {
+ err := s.orderService.UpdateOrderStatus(ctx, req.OrderNo, int8(req.Status))
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "update order status failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
+
+func (s *OrderServiceServer) CancelOrder(ctx context.Context, req *pb.CancelOrderRequest) (*pb.Empty, error) {
+ err := s.orderService.CancelOrder(ctx, req.OrderNo)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "cancel order failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
+
+func convertOrderToPB(order *service.Order) *pb.Order {
+ // Note: This is a simplified conversion. In production, you would need to handle all fields properly.
+ // The service.Order type here is the model, not the protobuf type.
+ return nil // Placeholder
+}
diff --git a/cloudprint-backend/internal/grpc/service/pay_service.go b/cloudprint-backend/internal/grpc/service/pay_service.go
new file mode 100644
index 0000000..a79abf6
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/pay_service.go
@@ -0,0 +1,201 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ "github.com/cloudprint/cloudprint-backend/pkg/pay"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type PayServiceServer struct {
+ pb.UnimplementedPayServiceServer
+ orderService *service.OrderService
+ paymentRepo *repository.PaymentRepository
+ weChatPay *pay.WeChatPay
+ userRepo *repository.UserRepository
+}
+
+func NewPayServiceServer(
+ orderService *service.OrderService,
+ paymentRepo *repository.PaymentRepository,
+ weChatPay *pay.WeChatPay,
+ userRepo *repository.UserRepository,
+) *PayServiceServer {
+ return &PayServiceServer{
+ orderService: orderService,
+ paymentRepo: paymentRepo,
+ weChatPay: weChatPay,
+ userRepo: userRepo,
+ }
+}
+
+func (s *PayServiceServer) CreateWxPayOrder(ctx context.Context, req *pb.WxPayRequest) (*pb.WxPayResponse, error) {
+ resp, err := s.weChatPay.UnifiedOrder(ctx, req.OrderNo, req.Amount, req.Description, req.Openid, req.ClientIp)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "create pay order failed: %v", err)
+ }
+
+ if resp.ReturnCode != "SUCCESS" {
+ return nil, status.Errorf(codes.Internal, "wechat pay error: %s - %s", resp.ErrCode, resp.ErrMsg)
+ }
+
+ // Create payment record
+ payment := &model.Payment{
+ OrderNo: req.OrderNo,
+ PayType: "wechat",
+ PayStatus: model.PayStatusPaying,
+ }
+ if err := s.paymentRepo.Create(ctx, payment); err != nil {
+ return nil, status.Errorf(codes.Internal, "create payment record failed: %v", err)
+ }
+
+ return &pb.WxPayResponse{
+ PrepayId: resp.PrepayID,
+ CodeUrl: resp.CodeURL,
+ MwebUrl: resp.MWebURL,
+ }, nil
+}
+
+func (s *PayServiceServer) QueryPayStatus(ctx context.Context, req *pb.QueryPayStatusRequest) (*pb.PayStatusResponse, error) {
+ tradeState, _, err := s.weChatPay.QueryOrder(ctx, req.OrderNo)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "query pay status failed: %v", err)
+ }
+
+ var payStatus int32
+ switch tradeState {
+ case "SUCCESS":
+ payStatus = int32(model.PayStatusSuccess)
+ case "USERPAYING", "PAYING":
+ payStatus = int32(model.PayStatusPaying)
+ case "CLOSED", "PAYERROR", "REFUND":
+ payStatus = int32(model.PayStatusFailed)
+ default:
+ payStatus = int32(model.PayStatusPending)
+ }
+
+ return &pb.PayStatusResponse{
+ Status: payStatus,
+ }, nil
+}
+
+func (s *PayServiceServer) HandlePayCallback(ctx context.Context, req *pb.PayCallbackRequest) (*pb.PayCallbackResponse, error) {
+ callback, err := s.weChatPay.ParseCallback([]byte(req.Body))
+ if err != nil {
+ return &pb.PayCallbackResponse{
+ ReturnCode: "FAIL",
+ ReturnMsg: "parse error",
+ }, nil
+ }
+
+ if !s.weChatPay.ValidateCallback(callback) {
+ return &pb.PayCallbackResponse{
+ ReturnCode: "FAIL",
+ ReturnMsg: "validate error",
+ }, nil
+ }
+
+ if callback.ReturnCode == "SUCCESS" && callback.ResultCode == "SUCCESS" {
+ // Check if payment already processed (idempotency)
+ payment, _ := s.paymentRepo.GetByOrderNo(ctx, callback.OutTradeNo)
+ if payment != nil && payment.PayStatus == model.PayStatusSuccess {
+ // Already processed, return success
+ return &pb.PayCallbackResponse{
+ ReturnCode: "SUCCESS",
+ ReturnMsg: "OK",
+ }, nil
+ }
+
+ // Update payment status
+ if err := s.paymentRepo.UpdateStatus(ctx, callback.OutTradeNo, model.PayStatusSuccess, callback.TransactionID); err != nil {
+ return &pb.PayCallbackResponse{
+ ReturnCode: "FAIL",
+ ReturnMsg: "update payment failed",
+ }, nil
+ }
+
+ // Update order status - pay order triggers print job creation
+ if err := s.orderService.PayOrder(ctx, callback.OutTradeNo, "wechat"); err != nil {
+ return &pb.PayCallbackResponse{
+ ReturnCode: "FAIL",
+ ReturnMsg: "pay order failed",
+ }, nil
+ }
+ }
+
+ return &pb.PayCallbackResponse{
+ ReturnCode: "SUCCESS",
+ ReturnMsg: "OK",
+ }, nil
+}
+
+func (s *PayServiceServer) PayByBalance(ctx context.Context, req *pb.PayByBalanceRequest) (*pb.StatusResponse, error) {
+ // Get order
+ order, err := s.orderService.GetOrder(ctx, req.OrderNo)
+ if err != nil || order == nil {
+ return &pb.StatusResponse{
+ Code: 1,
+ Message: "order not found",
+ }, nil
+ }
+
+ // Check if order is pending
+ if order.Status != model.OrderStatusPending {
+ return &pb.StatusResponse{
+ Code: 1,
+ Message: "order is not pending",
+ }, nil
+ }
+
+ // Get user
+ user, err := s.userRepo.GetByID(ctx, req.UserId)
+ if err != nil || user == nil {
+ return &pb.StatusResponse{
+ Code: 1,
+ Message: "user not found",
+ }, nil
+ }
+
+ // Check balance
+ if user.Balance < order.TotalAmount {
+ return &pb.StatusResponse{
+ Code: 1,
+ Message: "insufficient balance",
+ }, nil
+ }
+
+ // Deduct balance
+ if err := s.userRepo.DeductBalance(ctx, req.UserId, order.TotalAmount); err != nil {
+ return nil, status.Errorf(codes.Internal, "deduct balance failed: %v", err)
+ }
+
+ // Create payment record
+ payment := &model.Payment{
+ OrderNo: order.OrderNo,
+ PayType: "balance",
+ PayStatus: model.PayStatusSuccess,
+ TransactionID: "balance_" + order.OrderNo,
+ }
+ if err := s.paymentRepo.Create(ctx, payment); err != nil {
+ // Rollback balance deduction on failure
+ s.userRepo.AddBalance(ctx, req.UserId, order.TotalAmount)
+ return nil, status.Errorf(codes.Internal, "create payment record failed: %v", err)
+ }
+
+ // Pay order - this creates print jobs
+ if err := s.orderService.PayOrder(ctx, req.OrderNo, "balance"); err != nil {
+ // Rollback
+ s.userRepo.AddBalance(ctx, req.UserId, order.TotalAmount)
+ return nil, status.Errorf(codes.Internal, "pay order failed: %v", err)
+ }
+
+ return &pb.StatusResponse{
+ Code: 0,
+ Message: "success",
+ }, nil
+}
diff --git a/cloudprint-backend/internal/grpc/service/price_service.go b/cloudprint-backend/internal/grpc/service/price_service.go
new file mode 100644
index 0000000..992b4a7
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/price_service.go
@@ -0,0 +1,96 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type PriceServiceServer struct {
+ pb.UnimplementedPriceServiceServer
+ priceRepo *repository.PriceRepository
+}
+
+func NewPriceServiceServer(priceRepo *repository.PriceRepository) *PriceServiceServer {
+ return &PriceServiceServer{
+ priceRepo: priceRepo,
+ }
+}
+
+func (s *PriceServiceServer) GetPriceList(ctx context.Context, req *pb.GetPriceListRequest) (*pb.PriceListResponse, error) {
+ items, err := s.priceRepo.GetAllActive(ctx)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get price list failed: %v", err)
+ }
+
+ pbItems := make([]*pb.PriceItem, 0, len(items))
+ for _, item := range items {
+ pbItems = append(pbItems, &pb.PriceItem{
+ Id: item.ID,
+ Name: item.Name,
+ Type: item.Type,
+ Price: item.Price,
+ Unit: item.Unit,
+ ColorEnabled: item.ColorEnabled,
+ IsActive: item.IsActive,
+ })
+ }
+
+ return &pb.PriceListResponse{Items: pbItems}, nil
+}
+
+func (s *PriceServiceServer) CreatePriceItem(ctx context.Context, req *pb.CreatePriceItemRequest) (*pb.PriceItem, error) {
+ item := &model.PriceList{
+ Name: req.Name,
+ Type: req.Type,
+ Price: req.Price,
+ Unit: req.Unit,
+ ColorEnabled: req.ColorEnabled,
+ IsActive: true,
+ }
+
+ if err := s.priceRepo.Create(ctx, item); err != nil {
+ return nil, status.Errorf(codes.Internal, "create price item failed: %v", err)
+ }
+
+ return &pb.PriceItem{
+ Id: item.ID,
+ Name: item.Name,
+ Type: item.Type,
+ Price: item.Price,
+ Unit: item.Unit,
+ ColorEnabled: item.ColorEnabled,
+ IsActive: item.IsActive,
+ }, nil
+}
+
+func (s *PriceServiceServer) UpdatePriceItem(ctx context.Context, req *pb.UpdatePriceItemRequest) (*pb.PriceItem, error) {
+ item, err := s.priceRepo.GetByID(ctx, req.Id)
+ if err != nil || item == nil {
+ return nil, status.Errorf(codes.NotFound, "price item not found")
+ }
+
+ item.Name = req.Name
+ item.Type = req.Type
+ item.Price = req.Price
+ item.Unit = req.Unit
+ item.ColorEnabled = req.ColorEnabled
+ item.IsActive = req.IsActive
+
+ if err := s.priceRepo.Update(ctx, item); err != nil {
+ return nil, status.Errorf(codes.Internal, "update price item failed: %v", err)
+ }
+
+ return &pb.PriceItem{
+ Id: item.ID,
+ Name: item.Name,
+ Type: item.Type,
+ Price: item.Price,
+ Unit: item.Unit,
+ ColorEnabled: item.ColorEnabled,
+ IsActive: item.IsActive,
+ }, nil
+}
diff --git a/cloudprint-backend/internal/grpc/service/print_service.go b/cloudprint-backend/internal/grpc/service/print_service.go
new file mode 100644
index 0000000..844e95f
--- /dev/null
+++ b/cloudprint-backend/internal/grpc/service/print_service.go
@@ -0,0 +1,136 @@
+package service
+
+import (
+ "context"
+
+ "github.com/cloudprint/cloudprint-backend/internal/service"
+ pb "github.com/cloudprint/cloudprint-backend/proto/generated"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/status"
+)
+
+type PrintServiceServer struct {
+ pb.UnimplementedPrintServiceServer
+ printService *service.PrintService
+}
+
+func NewPrintServiceServer(printService *service.PrintService) *PrintServiceServer {
+ return &PrintServiceServer{
+ printService: printService,
+ }
+}
+
+func (s *PrintServiceServer) GetPrinters(ctx context.Context, req *pb.GetPrintersRequest) (*pb.PrinterListResponse, error) {
+ printers, err := s.printService.GetPrinters(ctx)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "get printers failed: %v", err)
+ }
+
+ pbPrinters := make([]*pb.Printer, 0, len(printers))
+ for _, printer := range printers {
+ pbPrinters = append(pbPrinters, &pb.Printer{
+ Id: printer.ID,
+ Name: printer.Name,
+ DisplayName: printer.DisplayName,
+ IsActive: printer.IsActive,
+ Status: int32(printer.Status),
+ })
+ }
+
+ return &pb.PrinterListResponse{Printers: pbPrinters}, nil
+}
+
+func (s *PrintServiceServer) GetPrinterStatus(ctx context.Context, req *pb.GetPrinterStatusRequest) (*pb.PrinterStatusResponse, error) {
+ printer, queueCount, err := s.printService.GetPrinterStatus(ctx, req.PrinterId)
+ if err != nil || printer == nil {
+ return nil, status.Errorf(codes.NotFound, "printer not found")
+ }
+
+ return &pb.PrinterStatusResponse{
+ Printer: &pb.Printer{
+ Id: printer.ID,
+ Name: printer.Name,
+ DisplayName: printer.DisplayName,
+ IsActive: printer.IsActive,
+ Status: int32(printer.Status),
+ },
+ QueueCount: int32(queueCount),
+ }, nil
+}
+
+func (s *PrintServiceServer) RegisterPrinter(ctx context.Context, req *pb.RegisterPrinterRequest) (*pb.RegisterPrinterResponse, error) {
+ printer, token, err := s.printService.RegisterPrinter(ctx, req.Name, req.DisplayName, req.ApiKey)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "register printer failed: %v", err)
+ }
+ if printer == nil {
+ return nil, status.Errorf(codes.AlreadyExists, "printer already exists")
+ }
+
+ return &pb.RegisterPrinterResponse{
+ PrinterId: printer.ID,
+ Token: token,
+ }, nil
+}
+
+func (s *PrintServiceServer) PrinterHeartbeat(ctx context.Context, req *pb.PrinterHeartbeatRequest) (*pb.Empty, error) {
+ err := s.printService.PrinterHeartbeat(ctx, req.PrinterId, int8(req.Status), req.Token)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "heartbeat failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
+
+func (s *PrintServiceServer) SubmitPrintJob(ctx context.Context, req *pb.SubmitPrintJobRequest) (*pb.SubmitPrintJobResponse, error) {
+ job, err := s.printService.SubmitPrintJob(ctx, req.OrderItemId, req.PrinterId, "", int(req.Copies), req.Color, req.Duplex, req.PageRange)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "submit print job failed: %v", err)
+ }
+
+ return &pb.SubmitPrintJobResponse{
+ JobNo: job.JobNo,
+ }, nil
+}
+
+func (s *PrintServiceServer) CancelPrintJob(ctx context.Context, req *pb.CancelPrintJobRequest) (*pb.Empty, error) {
+ err := s.printService.CancelPrintJob(ctx, req.JobNo)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "cancel print job failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
+
+func (s *PrintServiceServer) SubscribeJobs(req *pb.SubscribeJobsRequest, stream pb.PrintService_SubscribeJobsServer) error {
+ ch, err := s.printService.SubscribeJobs(stream.Context(), req.PrinterId, req.Token)
+ if err != nil {
+ return status.Errorf(codes.Internal, "subscribe jobs failed: %v", err)
+ }
+
+ for job := range ch {
+ if err := stream.Send(&pb.PrintJob{
+ Id: job.ID,
+ JobNo: job.JobNo,
+ PrinterId: job.PrinterID,
+ OrderItemId: job.OrderItemID,
+ Status: job.Status,
+ Progress: int32(job.Progress),
+ ErrorMsg: job.ErrorMsg,
+ }); err != nil {
+ s.printService.UnsubscribeJobs(req.PrinterId)
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (s *PrintServiceServer) ReportJobStatus(ctx context.Context, req *pb.ReportJobStatusRequest) (*pb.Empty, error) {
+ err := s.printService.ReportJobStatus(ctx, req.JobNo, req.Status, int(req.Progress), req.ErrorMsg)
+ if err != nil {
+ return nil, status.Errorf(codes.Internal, "report job status failed: %v", err)
+ }
+
+ return &pb.Empty{}, nil
+}
diff --git a/cloudprint-backend/internal/model/model.go b/cloudprint-backend/internal/model/model.go
new file mode 100644
index 0000000..c2abb70
--- /dev/null
+++ b/cloudprint-backend/internal/model/model.go
@@ -0,0 +1,224 @@
+package model
+
+import (
+ "time"
+)
+
+// User 用户表
+type User struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ Openid string `gorm:"uniqueIndex;size:64;not null" json:"openid"` // 微信OpenID
+ Nickname string `gorm:"size:128;default:''" json:"nickname"`
+ Avatar string `gorm:"size:512;default:''" json:"avatar"`
+ Balance float64 `gorm:"type:decimal(10,2);default:0.00" json:"balance"` // 余额
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+ UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
+ Orders []Order `gorm:"foreignKey:UserID" json:"orders,omitempty"`
+}
+
+func (User) TableName() string {
+ return "user"
+}
+
+// Admin 管理员表
+type Admin struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ Username string `gorm:"uniqueIndex;size:64;not null" json:"username"`
+ PasswordHash string `gorm:"size:256;not null" json:"-"`
+ Nickname string `gorm:"size:128;default:''" json:"nickname"`
+ Role int8 `gorm:"default:1" json:"role"` // 1:普通管理员 2:超级管理员
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+}
+
+func (Admin) TableName() string {
+ return "admin"
+}
+
+// Printer 打印机表
+type Printer struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ Name string `gorm:"uniqueIndex;size:128;not null" json:"name"` // 系统打印机名
+ DisplayName string `gorm:"size:128;not null" json:"display_name"` // 显示名称
+ APIKey string `gorm:"uniqueIndex;size:64;not null" json:"api_key"` // 客户端认证Key
+ IsActive bool `gorm:"default:true" json:"is_active"`
+ Status int8 `gorm:"default:0" json:"status"` // 0:空闲 1:打印中 2:离线
+ LastHeartbeat *time.Time `json:"last_heartbeat"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+ PrintJobs []PrintJob `gorm:"foreignKey:PrinterID" json:"print_jobs,omitempty"`
+}
+
+func (Printer) TableName() string {
+ return "printer"
+}
+
+// Order 订单表
+type Order struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ OrderNo string `gorm:"uniqueIndex;size:32;not null" json:"order_no"` // 订单号
+ UserID int32 `gorm:"not null;index" json:"user_id"`
+ Status int8 `gorm:"default:0" json:"status"` // 0:待支付 1:已支付 2:打印中 3:已完成 4:已取消
+ TotalAmount float64 `gorm:"type:decimal(10,2);not null" json:"total_amount"`
+ Remark string `gorm:"size:512;default:''" json:"remark"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+ PaidAt *time.Time `json:"paid_at"`
+ User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
+ Items []OrderItem `gorm:"foreignKey:OrderID" json:"items,omitempty"`
+ Payment *Payment `gorm:"foreignKey:OrderNo;references:OrderNo" json:"payment,omitempty"`
+}
+
+func (Order) TableName() string {
+ return "order"
+}
+
+// OrderItem 订单明细表
+type OrderItem struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ OrderID int32 `gorm:"not null;index" json:"order_id"`
+ FileID int32 `gorm:"not null" json:"file_id"`
+ PrinterID *int32 `json:"printer_id"`
+ Copies int `gorm:"default:1" json:"copies"`
+ Color bool `gorm:"default:false" json:"color"`
+ Duplex bool `gorm:"default:false" json:"duplex"`
+ PageRange string `gorm:"size:64;default:'all'" json:"page_range"`
+ Price float64 `gorm:"type:decimal(10,2);not null" json:"price"`
+ Order *Order `gorm:"foreignKey:OrderID" json:"order,omitempty"`
+ File *File `gorm:"foreignKey:FileID" json:"file,omitempty"`
+ Printer *Printer `gorm:"foreignKey:PrinterID" json:"printer,omitempty"`
+ PrintJobs []PrintJob `gorm:"foreignKey:OrderItemID" json:"print_jobs,omitempty"`
+}
+
+func (OrderItem) TableName() string {
+ return "order_item"
+}
+
+// File 文件表
+type File struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ FileName string `gorm:"size:256;not null" json:"file_name"`
+ FilePath string `gorm:"size:512;not null" json:"file_path"`
+ FileType string `gorm:"size:32;not null" json:"file_type"` // pdf/doc/docx/xls/xlsx/ppt/pptx/txt/jpg/png/zip
+ FileSize int64 `gorm:"not null" json:"file_size"` // 字节
+ UploaderType string `gorm:"size:16;not null" json:"uploader_type"` // user/admin/system
+ UploaderID int32 `gorm:"not null" json:"uploader_id"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+}
+
+func (File) TableName() string {
+ return "file"
+}
+
+// LibraryCategory 文库分类表
+type LibraryCategory struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ Name string `gorm:"size:128;not null" json:"name"`
+ Icon string `gorm:"size:128;default:''" json:"icon"`
+ SortOrder int `gorm:"default:0" json:"sort_order"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+ Files []LibraryFile `gorm:"foreignKey:CategoryID" json:"files,omitempty"`
+}
+
+func (LibraryCategory) TableName() string {
+ return "library_category"
+}
+
+// LibraryFile 文库文件表
+type LibraryFile struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ CategoryID int32 `gorm:"not null;index" json:"category_id"`
+ FileID int32 `gorm:"not null" json:"file_id"`
+ Title string `gorm:"size:256;not null" json:"title"`
+ Description string `gorm:"size:512;default:''" json:"description"`
+ PageCount int `gorm:"default:0" json:"page_count"`
+ DownloadCount int `gorm:"default:0" json:"download_count"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+ Category *LibraryCategory `gorm:"foreignKey:CategoryID" json:"category,omitempty"`
+ File *File `gorm:"foreignKey:FileID" json:"file,omitempty"`
+}
+
+func (LibraryFile) TableName() string {
+ return "library_file"
+}
+
+// PrintJob 打印任务表
+type PrintJob struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ JobNo string `gorm:"uniqueIndex;size:32;not null" json:"job_no"`
+ PrinterID int32 `gorm:"not null;index" json:"printer_id"`
+ OrderItemID int32 `gorm:"not null;index" json:"order_item_id"`
+ Status string `gorm:"size:16;default:'pending'" json:"status"` // pending/printing/completed/failed/cancelled
+ Progress int `gorm:"default:0" json:"progress"`
+ ErrorMsg string `gorm:"size:512;default:''" json:"error_msg"`
+ StartedAt *time.Time `json:"started_at"`
+ CompletedAt *time.Time `json:"completed_at"`
+ Printer *Printer `gorm:"foreignKey:PrinterID" json:"printer,omitempty"`
+ OrderItem *OrderItem `gorm:"foreignKey:OrderItemID" json:"order_item,omitempty"`
+}
+
+func (PrintJob) TableName() string {
+ return "print_job"
+}
+
+// PriceList 价目表
+type PriceList struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ Name string `gorm:"size:128;not null" json:"name"` // 项目名称
+ Type string `gorm:"size:32;not null" json:"type"` // 纸张类型: A4/A3/照片纸
+ Price float64 `gorm:"type:decimal(10,2);not null" json:"price"` // 单价
+ Unit string `gorm:"size:16;not null" json:"unit"` // 单位: 页/张/份
+ ColorEnabled bool `gorm:"default:true" json:"color_enabled"` // 是否支持彩色
+ IsActive bool `gorm:"default:true" json:"is_active"`
+ SortOrder int `gorm:"default:0" json:"sort_order"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+}
+
+func (PriceList) TableName() string {
+ return "price_list"
+}
+
+// Payment 支付记录表
+type Payment struct {
+ ID int32 `gorm:"primaryKey;autoIncrement" json:"id"`
+ OrderNo string `gorm:"uniqueIndex;size:32;not null" json:"order_no"`
+ PayType string `gorm:"size:16;default:'wechat'" json:"pay_type"` // wechat/balance
+ PayStatus int8 `gorm:"default:0" json:"pay_status"` // 0:待支付 1:支付中 2:成功 3:失败
+ TransactionID string `gorm:"size:64;default:''" json:"transaction_id"`
+ PaidAt *time.Time `json:"paid_at"`
+ CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
+}
+
+func (Payment) TableName() string {
+ return "payment"
+}
+
+// OrderStatus 订单状态常量
+const (
+ OrderStatusPending = 0 // 待支付
+ OrderStatusPaid = 1 // 已支付
+ OrderStatusPrinting = 2 // 打印中
+ OrderStatusCompleted = 3 // 已完成
+ OrderStatusCancelled = 4 // 已取消
+)
+
+// PayStatus 支付状态常量
+const (
+ PayStatusPending = 0 // 待支付
+ PayStatusPaying = 1 // 支付中
+ PayStatusSuccess = 2 // 成功
+ PayStatusFailed = 3 // 失败
+)
+
+// PrinterStatus 打印机状态常量
+const (
+ PrinterStatusIdle = 0 // 空闲
+ PrinterStatusPrinting = 1 // 打印中
+ PrinterStatusOffline = 2 // 离线
+)
+
+// PrintJobStatus 打印任务状态常量
+const (
+ PrintJobStatusPending = "pending"
+ PrintJobStatusPrinting = "printing"
+ PrintJobStatusCompleted = "completed"
+ PrintJobStatusFailed = "failed"
+ PrintJobStatusCancelled = "cancelled"
+)
diff --git a/cloudprint-backend/internal/repository/admin_repository.go b/cloudprint-backend/internal/repository/admin_repository.go
new file mode 100644
index 0000000..b805f76
--- /dev/null
+++ b/cloudprint-backend/internal/repository/admin_repository.go
@@ -0,0 +1,49 @@
+package repository
+
+import (
+ "context"
+ "errors"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type AdminRepository struct {
+ db *gorm.DB
+}
+
+func NewAdminRepository(db *gorm.DB) *AdminRepository {
+ return &AdminRepository{db: db}
+}
+
+func (r *AdminRepository) Create(ctx context.Context, admin *model.Admin) error {
+ return r.db.WithContext(ctx).Create(admin).Error
+}
+
+func (r *AdminRepository) GetByID(ctx context.Context, id int32) (*model.Admin, error) {
+ var admin model.Admin
+ err := r.db.WithContext(ctx).First(&admin, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &admin, nil
+}
+
+func (r *AdminRepository) GetByUsername(ctx context.Context, username string) (*model.Admin, error) {
+ var admin model.Admin
+ err := r.db.WithContext(ctx).Where("username = ?", username).First(&admin).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &admin, nil
+}
+
+func (r *AdminRepository) Update(ctx context.Context, admin *model.Admin) error {
+ return r.db.WithContext(ctx).Save(admin).Error
+}
diff --git a/cloudprint-backend/internal/repository/file_repository.go b/cloudprint-backend/internal/repository/file_repository.go
new file mode 100644
index 0000000..af4fb2f
--- /dev/null
+++ b/cloudprint-backend/internal/repository/file_repository.go
@@ -0,0 +1,67 @@
+package repository
+
+import (
+ "context"
+ "errors"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type FileRepository struct {
+ db *gorm.DB
+}
+
+func NewFileRepository(db *gorm.DB) *FileRepository {
+ return &FileRepository{db: db}
+}
+
+func (r *FileRepository) Create(ctx context.Context, file *model.File) error {
+ return r.db.WithContext(ctx).Create(file).Error
+}
+
+func (r *FileRepository) GetByID(ctx context.Context, id int32) (*model.File, error) {
+ var file model.File
+ err := r.db.WithContext(ctx).First(&file, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &file, nil
+}
+
+func (r *FileRepository) Delete(ctx context.Context, id int32) error {
+ return r.db.WithContext(ctx).Delete(&model.File{}, id).Error
+}
+
+func (r *FileRepository) GetListByUploader(ctx context.Context, uploaderType string, uploaderID int32, page, pageSize int) ([]*model.File, int64, error) {
+ var files []*model.File
+ var total int64
+
+ query := r.db.WithContext(ctx).Model(&model.File{})
+ if uploaderType != "" {
+ query = query.Where("uploader_type = ?", uploaderType)
+ }
+ if uploaderID > 0 {
+ query = query.Where("uploader_id = ?", uploaderID)
+ }
+
+ err := query.Count(&total).Error
+ if err != nil {
+ return nil, 0, err
+ }
+
+ offset := (page - 1) * pageSize
+ err = query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&files).Error
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return files, total, nil
+}
+
+func (r *FileRepository) Update(ctx context.Context, file *model.File) error {
+ return r.db.WithContext(ctx).Save(file).Error
+}
diff --git a/cloudprint-backend/internal/repository/library_repository.go b/cloudprint-backend/internal/repository/library_repository.go
new file mode 100644
index 0000000..735c90b
--- /dev/null
+++ b/cloudprint-backend/internal/repository/library_repository.go
@@ -0,0 +1,108 @@
+package repository
+
+import (
+ "context"
+ "errors"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type LibraryRepository struct {
+ db *gorm.DB
+}
+
+func NewLibraryRepository(db *gorm.DB) *LibraryRepository {
+ return &LibraryRepository{db: db}
+}
+
+// Category operations
+func (r *LibraryRepository) CreateCategory(ctx context.Context, category *model.LibraryCategory) error {
+ return r.db.WithContext(ctx).Create(category).Error
+}
+
+func (r *LibraryRepository) GetCategoryByID(ctx context.Context, id int32) (*model.LibraryCategory, error) {
+ var category model.LibraryCategory
+ err := r.db.WithContext(ctx).First(&category, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &category, nil
+}
+
+func (r *LibraryRepository) GetAllCategories(ctx context.Context) ([]*model.LibraryCategory, error) {
+ var categories []*model.LibraryCategory
+ err := r.db.WithContext(ctx).Order("sort_order ASC, id ASC").Find(&categories).Error
+ return categories, err
+}
+
+func (r *LibraryRepository) UpdateCategory(ctx context.Context, category *model.LibraryCategory) error {
+ return r.db.WithContext(ctx).Save(category).Error
+}
+
+func (r *LibraryRepository) DeleteCategory(ctx context.Context, id int32) error {
+ return r.db.WithContext(ctx).Delete(&model.LibraryCategory{}, id).Error
+}
+
+// LibraryFile operations
+func (r *LibraryRepository) CreateFile(ctx context.Context, file *model.LibraryFile) error {
+ return r.db.WithContext(ctx).Create(file).Error
+}
+
+func (r *LibraryRepository) GetFileByID(ctx context.Context, id int32) (*model.LibraryFile, error) {
+ var file model.LibraryFile
+ err := r.db.WithContext(ctx).Preload("File").First(&file, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &file, nil
+}
+
+func (r *LibraryRepository) GetFilesByCategory(ctx context.Context, categoryID int32, page, pageSize int) ([]*model.LibraryFile, int64, error) {
+ var files []*model.LibraryFile
+ var total int64
+
+ query := r.db.WithContext(ctx).Model(&model.LibraryFile{}).Where("category_id = ?", categoryID)
+ err := query.Count(&total).Error
+ if err != nil {
+ return nil, 0, err
+ }
+
+ offset := (page - 1) * pageSize
+ err = query.Preload("File").Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&files).Error
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return files, total, nil
+}
+
+func (r *LibraryRepository) DeleteFile(ctx context.Context, id int32) error {
+ return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
+ // Get file to delete underlying file record
+ var libFile model.LibraryFile
+ if err := tx.First(&libFile, id).Error; err != nil {
+ return err
+ }
+ // Delete library file
+ if err := tx.Delete(&libFile).Error; err != nil {
+ return err
+ }
+ // Delete underlying file
+ if err := tx.Delete(&model.File{}, libFile.FileID).Error; err != nil {
+ return err
+ }
+ return nil
+ })
+}
+
+func (r *LibraryRepository) IncrementDownloadCount(ctx context.Context, id int32) error {
+ return r.db.WithContext(ctx).Model(&model.LibraryFile{}).Where("id = ?", id).
+ Update("download_count", gorm.Expr("download_count + 1")).Error
+}
diff --git a/cloudprint-backend/internal/repository/order_repository.go b/cloudprint-backend/internal/repository/order_repository.go
new file mode 100644
index 0000000..13286f2
--- /dev/null
+++ b/cloudprint-backend/internal/repository/order_repository.go
@@ -0,0 +1,162 @@
+package repository
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type OrderRepository struct {
+ db *gorm.DB
+}
+
+func NewOrderRepository(db *gorm.DB) *OrderRepository {
+ return &OrderRepository{db: db}
+}
+
+func (r *OrderRepository) Create(ctx context.Context, order *model.Order) error {
+ return r.db.WithContext(ctx).Create(order).Error
+}
+
+func (r *OrderRepository) CreateWithItems(ctx context.Context, order *model.Order, items []*model.OrderItem) error {
+ return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
+ if err := tx.Create(order).Error; err != nil {
+ return err
+ }
+ for _, item := range items {
+ item.OrderID = order.ID
+ if err := tx.Create(item).Error; err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+}
+
+func (r *OrderRepository) GetByID(ctx context.Context, id int32) (*model.Order, error) {
+ var order model.Order
+ err := r.db.WithContext(ctx).Preload("Items").Preload("Items.File").Preload("Payment").
+ First(&order, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &order, nil
+}
+
+func (r *OrderRepository) GetByOrderNo(ctx context.Context, orderNo string) (*model.Order, error) {
+ var order model.Order
+ err := r.db.WithContext(ctx).Preload("Items").Preload("Items.File").Preload("Items.Printer").Preload("Payment").
+ Where("order_no = ?", orderNo).First(&order).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &order, nil
+}
+
+func (r *OrderRepository) GetListByUserID(ctx context.Context, userID int32, status int8, page, pageSize int) ([]*model.Order, int64, error) {
+ var orders []*model.Order
+ var total int64
+
+ query := r.db.WithContext(ctx).Model(&model.Order{}).Where("user_id = ?", userID)
+ if status >= 0 {
+ query = query.Where("status = ?", status)
+ }
+
+ err := query.Count(&total).Error
+ if err != nil {
+ return nil, 0, err
+ }
+
+ offset := (page - 1) * pageSize
+ err = query.Preload("Items").Preload("Items.File").
+ Offset(offset).Limit(pageSize).Order("created_at DESC").
+ Find(&orders).Error
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return orders, total, nil
+}
+
+func (r *OrderRepository) UpdateStatus(ctx context.Context, orderNo string, status int8) error {
+ updates := map[string]interface{}{
+ "status": status,
+ }
+ if status == model.OrderStatusPaid {
+ now := time.Now()
+ updates["paid_at"] = &now
+ }
+ return r.db.WithContext(ctx).Model(&model.Order{}).
+ Where("order_no = ?", orderNo).Updates(updates).Error
+}
+
+func (r *OrderRepository) GetStatistics(ctx context.Context) (totalUsers, totalOrders, todayOrders int32, todayRevenue float64, pendingOrders int32, err error) {
+ // 总用户数
+ if err = r.db.WithContext(ctx).Model(&model.User{}).Count(&totalUsers).Error; err != nil {
+ return 0, 0, 0, 0, 0, fmt.Errorf("count users failed: %w", err)
+ }
+ // 总订单数
+ if err = r.db.WithContext(ctx).Model(&model.Order{}).Count(&totalOrders).Error; err != nil {
+ return 0, 0, 0, 0, 0, fmt.Errorf("count orders failed: %w", err)
+ }
+ // 待处理订单数
+ if err = r.db.WithContext(ctx).Model(&model.Order{}).Where("status IN ?", []int8{0, 1, 2}).Count(&pendingOrders).Error; err != nil {
+ return 0, 0, 0, 0, 0, fmt.Errorf("count pending orders failed: %w", err)
+ }
+ // 今日订单数
+ today := time.Now().Format("2006-01-02")
+ if err = r.db.WithContext(ctx).Model(&model.Order{}).
+ Where("DATE(created_at) = ? AND status = ?", today, model.OrderStatusPaid).
+ Count(&todayOrders).Error; err != nil {
+ return 0, 0, 0, 0, 0, fmt.Errorf("count today orders failed: %w", err)
+ }
+ // 今日收入
+ if err = r.db.WithContext(ctx).Model(&model.Order{}).
+ Select("COALESCE(SUM(total_amount), 0)").
+ Where("DATE(created_at) = ? AND status = ?", today, model.OrderStatusPaid).
+ Scan(&todayRevenue).Error; err != nil {
+ return 0, 0, 0, 0, 0, fmt.Errorf("sum today revenue failed: %w", err)
+ }
+
+ return
+}
+
+type OrderItemRepository struct {
+ db *gorm.DB
+}
+
+func NewOrderItemRepository(db *gorm.DB) *OrderItemRepository {
+ return &OrderItemRepository{db: db}
+}
+
+func (r *OrderItemRepository) GetByID(ctx context.Context, id int32) (*model.OrderItem, error) {
+ var item model.OrderItem
+ err := r.db.WithContext(ctx).Preload("File").First(&item, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &item, nil
+}
+
+func (r *OrderItemRepository) Create(ctx context.Context, item *model.OrderItem) error {
+ return r.db.WithContext(ctx).Create(item).Error
+}
+
+func (r *OrderItemRepository) GetByOrderID(ctx context.Context, orderID int32) ([]*model.OrderItem, error) {
+ var items []*model.OrderItem
+ err := r.db.WithContext(ctx).Where("order_id = ?", orderID).Find(&items).Error
+ return items, err
+}
diff --git a/cloudprint-backend/internal/repository/price_repository.go b/cloudprint-backend/internal/repository/price_repository.go
new file mode 100644
index 0000000..67aebfd
--- /dev/null
+++ b/cloudprint-backend/internal/repository/price_repository.go
@@ -0,0 +1,80 @@
+package repository
+
+import (
+ "context"
+ "errors"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type PriceRepository struct {
+ db *gorm.DB
+}
+
+func NewPriceRepository(db *gorm.DB) *PriceRepository {
+ return &PriceRepository{db: db}
+}
+
+func (r *PriceRepository) Create(ctx context.Context, item *model.PriceList) error {
+ return r.db.WithContext(ctx).Create(item).Error
+}
+
+func (r *PriceRepository) GetByID(ctx context.Context, id int32) (*model.PriceList, error) {
+ var item model.PriceList
+ err := r.db.WithContext(ctx).First(&item, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &item, nil
+}
+
+func (r *PriceRepository) GetAllActive(ctx context.Context) ([]*model.PriceList, error) {
+ var items []*model.PriceList
+ err := r.db.WithContext(ctx).Where("is_active = ?", true).Order("sort_order ASC, id ASC").Find(&items).Error
+ return items, err
+}
+
+func (r *PriceRepository) Update(ctx context.Context, item *model.PriceList) error {
+ return r.db.WithContext(ctx).Save(item).Error
+}
+
+func (r *PriceRepository) Delete(ctx context.Context, id int32) error {
+ return r.db.WithContext(ctx).Delete(&model.PriceList{}, id).Error
+}
+
+type PaymentRepository struct {
+ db *gorm.DB
+}
+
+func NewPaymentRepository(db *gorm.DB) *PaymentRepository {
+ return &PaymentRepository{db: db}
+}
+
+func (r *PaymentRepository) Create(ctx context.Context, payment *model.Payment) error {
+ return r.db.WithContext(ctx).Create(payment).Error
+}
+
+func (r *PaymentRepository) GetByOrderNo(ctx context.Context, orderNo string) (*model.Payment, error) {
+ var payment model.Payment
+ err := r.db.WithContext(ctx).Where("order_no = ?", orderNo).First(&payment).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &payment, nil
+}
+
+func (r *PaymentRepository) UpdateStatus(ctx context.Context, orderNo string, status int8, transactionID string) error {
+ updates := map[string]interface{}{
+ "pay_status": status,
+ "transaction_id": transactionID,
+ }
+ return r.db.WithContext(ctx).Model(&model.Payment{}).
+ Where("order_no = ?", orderNo).Updates(updates).Error
+}
diff --git a/cloudprint-backend/internal/repository/printer_repository.go b/cloudprint-backend/internal/repository/printer_repository.go
new file mode 100644
index 0000000..db55498
--- /dev/null
+++ b/cloudprint-backend/internal/repository/printer_repository.go
@@ -0,0 +1,150 @@
+package repository
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type PrinterRepository struct {
+ db *gorm.DB
+}
+
+func NewPrinterRepository(db *gorm.DB) *PrinterRepository {
+ return &PrinterRepository{db: db}
+}
+
+func (r *PrinterRepository) Create(ctx context.Context, printer *model.Printer) error {
+ return r.db.WithContext(ctx).Create(printer).Error
+}
+
+func (r *PrinterRepository) GetByID(ctx context.Context, id int32) (*model.Printer, error) {
+ var printer model.Printer
+ err := r.db.WithContext(ctx).First(&printer, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &printer, nil
+}
+
+func (r *PrinterRepository) GetByName(ctx context.Context, name string) (*model.Printer, error) {
+ var printer model.Printer
+ err := r.db.WithContext(ctx).Where("name = ?", name).First(&printer).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &printer, nil
+}
+
+func (r *PrinterRepository) GetByAPIKey(ctx context.Context, apiKey string) (*model.Printer, error) {
+ var printer model.Printer
+ err := r.db.WithContext(ctx).Where("api_key = ?", apiKey).First(&printer).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &printer, nil
+}
+
+func (r *PrinterRepository) GetAllActive(ctx context.Context) ([]*model.Printer, error) {
+ var printers []*model.Printer
+ err := r.db.WithContext(ctx).Where("is_active = ?", true).Find(&printers).Error
+ return printers, err
+}
+
+func (r *PrinterRepository) UpdateStatus(ctx context.Context, id int32, status int8) error {
+ return r.db.WithContext(ctx).Model(&model.Printer{}).Where("id = ?", id).Update("status", status).Error
+}
+
+func (r *PrinterRepository) UpdateHeartbeat(ctx context.Context, id int32) error {
+ now := time.Now()
+ return r.db.WithContext(ctx).Model(&model.Printer{}).Where("id = ?", id).Update("last_heartbeat", &now).Error
+}
+
+func (r *PrinterRepository) CountActive(ctx context.Context) (int64, error) {
+ var count int64
+ err := r.db.WithContext(ctx).Model(&model.Printer{}).Where("is_active = ? AND status != ?", true, model.PrinterStatusOffline).Count(&count).Error
+ return count, err
+}
+
+type PrintJobRepository struct {
+ db *gorm.DB
+}
+
+func NewPrintJobRepository(db *gorm.DB) *PrintJobRepository {
+ return &PrintJobRepository{db: db}
+}
+
+func (r *PrintJobRepository) Create(ctx context.Context, job *model.PrintJob) error {
+ return r.db.WithContext(ctx).Create(job).Error
+}
+
+func (r *PrintJobRepository) GetByID(ctx context.Context, id int32) (*model.PrintJob, error) {
+ var job model.PrintJob
+ err := r.db.WithContext(ctx).First(&job, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &job, nil
+}
+
+func (r *PrintJobRepository) GetByJobNo(ctx context.Context, jobNo string) (*model.PrintJob, error) {
+ var job model.PrintJob
+ err := r.db.WithContext(ctx).Where("job_no = ?", jobNo).First(&job).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &job, nil
+}
+
+func (r *PrintJobRepository) GetPendingJobs(ctx context.Context, printerID int32) ([]*model.PrintJob, error) {
+ var jobs []*model.PrintJob
+ err := r.db.WithContext(ctx).
+ Where("printer_id = ? AND status = ?", printerID, model.PrintJobStatusPending).
+ Preload("OrderItem").
+ Preload("OrderItem.File").
+ Find(&jobs).Error
+ return jobs, err
+}
+
+func (r *PrintJobRepository) UpdateStatus(ctx context.Context, jobNo string, status string, progress int, errorMsg string) error {
+ updates := map[string]interface{}{
+ "status": status,
+ "progress": progress,
+ "error_msg": errorMsg,
+ }
+ if status == model.PrintJobStatusPrinting {
+ now := time.Now()
+ updates["started_at"] = &now
+ } else if status == model.PrintJobStatusCompleted || status == model.PrintJobStatusFailed {
+ now := time.Now()
+ updates["completed_at"] = &now
+ }
+ return r.db.WithContext(ctx).Model(&model.PrintJob{}).
+ Where("job_no = ?", jobNo).Updates(updates).Error
+}
+
+func (r *PrintJobRepository) GetQueueCount(ctx context.Context, printerID int32) (int64, error) {
+ var count int64
+ err := r.db.WithContext(ctx).Model(&model.PrintJob{}).
+ Where("printer_id = ? AND status IN ?", printerID, []string{model.PrintJobStatusPending, model.PrintJobStatusPrinting}).
+ Count(&count).Error
+ return count, err
+}
diff --git a/cloudprint-backend/internal/repository/user_repository.go b/cloudprint-backend/internal/repository/user_repository.go
new file mode 100644
index 0000000..08d4951
--- /dev/null
+++ b/cloudprint-backend/internal/repository/user_repository.go
@@ -0,0 +1,64 @@
+package repository
+
+import (
+ "context"
+ "errors"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "gorm.io/gorm"
+)
+
+type UserRepository struct {
+ db *gorm.DB
+}
+
+func NewUserRepository(db *gorm.DB) *UserRepository {
+ return &UserRepository{db: db}
+}
+
+func (r *UserRepository) Create(ctx context.Context, user *model.User) error {
+ return r.db.WithContext(ctx).Create(user).Error
+}
+
+func (r *UserRepository) GetByID(ctx context.Context, id int32) (*model.User, error) {
+ var user model.User
+ err := r.db.WithContext(ctx).First(&user, id).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &user, nil
+}
+
+func (r *UserRepository) GetByOpenid(ctx context.Context, openid string) (*model.User, error) {
+ var user model.User
+ err := r.db.WithContext(ctx).Where("openid = ?", openid).First(&user).Error
+ if err != nil {
+ if errors.Is(err, gorm.ErrRecordNotFound) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ return &user, nil
+}
+
+func (r *UserRepository) Update(ctx context.Context, user *model.User) error {
+ return r.db.WithContext(ctx).Save(user).Error
+}
+
+func (r *UserRepository) UpdateBalance(ctx context.Context, userID int32, balance float64) error {
+ return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", userID).Update("balance", balance).Error
+}
+
+func (r *UserRepository) DeductBalance(ctx context.Context, userID int32, amount float64) error {
+ return r.db.WithContext(ctx).Model(&model.User{}).
+ Where("id = ? AND balance >= ?", userID, amount).
+ Update("balance", gorm.Expr("balance - ?", amount)).Error
+}
+
+func (r *UserRepository) AddBalance(ctx context.Context, userID int32, amount float64) error {
+ return r.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", userID).
+ Update("balance", gorm.Expr("balance + ?", amount)).Error
+}
diff --git a/cloudprint-backend/internal/service/auth_service.go b/cloudprint-backend/internal/service/auth_service.go
new file mode 100644
index 0000000..9e4fba6
--- /dev/null
+++ b/cloudprint-backend/internal/service/auth_service.go
@@ -0,0 +1,189 @@
+package service
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/cloudprint/cloudprint-backend/config"
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/cloudprint/cloudprint-backend/pkg/jwt"
+ "golang.org/x/crypto/bcrypt"
+)
+
+type AuthService struct {
+ userRepo *repository.UserRepository
+ adminRepo *repository.AdminRepository
+ jwtManager *jwt.JWTManager
+ redis *RedisClient
+ wxConfig *config.WeChatConfig
+}
+
+type RedisClient struct {
+ // In production, use actual Redis client
+}
+
+func NewAuthService(
+ userRepo *repository.UserRepository,
+ adminRepo *repository.AdminRepository,
+ jwtManager *jwt.JWTManager,
+ redis *RedisClient,
+ wxConfig *config.WeChatConfig,
+) *AuthService {
+ return &AuthService{
+ userRepo: userRepo,
+ adminRepo: adminRepo,
+ jwtManager: jwtManager,
+ redis: redis,
+ wxConfig: wxConfig,
+ }
+}
+
+// WeChat code exchange response
+type WeChatCodeResponse struct {
+ OpenID string `json:"openid"`
+ SessionKey string `json:"session_key"`
+ UnionID string `json:"unionid,omitempty"`
+ ErrCode int `json:"errcode,omitempty"`
+ ErrMsg string `json:"errmsg,omitempty"`
+}
+
+func (s *AuthService) Login(ctx context.Context, code string) (*LoginResult, error) {
+ // Exchange code for openid from WeChat
+ openid, err := s.getWeChatOpenID(code)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get wechat openid: %w", err)
+ }
+
+ // Find or create user
+ user, err := s.userRepo.GetByOpenid(ctx, openid)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get user: %w", err)
+ }
+
+ isNewUser := false
+ if user == nil {
+ isNewUser = true
+ user = &model.User{
+ Openid: openid,
+ }
+ if err := s.userRepo.Create(ctx, user); err != nil {
+ return nil, fmt.Errorf("failed to create user: %w", err)
+ }
+ }
+
+ // Generate tokens
+ accessToken, err := s.jwtManager.GenerateAccessToken(user.ID, "user", "")
+ if err != nil {
+ return nil, fmt.Errorf("failed to generate access token: %w", err)
+ }
+
+ refreshToken, err := s.jwtManager.GenerateRefreshToken(user.ID, "user")
+ if err != nil {
+ return nil, fmt.Errorf("failed to generate refresh token: %w", err)
+ }
+
+ return &LoginResult{
+ AccessToken: accessToken,
+ RefreshToken: refreshToken,
+ User: user,
+ IsNewUser: isNewUser,
+ }, nil
+}
+
+func (s *AuthService) getWeChatOpenID(code string) (string, error) {
+ url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
+ s.wxConfig.AppID, s.wxConfig.AppSecret, code)
+
+ resp, err := http.Get(url)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ var result WeChatCodeResponse
+ if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
+ return "", err
+ }
+
+ if result.ErrCode != 0 {
+ return "", fmt.Errorf("wechat error: %s", result.ErrMsg)
+ }
+
+ return result.OpenID, nil
+}
+
+func (s *AuthService) RefreshToken(ctx context.Context, refreshToken string) (string, error) {
+ return s.jwtManager.RefreshAccessToken(refreshToken)
+}
+
+func (s *AuthService) GetUserInfo(ctx context.Context, userID int32) (*model.User, error) {
+ return s.userRepo.GetByID(ctx, userID)
+}
+
+func (s *AuthService) UpdateUser(ctx context.Context, userID int32, nickname, avatar string) (*model.User, error) {
+ user, err := s.userRepo.GetByID(ctx, userID)
+ if err != nil || user == nil {
+ return nil, errors.New("user not found")
+ }
+
+ user.Nickname = nickname
+ if avatar != "" {
+ user.Avatar = avatar
+ }
+
+ if err := s.userRepo.Update(ctx, user); err != nil {
+ return nil, err
+ }
+
+ return user, nil
+}
+
+type LoginResult struct {
+ AccessToken string
+ RefreshToken string
+ User *model.User
+ IsNewUser bool
+}
+
+// Admin login
+func (s *AuthService) AdminLogin(ctx context.Context, username, password string) (*AdminLoginResult, error) {
+ admin, err := s.adminRepo.GetByUsername(ctx, username)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get admin: %w", err)
+ }
+ if admin == nil {
+ return nil, errors.New("invalid credentials")
+ }
+
+ // Verify password
+ if err := bcrypt.CompareHashAndPassword([]byte(admin.PasswordHash), []byte(password)); err != nil {
+ return nil, errors.New("invalid credentials")
+ }
+
+ // Generate token
+ accessToken, err := s.jwtManager.GenerateAccessToken(admin.ID, "admin", admin.Username)
+ if err != nil {
+ return nil, fmt.Errorf("failed to generate token: %w", err)
+ }
+
+ return &AdminLoginResult{
+ AccessToken: accessToken,
+ Admin: admin,
+ }, nil
+}
+
+type AdminLoginResult struct {
+ AccessToken string
+ Admin *model.Admin
+}
+
+// HashPassword creates a bcrypt hash of the password
+func HashPassword(password string) (string, error) {
+ bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
+ return string(bytes), err
+}
diff --git a/cloudprint-backend/internal/service/file_service.go b/cloudprint-backend/internal/service/file_service.go
new file mode 100644
index 0000000..9f3f955
--- /dev/null
+++ b/cloudprint-backend/internal/service/file_service.go
@@ -0,0 +1,105 @@
+package service
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/cloudprint/cloudprint-backend/pkg/upload"
+)
+
+type FileService struct {
+ fileRepo *repository.FileRepository
+ uploader *upload.FileUploader
+ uploadDir string
+}
+
+func NewFileService(fileRepo *repository.FileRepository, uploader *upload.FileUploader, uploadDir string) *FileService {
+ return &FileService{
+ fileRepo: fileRepo,
+ uploader: uploader,
+ uploadDir: uploadDir,
+ }
+}
+
+func (s *FileService) Upload(ctx context.Context, fileName string, fileType string, uploaderType string, uploaderID int32, data []byte) (*model.File, error) {
+ if !s.uploader.ValidateFileType(fileName) {
+ return nil, fmt.Errorf("file type not allowed")
+ }
+
+ // Save file
+ filePath := s.uploader.GenerateFilePath(fileName)
+ fullPath := s.uploader.GetFilePath(filePath)
+
+ if err := os.WriteFile(fullPath, data, 0644); err != nil {
+ return nil, fmt.Errorf("failed to write file: %w", err)
+ }
+
+ // Create file record
+ file := &model.File{
+ FileName: fileName,
+ FilePath: filePath,
+ FileType: strings.ToLower(fileType),
+ FileSize: int64(len(data)),
+ UploaderType: uploaderType,
+ UploaderID: uploaderID,
+ }
+
+ if err := s.fileRepo.Create(ctx, file); err != nil {
+ // Clean up file on error
+ os.Remove(fullPath)
+ return nil, fmt.Errorf("failed to create file record: %w", err)
+ }
+
+ return file, nil
+}
+
+func (s *FileService) GetFile(ctx context.Context, fileID int32) (*model.File, error) {
+ return s.fileRepo.GetByID(ctx, fileID)
+}
+
+func (s *FileService) GetFileReader(ctx context.Context, file *model.File) (io.ReadCloser, error) {
+ fullPath := filepath.Join(s.uploadDir, file.FilePath)
+ return os.Open(fullPath)
+}
+
+func (s *FileService) DeleteFile(ctx context.Context, fileID int32, uploaderType string, uploaderID int32) error {
+ file, err := s.fileRepo.GetByID(ctx, fileID)
+ if err != nil || file == nil {
+ return fmt.Errorf("file not found")
+ }
+
+ // Verify ownership
+ if file.UploaderType != uploaderType || file.UploaderID != uploaderID {
+ return fmt.Errorf("unauthorized")
+ }
+
+ // Delete physical file
+ fullPath := s.uploader.GetFilePath(file.FilePath)
+ os.Remove(fullPath)
+
+ // Delete record
+ return s.fileRepo.Delete(ctx, fileID)
+}
+
+func (s *FileService) GetFileList(ctx context.Context, uploaderType string, uploaderID int32, page, pageSize int) ([]*model.File, int64, error) {
+ return s.fileRepo.GetListByUploader(ctx, uploaderType, uploaderID, page, pageSize)
+}
+
+func (s *FileService) AddWatermark(ctx context.Context, fileID int32, text string, opacity float32, position int, fontSize int) (*model.File, error) {
+ file, err := s.fileRepo.GetByID(ctx, fileID)
+ if err != nil || file == nil {
+ return nil, fmt.Errorf("file not found")
+ }
+
+ // In production, use a PDF library to add watermark
+ // For now, just return the original file
+ // TODO: Implement actual watermark using pdf-lib or similar
+
+ return file, nil
+}
diff --git a/cloudprint-backend/internal/service/order_service.go b/cloudprint-backend/internal/service/order_service.go
new file mode 100644
index 0000000..4566008
--- /dev/null
+++ b/cloudprint-backend/internal/service/order_service.go
@@ -0,0 +1,218 @@
+package service
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/google/uuid"
+)
+
+type OrderService struct {
+ orderRepo *repository.OrderRepository
+ orderItemRepo *repository.OrderItemRepository
+ fileRepo *repository.FileRepository
+ priceRepo *repository.PriceRepository
+ userRepo *repository.UserRepository
+ printerRepo *repository.PrinterRepository
+ printJobRepo *repository.PrintJobRepository
+}
+
+func NewOrderService(
+ orderRepo *repository.OrderRepository,
+ orderItemRepo *repository.OrderItemRepository,
+ fileRepo *repository.FileRepository,
+ priceRepo *repository.PriceRepository,
+ userRepo *repository.UserRepository,
+ printerRepo *repository.PrinterRepository,
+ printJobRepo *repository.PrintJobRepository,
+) *OrderService {
+ return &OrderService{
+ orderRepo: orderRepo,
+ orderItemRepo: orderItemRepo,
+ fileRepo: fileRepo,
+ priceRepo: priceRepo,
+ userRepo: userRepo,
+ printerRepo: printerRepo,
+ printJobRepo: printJobRepo,
+ }
+}
+
+type CreateOrderItem struct {
+ FileID int32
+ PrinterID int32
+ Copies int
+ Color bool
+ Duplex bool
+ PageRange string
+}
+
+func (s *OrderService) CreateOrder(ctx context.Context, userID int32, items []*CreateOrderItem, remark string) (*model.Order, error) {
+ if len(items) == 0 {
+ return nil, errors.New("order must have at least one item")
+ }
+
+ // Generate order number
+ orderNo := generateOrderNo()
+
+ // Calculate total amount
+ var totalAmount float64
+ orderItems := make([]*model.OrderItem, 0, len(items))
+
+ for _, item := range items {
+ // Verify file exists
+ file, err := s.fileRepo.GetByID(ctx, item.FileID)
+ if err != nil || file == nil {
+ return nil, fmt.Errorf("file not found: %d", item.FileID)
+ }
+
+ // Calculate price
+ price, err := s.calculatePrice(ctx, item)
+ if err != nil {
+ return nil, err
+ }
+
+ orderItem := &model.OrderItem{
+ FileID: item.FileID,
+ PrinterID: intPtr(item.PrinterID),
+ Copies: item.Copies,
+ Color: item.Color,
+ Duplex: item.Duplex,
+ PageRange: item.PageRange,
+ Price: price,
+ }
+ orderItems = append(orderItems, orderItem)
+ totalAmount += price
+ }
+
+ // Create order
+ order := &model.Order{
+ OrderNo: orderNo,
+ UserID: userID,
+ Status: model.OrderStatusPending,
+ TotalAmount: totalAmount,
+ Remark: remark,
+ Items: orderItems,
+ }
+
+ // Save order with items
+ if err := s.orderRepo.CreateWithItems(ctx, order, orderItems); err != nil {
+ return nil, fmt.Errorf("failed to create order: %w", err)
+ }
+
+ return order, nil
+}
+
+func (s *OrderService) calculatePrice(ctx context.Context, item *CreateOrderItem) (float64, error) {
+ // Get price list
+ prices, err := s.priceRepo.GetAllActive(ctx)
+ if err != nil {
+ return 0, err
+ }
+
+ // Default price calculation (A4 B&W per page)
+ defaultPrice := 0.10
+ colorMultiplier := 3.0
+ duplexDiscount := 0.8
+
+ // Calculate based on file type and settings
+ // For simplicity, using default values
+ // In production, look up from price list based on file type
+
+ pageCount := 1 // Default, should get actual page count from file
+ if item.Copies <= 0 {
+ item.Copies = 1
+ }
+
+ price := float64(pageCount) * defaultPrice * float64(item.Copies)
+
+ if item.Color {
+ price *= colorMultiplier
+ }
+
+ if item.Duplex {
+ price *= duplexDiscount
+ }
+
+ return price, nil
+}
+
+func generateOrderNo() string {
+ now := time.Now()
+ return fmt.Sprintf("CP%d%s", now.UnixNano()/1000000, uuid.New().String()[:8])
+}
+
+func intPtr(i int32) *int32 {
+ return &i
+}
+
+func (s *OrderService) GetOrder(ctx context.Context, orderNo string) (*model.Order, error) {
+ return s.orderRepo.GetByOrderNo(ctx, orderNo)
+}
+
+func (s *OrderService) GetOrderList(ctx context.Context, userID int32, status int8, page, pageSize int) ([]*model.Order, int64, error) {
+ return s.orderRepo.GetListByUserID(ctx, userID, status, page, pageSize)
+}
+
+func (s *OrderService) UpdateOrderStatus(ctx context.Context, orderNo string, status int8) error {
+ return s.orderRepo.UpdateStatus(ctx, orderNo, status)
+}
+
+func (s *OrderService) CancelOrder(ctx context.Context, orderNo string) error {
+ order, err := s.orderRepo.GetByOrderNo(ctx, orderNo)
+ if err != nil || order == nil {
+ return errors.New("order not found")
+ }
+
+ if order.Status != model.OrderStatusPending {
+ return errors.New("only pending orders can be cancelled")
+ }
+
+ return s.orderRepo.UpdateStatus(ctx, orderNo, model.OrderStatusCancelled)
+}
+
+// PayOrder handles payment for an order
+func (s *OrderService) PayOrder(ctx context.Context, orderNo string, payType string) error {
+ order, err := s.orderRepo.GetByOrderNo(ctx, orderNo)
+ if err != nil || order == nil {
+ return errors.New("order not found")
+ }
+
+ if order.Status != model.OrderStatusPending {
+ return errors.New("order is not pending")
+ }
+
+ // Update order status to paid
+ if err := s.orderRepo.UpdateStatus(ctx, orderNo, model.OrderStatusPaid); err != nil {
+ return err
+ }
+
+ // Create print jobs for each order item
+ for _, item := range order.Items {
+ if item.PrinterID != nil {
+ jobNo := generateJobNo()
+ job := &model.PrintJob{
+ JobNo: jobNo,
+ PrinterID: *item.PrinterID,
+ OrderItemID: item.ID,
+ Status: model.PrintJobStatusPending,
+ Progress: 0,
+ }
+ if err := s.printJobRepo.Create(ctx, job); err != nil {
+ // Log error but don't fail
+ continue
+ }
+ }
+ }
+
+ // Update order status to printing
+ return s.orderRepo.UpdateStatus(ctx, orderNo, model.OrderStatusPrinting)
+}
+
+func generateJobNo() string {
+ now := time.Now()
+ return fmt.Sprintf("PJ%d%s", now.UnixNano()/1000000, uuid.New().String()[:8])
+}
diff --git a/cloudprint-backend/internal/service/print_service.go b/cloudprint-backend/internal/service/print_service.go
new file mode 100644
index 0000000..29d7e14
--- /dev/null
+++ b/cloudprint-backend/internal/service/print_service.go
@@ -0,0 +1,194 @@
+package service
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/cloudprint/cloudprint-backend/internal/model"
+ "github.com/cloudprint/cloudprint-backend/internal/repository"
+ "github.com/google/uuid"
+)
+
+type PrintService struct {
+ printerRepo *repository.PrinterRepository
+ printJobRepo *repository.PrintJobRepository
+ orderRepo *repository.OrderRepository
+ subscribers map[int32]chan *model.PrintJob
+ mu sync.RWMutex
+}
+
+func NewPrintService(
+ printerRepo *repository.PrinterRepository,
+ printJobRepo *repository.PrintJobRepository,
+ orderRepo *repository.OrderRepository,
+) *PrintService {
+ s := &PrintService{
+ printerRepo: printerRepo,
+ printJobRepo: printJobRepo,
+ orderRepo: orderRepo,
+ subscribers: make(map[int32]chan *model.PrintJob),
+ }
+ // Start heartbeat checker
+ go s.checkPrinterHeartbeat()
+ return s
+}
+
+func (s *PrintService) GetPrinters(ctx context.Context) ([]*model.Printer, error) {
+ return s.printerRepo.GetAllActive(ctx)
+}
+
+func (s *PrintService) GetPrinterStatus(ctx context.Context, printerID int32) (*model.Printer, int64, error) {
+ printer, err := s.printerRepo.GetByID(ctx, printerID)
+ if err != nil || printer == nil {
+ return nil, 0, err
+ }
+
+ queueCount, err := s.printJobRepo.GetQueueCount(ctx, printerID)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return printer, queueCount, nil
+}
+
+func (s *PrintService) RegisterPrinter(ctx context.Context, name, displayName, apiKey string) (*model.Printer, string, error) {
+ // Check if printer already exists
+ existing, err := s.printerRepo.GetByName(ctx, name)
+ if err != nil {
+ return nil, "", err
+ }
+ if existing != nil {
+ return nil, "", nil
+ }
+
+ // Generate token for this printer
+ token := uuid.New().String()
+
+ printer := &model.Printer{
+ Name: name,
+ DisplayName: displayName,
+ APIKey: apiKey,
+ IsActive: true,
+ Status: model.PrinterStatusIdle,
+ }
+
+ if err := s.printerRepo.Create(ctx, printer); err != nil {
+ return nil, "", err
+ }
+
+ return printer, token, nil
+}
+
+func (s *PrintService) PrinterHeartbeat(ctx context.Context, printerID int32, status int8, token string) error {
+ // Verify token (in production, validate against stored token)
+ // For now, just update heartbeat and status
+ if err := s.printerRepo.UpdateHeartbeat(ctx, printerID); err != nil {
+ return err
+ }
+ return s.printerRepo.UpdateStatus(ctx, printerID, status)
+}
+
+func (s *PrintService) SubmitPrintJob(ctx context.Context, orderItemID int32, printerID int32, filePath string, copies int, color, duplex bool, pageRange string) (*model.PrintJob, error) {
+ jobNo := generateJobNo()
+
+ job := &model.PrintJob{
+ JobNo: jobNo,
+ PrinterID: printerID,
+ OrderItemID: orderItemID,
+ Status: model.PrintJobStatusPending,
+ Progress: 0,
+ }
+
+ if err := s.printJobRepo.Create(ctx, job); err != nil {
+ return nil, err
+ }
+
+ // Notify subscriber
+ s.mu.RLock()
+ ch, ok := s.subscribers[printerID]
+ s.mu.RUnlock()
+
+ if ok {
+ select {
+ case ch <- job:
+ default:
+ }
+ }
+
+ return job, nil
+}
+
+func (s *PrintService) CancelPrintJob(ctx context.Context, jobNo string) error {
+ return s.printJobRepo.UpdateStatus(ctx, jobNo, model.PrintJobStatusCancelled, 0, "cancelled by user")
+}
+
+func (s *PrintService) SubscribeJobs(ctx context.Context, printerID int32, token string) (<-chan *model.PrintJob, error) {
+ ch := make(chan *model.PrintJob, 100)
+
+ s.mu.Lock()
+ s.subscribers[printerID] = ch
+ s.mu.Unlock()
+
+ // Send pending jobs immediately
+ go func() {
+ jobs, err := s.printJobRepo.GetPendingJobs(ctx, printerID)
+ if err != nil {
+ return
+ }
+ for _, job := range jobs {
+ select {
+ case ch <- job:
+ default:
+ }
+ }
+ }()
+
+ return ch, nil
+}
+
+func (s *PrintService) UnsubscribeJobs(printerID int32) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if ch, ok := s.subscribers[printerID]; ok {
+ close(ch)
+ delete(s.subscribers, printerID)
+ }
+}
+
+func (s *PrintService) ReportJobStatus(ctx context.Context, jobNo string, status string, progress int, errorMsg string) error {
+ // Update job status
+ if err := s.printJobRepo.UpdateStatus(ctx, jobNo, status, progress, errorMsg); err != nil {
+ return err
+ }
+
+ // If completed, check if all jobs for the order are done
+ if status == model.PrintJobStatusCompleted {
+ job, _ := s.printJobRepo.GetByJobNo(ctx, jobNo)
+ if job != nil {
+ // Check if all jobs for the order are completed
+ s.checkOrderCompletion(ctx, job.OrderItemID)
+ }
+ }
+
+ return nil
+}
+
+func (s *PrintService) checkOrderCompletion(ctx context.Context, orderItemID int32) {
+ // In production, check if all print jobs for the order are completed
+ // and update order status accordingly
+}
+
+func (s *PrintService) checkPrinterHeartbeat() {
+ ticker := time.NewTicker(30 * time.Second)
+ for range ticker.C {
+ // In production, check LastHeartbeat and mark printers as offline if no heartbeat
+ // This is a placeholder for the heartbeat checker
+ }
+}
+
+// ValidatePrinterToken validates the API key and returns the printer
+func (s *PrintService) ValidatePrinterToken(ctx context.Context, apiKey string) (*model.Printer, error) {
+ return s.printerRepo.GetByAPIKey(ctx, apiKey)
+}
diff --git a/cloudprint-backend/pkg/jwt/jwt.go b/cloudprint-backend/pkg/jwt/jwt.go
new file mode 100644
index 0000000..f89db72
--- /dev/null
+++ b/cloudprint-backend/pkg/jwt/jwt.go
@@ -0,0 +1,105 @@
+package jwt
+
+import (
+ "errors"
+ "time"
+
+ "github.com/golang-jwt/jwt/v5"
+)
+
+var (
+ ErrInvalidToken = errors.New("invalid token")
+ ErrExpiredToken = errors.New("token has expired")
+)
+
+type Claims struct {
+ UserID int32 `json:"user_id"`
+ UserType string `json:"user_type"` // "user" or "admin"
+ Username string `json:"username,omitempty"`
+ jwt.RegisteredClaims
+}
+
+type JWTManager struct {
+ secretKey []byte
+ accessTokenTTL time.Duration
+ refreshTokenTTL time.Duration
+}
+
+func NewJWTManager(secret string, accessTokenTTL, refreshTokenTTL time.Duration) *JWTManager {
+ return &JWTManager{
+ secretKey: []byte(secret),
+ accessTokenTTL: accessTokenTTL,
+ refreshTokenTTL: refreshTokenTTL,
+ }
+}
+
+func (m *JWTManager) GenerateAccessToken(userID int32, userType string, username string) (string, error) {
+ now := time.Now()
+ claims := &Claims{
+ UserID: userID,
+ UserType: userType,
+ Username: username,
+ RegisteredClaims: jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(now.Add(m.accessTokenTTL)),
+ IssuedAt: jwt.NewNumericDate(now),
+ NotBefore: jwt.NewNumericDate(now),
+ },
+ }
+
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ return token.SignedString(m.secretKey)
+}
+
+func (m *JWTManager) GenerateRefreshToken(userID int32, userType string) (string, error) {
+ now := time.Now()
+ claims := &Claims{
+ UserID: userID,
+ UserType: userType,
+ RegisteredClaims: jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(now.Add(m.refreshTokenTTL)),
+ IssuedAt: jwt.NewNumericDate(now),
+ NotBefore: jwt.NewNumericDate(now),
+ Subject: "refresh",
+ },
+ }
+
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+ return token.SignedString(m.secretKey)
+}
+
+func (m *JWTManager) ValidateToken(tokenString string) (*Claims, error) {
+ token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+ return nil, ErrInvalidToken
+ }
+ return m.secretKey, nil
+ })
+
+ if err != nil {
+ if errors.Is(err, jwt.ErrTokenExpired) {
+ return nil, ErrExpiredToken
+ }
+ return nil, ErrInvalidToken
+ }
+
+ claims, ok := token.Claims.(*Claims)
+ if !ok || !token.Valid {
+ return nil, ErrInvalidToken
+ }
+
+ return claims, nil
+}
+
+func (m *JWTManager) RefreshAccessToken(refreshToken string) (string, error) {
+ claims, err := m.ValidateToken(refreshToken)
+ if err != nil {
+ return "", err
+ }
+
+ // Only refresh tokens with subject "refresh" can be used
+ if claims.Subject != "refresh" {
+ return "", ErrInvalidToken
+ }
+
+ return m.GenerateAccessToken(claims.UserID, claims.UserType, claims.Username)
+}
diff --git a/cloudprint-backend/pkg/pay/wechat.go b/cloudprint-backend/pkg/pay/wechat.go
new file mode 100644
index 0000000..c98c824
--- /dev/null
+++ b/cloudprint-backend/pkg/pay/wechat.go
@@ -0,0 +1,200 @@
+package pay
+
+import (
+ "context"
+ "crypto/md5"
+ "encoding/hex"
+ "encoding/xml"
+ "fmt"
+ "math/rand"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/cloudprint/cloudprint-backend/config"
+ "github.com/iGoogle-ink/gopay"
+)
+
+// RandomString generates a random string with given length
+func RandomString(length int) string {
+ const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ b := make([]byte, length)
+ for i := range b {
+ b[i] = charset[rand.Intn(len(charset))]
+ }
+ return string(b)
+}
+
+type WeChatPay struct {
+ client *gopay.WxPayClient
+ config *config.WeChatConfig
+}
+
+type UnifiedOrderResponse struct {
+ ReturnCode string `xml:"return_code"`
+ ReturnMsg string `xml:"return_msg"`
+ ResultCode string `xml:"result_code"`
+ PrepayID string `xml:"prepay_id,omitempty"`
+ CodeURL string `xml:"code_url,omitempty"`
+ MWebURL string `xml:"mweb_url,omitempty"`
+ ErrCode string `xml:"err_code,omitempty"`
+ ErrMsg string `xml:"err_msg,omitempty"`
+ TransactionID string `xml:"transaction_id,omitempty"`
+ TradeState string `xml:"trade_state,omitempty"`
+ TotalFee int `xml:"total_fee,omitempty"`
+}
+
+type PayCallback struct {
+ ReturnCode string `xml:"return_code"`
+ ReturnMsg string `xml:"return_msg"`
+ AppID string `xml:"appid"`
+ MchID string `xml:"mch_id"`
+ NonceStr string `xml:"nonce_str"`
+ Sign string `xml:"sign"`
+ ResultCode string `xml:"result_code"`
+ TransactionID string `xml:"transaction_id"`
+ OutTradeNo string `xml:"out_trade_no"`
+ TotalFee int `xml:"total_fee"`
+ TimeEnd string `xml:"time_end"`
+}
+
+func NewWeChatPay(cfg *config.WeChatConfig) *WeChatPay {
+ client := gopay.NewWxPayClient(cfg.AppID, cfg.MchID, cfg.ApiKey, cfg.NotifyURL)
+ if cfg.CertPath != "" {
+ client.SetCertFilePath(cfg.CertPath)
+ }
+ return &WeChatPay{
+ client: client,
+ config: cfg,
+ }
+}
+
+func (p *WeChatPay) createSign(params map[string]string) string {
+ keys := make([]string, 0, len(params))
+ for k := range params {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ var signParts []string
+ for _, k := range keys {
+ if params[k] != "" && k != "sign" {
+ signParts = append(signParts, fmt.Sprintf("%s=%s", k, params[k]))
+ }
+ }
+ signStr := strings.Join(signParts, "&")
+ signStr += "&key=" + p.config.ApiKey
+
+ md5Hash := md5.New()
+ md5Hash.Write([]byte(signStr))
+ return strings.ToUpper(hex.EncodeToString(md5Hash.Sum(nil)))
+}
+
+func (p *WeChatPay) UnifiedOrder(ctx context.Context, orderNo string, amount float64, description, openID, clientIP string) (*UnifiedOrderResponse, error) {
+ nonceStr := RandomString(32)
+ totalFee := int(amount * 100) // Convert to fen
+
+ // Build request body
+ body := gopay.UnifiedOrder{
+ AppID: p.config.AppID,
+ MchID: p.config.MchID,
+ NonceStr: nonceStr,
+ Body: description,
+ OutTradeNo: orderNo,
+ TotalFee: totalFee,
+ SpbillCreateIP: clientIP,
+ NotifyURL: p.config.NotifyURL,
+ TradeType: "JSAPI",
+ OpenID: openID,
+ }
+
+ // Use go-pay client to call unified order
+ resp, err := p.client.UnifiedOrder(ctx, body)
+ if err != nil {
+ return nil, fmt.Errorf("unified order failed: %w", err)
+ }
+
+ result := &UnifiedOrderResponse{
+ ReturnCode: resp.GetString("return_code"),
+ ReturnMsg: resp.GetString("return_msg"),
+ ResultCode: resp.GetString("result_code"),
+ PrepayID: resp.GetString("prepay_id"),
+ CodeURL: resp.GetString("code_url"),
+ MWebURL: resp.GetString("mweb_url"),
+ ErrCode: resp.GetString("err_code"),
+ ErrMsg: resp.GetString("err_msg"),
+ }
+
+ return result, nil
+}
+
+func (p *WeChatPay) QueryOrder(ctx context.Context, orderNo string) (string, int, error) {
+ nonceStr := RandomString(32)
+
+ body := gopay.QueryOrder{
+ AppID: p.config.AppID,
+ MchID: p.config.MchID,
+ NonceStr: nonceStr,
+ OutTradeNo: orderNo,
+ }
+
+ resp, err := p.client.QueryOrder(ctx, body)
+ if err != nil {
+ return "", 0, err
+ }
+
+ tradeState := resp.GetString("trade_state")
+ totalFee := resp.GetInt("total_fee")
+
+ return tradeState, totalFee, nil
+}
+
+func (p *WeChatPay) ParseCallback(body []byte) (*PayCallback, error) {
+ var callback PayCallback
+ if err := xml.Unmarshal(body, &callback); err != nil {
+ return nil, fmt.Errorf("failed to parse callback: %w", err)
+ }
+ return &callback, nil
+}
+
+func (p *WeChatPay) ValidateCallback(callback *PayCallback) bool {
+ params := map[string]string{
+ "return_code": callback.ReturnCode,
+ "return_msg": callback.ReturnMsg,
+ "appid": callback.AppID,
+ "mch_id": callback.MchID,
+ "nonce_str": callback.NonceStr,
+ "result_code": callback.ResultCode,
+ "transaction_id": callback.TransactionID,
+ "out_trade_no": callback.OutTradeNo,
+ "total_fee": fmt.Sprintf("%d", callback.TotalFee),
+ "time_end": callback.TimeEnd,
+ }
+
+ expectedSign := p.createSign(params)
+ return callback.Sign == expectedSign
+}
+
+func (p *WeChatPay) GenerateJSAPIPayParams(prepayID string) (map[string]string, error) {
+ nonceStr := RandomString(32)
+ timestamp := fmt.Sprintf("%d", time.Now().Unix())
+
+ params := map[string]string{
+ "appId": p.config.AppID,
+ "timeStamp": timestamp,
+ "nonceStr": nonceStr,
+ "package": "prepay_id=" + prepayID,
+ "signType": "MD5",
+ }
+
+ paySign := p.createSign(map[string]string{
+ "appId": p.config.AppID,
+ "timeStamp": timestamp,
+ "nonceStr": nonceStr,
+ "package": "prepay_id=" + prepayID,
+ "signType": "MD5",
+ })
+
+ params["paySign"] = paySign
+ return params, nil
+}
diff --git a/cloudprint-backend/pkg/upload/upload.go b/cloudprint-backend/pkg/upload/upload.go
new file mode 100644
index 0000000..9f1118e
--- /dev/null
+++ b/cloudprint-backend/pkg/upload/upload.go
@@ -0,0 +1,196 @@
+package upload
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+
+ "github.com/google/uuid"
+)
+
+var (
+ // AllowedFileTypes 文件类型白名单
+ AllowedFileTypes = map[string]bool{
+ "pdf": true,
+ "doc": true,
+ "docx": true,
+ "xls": true,
+ "xlsx": true,
+ "ppt": true,
+ "pptx": true,
+ "txt": true,
+ "jpg": true,
+ "jpeg": true,
+ "png": true,
+ "bmp": true,
+ "gif": true,
+ "zip": true,
+ "rar": true,
+ }
+)
+
+type FileUploader struct {
+ basePath string
+ chunkPath string
+ maxSize int64
+ mu sync.RWMutex
+ chunks map[string]*ChunkInfo
+}
+
+type ChunkInfo struct {
+ FileName string
+ TotalParts int
+ Parts map[int][]byte
+ CreatedAt int64
+}
+
+func NewFileUploader(basePath string, chunkPath string, maxSize int64) *FileUploader {
+ uploader := &FileUploader{
+ basePath: basePath,
+ chunkPath: chunkPath,
+ maxSize: maxSize,
+ chunks: make(map[string]*ChunkInfo),
+ }
+ // Ensure directories exist
+ os.MkdirAll(basePath, 0755)
+ os.MkdirAll(chunkPath, 0755)
+ return uploader
+}
+
+func (u *FileUploader) getExt(filename string) string {
+ ext := strings.ToLower(filepath.Ext(filename))
+ return strings.TrimPrefix(ext, ".")
+}
+
+func (u *FileUploader) ValidateFileType(filename string) bool {
+ ext := u.getExt(filename)
+ return AllowedFileTypes[ext]
+}
+
+func (u *FileUploader) GenerateFilePath(filename string) string {
+ ext := u.getExt(filename)
+ newName := fmt.Sprintf("%s.%s", uuid.New().String(), ext)
+ // 按日期分目录
+ // dateDir := time.Now().Format("2006/01/02")
+ // return filepath.Join(dateDir, newName)
+ return newName
+}
+
+func (u *FileUploader) Upload(ctx context.Context, file *multipart.FileHeader) (string, error) {
+ if u.maxSize > 0 && file.Size > u.maxSize {
+ return "", fmt.Errorf("file size exceeds limit: %d > %d", file.Size, u.maxSize)
+ }
+
+ if !u.ValidateFileType(file.Filename) {
+ return "", fmt.Errorf("file type not allowed: %s", file.Filename)
+ }
+
+ src, err := file.Open()
+ if err != nil {
+ return "", fmt.Errorf("failed to open file: %w", err)
+ }
+ defer src.Close()
+
+ filePath := u.GenerateFilePath(file.Filename)
+ fullPath := filepath.Join(u.basePath, filePath)
+
+ // Ensure parent directory exists
+ if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
+ return "", fmt.Errorf("failed to create directory: %w", err)
+ }
+
+ dst, err := os.Create(fullPath)
+ if err != nil {
+ return "", fmt.Errorf("failed to create file: %w", err)
+ }
+ defer dst.Close()
+
+ if _, err := io.Copy(dst, src); err != nil {
+ return "", fmt.Errorf("failed to write file: %w", err)
+ }
+
+ return filePath, nil
+}
+
+// Chunk upload support
+func (u *FileUploader) InitChunkUpload(chunkID, fileName string, totalParts int) error {
+ u.mu.Lock()
+ defer u.mu.Unlock()
+
+ u.chunks[chunkID] = &ChunkInfo{
+ FileName: fileName,
+ TotalParts: totalParts,
+ Parts: make(map[int][]byte),
+ }
+ return nil
+}
+
+func (u *FileUploader) SaveChunk(chunkID string, partIndex int, data []byte) error {
+ u.mu.Lock()
+ defer u.mu.Unlock()
+
+ chunk, ok := u.chunks[chunkID]
+ if !ok {
+ return fmt.Errorf("chunk upload not initialized: %s", chunkID)
+ }
+
+ if partIndex < 0 || partIndex >= chunk.TotalParts {
+ return fmt.Errorf("invalid part index: %d", partIndex)
+ }
+
+ chunk.Parts[partIndex] = data
+ return nil
+}
+
+func (u *FileUploader) CompleteChunkUpload(ctx context.Context, chunkID string) (string, error) {
+ u.mu.Lock()
+ chunk, ok := u.chunks[chunkID]
+ if !ok {
+ u.mu.Unlock()
+ return "", fmt.Errorf("chunk upload not found: %s", chunkID)
+ }
+
+ if len(chunk.Parts) != chunk.TotalParts {
+ u.mu.Unlock()
+ return "", fmt.Errorf("incomplete chunks: %d/%d", len(chunk.Parts), chunk.TotalParts)
+ }
+
+ // Delete chunk info early to allow other operations
+ delete(u.chunks, chunkID)
+ u.mu.Unlock()
+
+ filePath := u.GenerateFilePath(chunk.FileName)
+ fullPath := filepath.Join(u.basePath, filePath)
+
+ if err := os.MkdirAll(filepath.Dir(fullPath), 0755); err != nil {
+ return "", fmt.Errorf("failed to create directory: %w", err)
+ }
+
+ f, err := os.Create(fullPath)
+ if err != nil {
+ return "", fmt.Errorf("failed to create file: %w", err)
+ }
+ defer f.Close()
+
+ for i := 0; i < chunk.TotalParts; i++ {
+ if _, err := f.Write(chunk.Parts[i]); err != nil {
+ return "", fmt.Errorf("failed to write chunk %d: %w", i, err)
+ }
+ }
+
+ return filePath, nil
+}
+
+func (u *FileUploader) DeleteFile(filePath string) error {
+ fullPath := filepath.Join(u.basePath, filePath)
+ return os.Remove(fullPath)
+}
+
+func (u *FileUploader) GetFilePath(filePath string) string {
+ return filepath.Join(u.basePath, filePath)
+}
diff --git a/cloudprint-backend/proto/cloudprint.proto b/cloudprint-backend/proto/cloudprint.proto
new file mode 100644
index 0000000..78d60a6
--- /dev/null
+++ b/cloudprint-backend/proto/cloudprint.proto
@@ -0,0 +1,502 @@
+syntax = "proto3";
+
+package cloudprint;
+
+option go_package = "github.com/cloudprint/cloudprint-backend/proto/generated";
+
+import "google/protobuf/empty.proto";
+import "google/protobuf/timestamp.proto";
+
+// ============ 通用消息 ============
+
+message Empty {}
+
+message StatusResponse {
+ int32 code = 1;
+ string message = 2;
+}
+
+// ============ 用户相关 ============
+
+message User {
+ int32 id = 1;
+ string openid = 2;
+ string nickname = 3;
+ string avatar = 4;
+ double balance = 5;
+ google.protobuf.Timestamp created_at = 6;
+}
+
+message LoginRequest {
+ string code = 1; // 微信授权码
+}
+
+message LoginResponse {
+ string access_token = 1;
+ string refresh_token = 2;
+ User user = 3;
+}
+
+message RefreshRequest {
+ string refresh_token = 1;
+}
+
+message RefreshResponse {
+ string access_token = 1;
+}
+
+message GetUserInfoRequest {}
+
+message UpdateUserRequest {
+ string nickname = 1;
+ string avatar = 2;
+}
+
+// ============ 文件相关 ============
+
+message FileInfo {
+ int32 id = 1;
+ string file_name = 2;
+ string file_path = 3;
+ string file_type = 4;
+ int64 file_size = 5;
+ string uploader_type = 6;
+ int32 uploader_id = 7;
+ google.protobuf.Timestamp created_at = 8;
+}
+
+message UploadRequest {
+ string file_name = 1;
+ string file_type = 2;
+ int64 file_size = 3;
+ bytes data = 4;
+ bool is_last_chunk = 5;
+ string chunk_id = 6;
+ int32 chunk_index = 7;
+ int32 total_chunks = 8;
+}
+
+message UploadResponse {
+ int32 file_id = 1;
+ string file_path = 2;
+ string file_url = 3;
+}
+
+message GetFileRequest {
+ int32 file_id = 1;
+}
+
+message FileData {
+ bytes data = 1;
+ bool is_last = 2;
+}
+
+message DeleteFileRequest {
+ int32 file_id = 1;
+}
+
+message WatermarkRequest {
+ int32 file_id = 1;
+ string text = 2;
+ float opacity = 3;
+ int32 position = 4; // 1: 左上 2: 右上 3: 左下 4: 右下 5: 居中
+ int32 font_size = 5;
+}
+
+message WatermarkResponse {
+ int32 file_id = 1;
+ string file_path = 2;
+}
+
+message GetFileListRequest {
+ string uploader_type = 1;
+ int32 uploader_id = 2;
+ int32 page = 3;
+ int32 page_size = 4;
+}
+
+message FileListResponse {
+ repeated FileInfo files = 1;
+ int32 total = 2;
+}
+
+// ============ 订单相关 ============
+
+message Order {
+ int32 id = 1;
+ string order_no = 2;
+ int32 user_id = 3;
+ int32 status = 4;
+ double total_amount = 5;
+ string remark = 6;
+ google.protobuf.Timestamp created_at = 7;
+ google.protobuf.Timestamp paid_at = 8;
+ repeated OrderItem items = 9;
+}
+
+message OrderItem {
+ int32 id = 1;
+ int32 order_id = 2;
+ int32 file_id = 3;
+ FileInfo file = 4;
+ int32 printer_id = 5;
+ int32 copies = 6;
+ bool color = 7;
+ bool duplex = 8;
+ string page_range = 9;
+ double price = 10;
+}
+
+message CreateOrderRequest {
+ repeated CreateOrderItem items = 1;
+ string remark = 2;
+}
+
+message CreateOrderItem {
+ int32 file_id = 1;
+ int32 printer_id = 2;
+ int32 copies = 3;
+ bool color = 4;
+ bool duplex = 5;
+ string page_range = 6;
+}
+
+message CreateOrderResponse {
+ string order_no = 1;
+ double total_amount = 2;
+}
+
+message GetOrderRequest {
+ string order_no = 1;
+}
+
+message GetOrderListRequest {
+ int32 user_id = 1;
+ int32 status = 2;
+ int32 page = 3;
+ int32 page_size = 4;
+}
+
+message OrderListResponse {
+ repeated Order orders = 1;
+ int32 total = 2;
+}
+
+message UpdateOrderStatusRequest {
+ string order_no = 1;
+ int32 status = 2;
+}
+
+message CancelOrderRequest {
+ string order_no = 1;
+}
+
+// ============ 打印机相关 ============
+
+message Printer {
+ int32 id = 1;
+ string name = 2;
+ string display_name = 3;
+ bool is_active = 4;
+ int32 status = 5; // 0: 空闲 1: 打印中 2: 离线
+ google.protobuf.Timestamp last_heartbeat = 6;
+}
+
+message GetPrintersRequest {}
+
+message PrinterListResponse {
+ repeated Printer printers = 1;
+}
+
+message GetPrinterStatusRequest {
+ int32 printer_id = 1;
+}
+
+message PrinterStatusResponse {
+ Printer printer = 1;
+ int32 queue_count = 2;
+}
+
+message RegisterPrinterRequest {
+ string name = 1;
+ string display_name = 2;
+ string api_key = 3;
+}
+
+message RegisterPrinterResponse {
+ int32 printer_id = 1;
+ string token = 2;
+}
+
+message PrinterHeartbeatRequest {
+ int32 printer_id = 1;
+ int32 status = 2;
+ string token = 3;
+}
+
+// ============ 打印任务相关 ============
+
+message PrintJob {
+ int32 id = 1;
+ string job_no = 2;
+ int32 printer_id = 3;
+ int32 order_item_id = 4;
+ string status = 5; // pending/printing/completed/failed/cancelled
+ int32 progress = 6;
+ string error_msg = 7;
+ google.protobuf.Timestamp started_at = 8;
+ google.protobuf.Timestamp completed_at = 9;
+ OrderItem order_item = 10;
+}
+
+message SubmitPrintJobRequest {
+ int32 order_item_id = 1;
+ int32 printer_id = 2;
+ string file_path = 3;
+ int32 copies = 4;
+ bool color = 5;
+ bool duplex = 6;
+ string page_range = 7;
+}
+
+message SubmitPrintJobResponse {
+ string job_no = 1;
+}
+
+message CancelPrintJobRequest {
+ string job_no = 1;
+}
+
+message SubscribeJobsRequest {
+ int32 printer_id = 1;
+ string token = 2;
+}
+
+message ReportJobStatusRequest {
+ string job_no = 1;
+ string status = 2;
+ int32 progress = 3;
+ string error_msg = 4;
+}
+
+// ============ 文库相关 ============
+
+message LibraryCategory {
+ int32 id = 1;
+ string name = 2;
+ string icon = 3;
+ int32 sort_order = 4;
+}
+
+message LibraryFile {
+ int32 id = 1;
+ int32 category_id = 2;
+ int32 file_id = 3;
+ string title = 4;
+ string description = 5;
+ int32 page_count = 6;
+ int32 download_count = 7;
+ FileInfo file = 8;
+ google.protobuf.Timestamp created_at = 9;
+}
+
+message GetCategoriesRequest {}
+
+message CategoryListResponse {
+ repeated LibraryCategory categories = 1;
+}
+
+message GetLibraryFilesRequest {
+ int32 category_id = 1;
+ int32 page = 2;
+ int32 page_size = 3;
+}
+
+message LibraryFileListResponse {
+ repeated LibraryFile files = 1;
+ int32 total = 2;
+}
+
+message UploadLibraryFileRequest {
+ int32 category_id = 1;
+ string title = 2;
+ string description = 3;
+ bytes data = 4;
+ string file_name = 5;
+ string file_type = 6;
+}
+
+message UploadLibraryFileResponse {
+ int32 library_file_id = 1;
+}
+
+message DeleteLibraryFileRequest {
+ int32 library_file_id = 1;
+}
+
+// ============ 价目表相关 ============
+
+message PriceItem {
+ int32 id = 1;
+ string name = 2;
+ string type = 3;
+ double price = 4;
+ string unit = 5;
+ bool color_enabled = 6;
+ bool is_active = 7;
+}
+
+message GetPriceListRequest {}
+
+message PriceListResponse {
+ repeated PriceItem items = 1;
+}
+
+message CreatePriceItemRequest {
+ string name = 1;
+ string type = 2;
+ double price = 3;
+ string unit = 4;
+ bool color_enabled = 5;
+}
+
+message UpdatePriceItemRequest {
+ int32 id = 1;
+ string name = 2;
+ string type = 3;
+ double price = 4;
+ string unit = 5;
+ bool color_enabled = 6;
+ bool is_active = 7;
+}
+
+// ============ 支付相关 ============
+
+message WxPayRequest {
+ string order_no = 1;
+ double amount = 2;
+ string description = 3;
+ string openid = 4;
+ string client_ip = 5;
+}
+
+message WxPayResponse {
+ string prepay_id = 1;
+ string code_url = 2;
+ string mweb_url = 3;
+}
+
+message QueryPayStatusRequest {
+ string order_no = 1;
+}
+
+message PayStatusResponse {
+ int32 status = 1; // 0: 待支付 1: 支付中 2: 成功 3: 失败
+ string transaction_id = 2;
+}
+
+message PayCallbackRequest {
+ string body = 1;
+}
+
+message PayCallbackResponse {
+ string return_code = 1;
+ string return_msg = 2;
+}
+
+message PayByBalanceRequest {
+ string order_no = 1;
+ int32 user_id = 2;
+}
+
+// ============ 管理后台相关 ============
+
+message Admin {
+ int32 id = 1;
+ string username = 2;
+ string nickname = 3;
+ int32 role = 4;
+ google.protobuf.Timestamp created_at = 5;
+}
+
+message AdminLoginRequest {
+ string username = 1;
+ string password = 2;
+}
+
+message AdminLoginResponse {
+ string access_token = 1;
+ Admin admin = 2;
+}
+
+message GetStatisticsRequest {}
+
+message Statistics {
+ int32 total_users = 1;
+ int32 total_orders = 2;
+ int32 today_orders = 3;
+ double today_revenue = 4;
+ int32 pending_orders = 5;
+ int32 active_printers = 6;
+}
+
+// ============ 服务定义 ============
+
+service AuthService {
+ rpc Login(LoginRequest) returns (LoginResponse);
+ rpc RefreshToken(RefreshRequest) returns (RefreshResponse);
+ rpc GetUserInfo(GetUserInfoRequest) returns (User);
+ rpc UpdateUser(UpdateUserRequest) returns (User);
+}
+
+service FileService {
+ rpc Upload(stream UploadRequest) returns (UploadResponse);
+ rpc GetFile(GetFileRequest) returns (stream FileData);
+ rpc DeleteFile(DeleteFileRequest) returns (Empty);
+ rpc AddWatermark(WatermarkRequest) returns (WatermarkResponse);
+ rpc GetFileList(GetFileListRequest) returns (FileListResponse);
+}
+
+service OrderService {
+ rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
+ rpc GetOrder(GetOrderRequest) returns (Order);
+ rpc GetOrderList(GetOrderListRequest) returns (OrderListResponse);
+ rpc UpdateOrderStatus(UpdateOrderStatusRequest) returns (Empty);
+ rpc CancelOrder(CancelOrderRequest) returns (Empty);
+}
+
+service PrintService {
+ rpc GetPrinters(GetPrintersRequest) returns (PrinterListResponse);
+ rpc GetPrinterStatus(GetPrinterStatusRequest) returns (PrinterStatusResponse);
+ rpc RegisterPrinter(RegisterPrinterRequest) returns (RegisterPrinterResponse);
+ rpc PrinterHeartbeat(PrinterHeartbeatRequest) returns (Empty);
+ rpc SubmitPrintJob(SubmitPrintJobRequest) returns (SubmitPrintJobResponse);
+ rpc CancelPrintJob(CancelPrintJobRequest) returns (Empty);
+ rpc SubscribeJobs(SubscribeJobsRequest) returns (stream PrintJob);
+ rpc ReportJobStatus(ReportJobStatusRequest) returns (Empty);
+}
+
+service LibraryService {
+ rpc GetCategories(GetCategoriesRequest) returns (CategoryListResponse);
+ rpc GetFiles(GetLibraryFilesRequest) returns (LibraryFileListResponse);
+ rpc UploadFile(stream UploadLibraryFileRequest) returns (UploadLibraryFileResponse);
+ rpc DeleteFile(DeleteLibraryFileRequest) returns (Empty);
+}
+
+service PriceService {
+ rpc GetPriceList(GetPriceListRequest) returns (PriceListResponse);
+ rpc CreatePriceItem(CreatePriceItemRequest) returns (PriceItem);
+ rpc UpdatePriceItem(UpdatePriceItemRequest) returns (PriceItem);
+}
+
+service PayService {
+ rpc CreateWxPayOrder(WxPayRequest) returns (WxPayResponse);
+ rpc QueryPayStatus(QueryPayStatusRequest) returns (PayStatusResponse);
+ rpc HandlePayCallback(PayCallbackRequest) returns (PayCallbackResponse);
+ rpc PayByBalance(PayByBalanceRequest) returns (StatusResponse);
+}
+
+service AdminService {
+ rpc Login(AdminLoginRequest) returns (AdminLoginResponse);
+ rpc GetStatistics(GetStatisticsRequest) returns (Statistics);
+}
diff --git a/cloudprint-backend/proto/generated/cloudprint.pb.go b/cloudprint-backend/proto/generated/cloudprint.pb.go
new file mode 100644
index 0000000..1f707e6
--- /dev/null
+++ b/cloudprint-backend/proto/generated/cloudprint.pb.go
@@ -0,0 +1,4785 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.36.11
+// protoc v6.32.0
+// source: cloudprint.proto
+
+package generated
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ _ "google.golang.org/protobuf/types/known/emptypb"
+ timestamppb "google.golang.org/protobuf/types/known/timestamppb"
+ reflect "reflect"
+ sync "sync"
+ unsafe "unsafe"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Empty struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Empty) Reset() {
+ *x = Empty{}
+ mi := &file_cloudprint_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Empty) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Empty) ProtoMessage() {}
+
+func (x *Empty) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_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 Empty.ProtoReflect.Descriptor instead.
+func (*Empty) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{0}
+}
+
+type StatusResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
+ Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *StatusResponse) Reset() {
+ *x = StatusResponse{}
+ mi := &file_cloudprint_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *StatusResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*StatusResponse) ProtoMessage() {}
+
+func (x *StatusResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_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 StatusResponse.ProtoReflect.Descriptor instead.
+func (*StatusResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *StatusResponse) GetCode() int32 {
+ if x != nil {
+ return x.Code
+ }
+ return 0
+}
+
+func (x *StatusResponse) GetMessage() string {
+ if x != nil {
+ return x.Message
+ }
+ return ""
+}
+
+type User struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Openid string `protobuf:"bytes,2,opt,name=openid,proto3" json:"openid,omitempty"`
+ Nickname string `protobuf:"bytes,3,opt,name=nickname,proto3" json:"nickname,omitempty"`
+ Avatar string `protobuf:"bytes,4,opt,name=avatar,proto3" json:"avatar,omitempty"`
+ Balance float64 `protobuf:"fixed64,5,opt,name=balance,proto3" json:"balance,omitempty"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *User) Reset() {
+ *x = User{}
+ mi := &file_cloudprint_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *User) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*User) ProtoMessage() {}
+
+func (x *User) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_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 User.ProtoReflect.Descriptor instead.
+func (*User) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *User) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *User) GetOpenid() string {
+ if x != nil {
+ return x.Openid
+ }
+ return ""
+}
+
+func (x *User) GetNickname() string {
+ if x != nil {
+ return x.Nickname
+ }
+ return ""
+}
+
+func (x *User) GetAvatar() string {
+ if x != nil {
+ return x.Avatar
+ }
+ return ""
+}
+
+func (x *User) GetBalance() float64 {
+ if x != nil {
+ return x.Balance
+ }
+ return 0
+}
+
+func (x *User) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+type LoginRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` // 微信授权码
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LoginRequest) Reset() {
+ *x = LoginRequest{}
+ mi := &file_cloudprint_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LoginRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LoginRequest) ProtoMessage() {}
+
+func (x *LoginRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_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 LoginRequest.ProtoReflect.Descriptor instead.
+func (*LoginRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *LoginRequest) GetCode() string {
+ if x != nil {
+ return x.Code
+ }
+ return ""
+}
+
+type LoginResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
+ RefreshToken string `protobuf:"bytes,2,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
+ User *User `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LoginResponse) Reset() {
+ *x = LoginResponse{}
+ mi := &file_cloudprint_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LoginResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LoginResponse) ProtoMessage() {}
+
+func (x *LoginResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[4]
+ 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 LoginResponse.ProtoReflect.Descriptor instead.
+func (*LoginResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *LoginResponse) GetAccessToken() string {
+ if x != nil {
+ return x.AccessToken
+ }
+ return ""
+}
+
+func (x *LoginResponse) GetRefreshToken() string {
+ if x != nil {
+ return x.RefreshToken
+ }
+ return ""
+}
+
+func (x *LoginResponse) GetUser() *User {
+ if x != nil {
+ return x.User
+ }
+ return nil
+}
+
+type RefreshRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ RefreshToken string `protobuf:"bytes,1,opt,name=refresh_token,json=refreshToken,proto3" json:"refresh_token,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RefreshRequest) Reset() {
+ *x = RefreshRequest{}
+ mi := &file_cloudprint_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RefreshRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RefreshRequest) ProtoMessage() {}
+
+func (x *RefreshRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_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 RefreshRequest.ProtoReflect.Descriptor instead.
+func (*RefreshRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *RefreshRequest) GetRefreshToken() string {
+ if x != nil {
+ return x.RefreshToken
+ }
+ return ""
+}
+
+type RefreshResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RefreshResponse) Reset() {
+ *x = RefreshResponse{}
+ mi := &file_cloudprint_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RefreshResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RefreshResponse) ProtoMessage() {}
+
+func (x *RefreshResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[6]
+ 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 RefreshResponse.ProtoReflect.Descriptor instead.
+func (*RefreshResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *RefreshResponse) GetAccessToken() string {
+ if x != nil {
+ return x.AccessToken
+ }
+ return ""
+}
+
+type GetUserInfoRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetUserInfoRequest) Reset() {
+ *x = GetUserInfoRequest{}
+ mi := &file_cloudprint_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetUserInfoRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetUserInfoRequest) ProtoMessage() {}
+
+func (x *GetUserInfoRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[7]
+ 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 GetUserInfoRequest.ProtoReflect.Descriptor instead.
+func (*GetUserInfoRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{7}
+}
+
+type UpdateUserRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Nickname string `protobuf:"bytes,1,opt,name=nickname,proto3" json:"nickname,omitempty"`
+ Avatar string `protobuf:"bytes,2,opt,name=avatar,proto3" json:"avatar,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateUserRequest) Reset() {
+ *x = UpdateUserRequest{}
+ mi := &file_cloudprint_proto_msgTypes[8]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdateUserRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateUserRequest) ProtoMessage() {}
+
+func (x *UpdateUserRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[8]
+ 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 UpdateUserRequest.ProtoReflect.Descriptor instead.
+func (*UpdateUserRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *UpdateUserRequest) GetNickname() string {
+ if x != nil {
+ return x.Nickname
+ }
+ return ""
+}
+
+func (x *UpdateUserRequest) GetAvatar() string {
+ if x != nil {
+ return x.Avatar
+ }
+ return ""
+}
+
+type FileInfo struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ FileName string `protobuf:"bytes,2,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"`
+ FilePath string `protobuf:"bytes,3,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
+ FileType string `protobuf:"bytes,4,opt,name=file_type,json=fileType,proto3" json:"file_type,omitempty"`
+ FileSize int64 `protobuf:"varint,5,opt,name=file_size,json=fileSize,proto3" json:"file_size,omitempty"`
+ UploaderType string `protobuf:"bytes,6,opt,name=uploader_type,json=uploaderType,proto3" json:"uploader_type,omitempty"`
+ UploaderId int32 `protobuf:"varint,7,opt,name=uploader_id,json=uploaderId,proto3" json:"uploader_id,omitempty"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *FileInfo) Reset() {
+ *x = FileInfo{}
+ mi := &file_cloudprint_proto_msgTypes[9]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *FileInfo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileInfo) ProtoMessage() {}
+
+func (x *FileInfo) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_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 FileInfo.ProtoReflect.Descriptor instead.
+func (*FileInfo) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *FileInfo) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *FileInfo) GetFileName() string {
+ if x != nil {
+ return x.FileName
+ }
+ return ""
+}
+
+func (x *FileInfo) GetFilePath() string {
+ if x != nil {
+ return x.FilePath
+ }
+ return ""
+}
+
+func (x *FileInfo) GetFileType() string {
+ if x != nil {
+ return x.FileType
+ }
+ return ""
+}
+
+func (x *FileInfo) GetFileSize() int64 {
+ if x != nil {
+ return x.FileSize
+ }
+ return 0
+}
+
+func (x *FileInfo) GetUploaderType() string {
+ if x != nil {
+ return x.UploaderType
+ }
+ return ""
+}
+
+func (x *FileInfo) GetUploaderId() int32 {
+ if x != nil {
+ return x.UploaderId
+ }
+ return 0
+}
+
+func (x *FileInfo) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+type UploadRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileName string `protobuf:"bytes,1,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"`
+ FileType string `protobuf:"bytes,2,opt,name=file_type,json=fileType,proto3" json:"file_type,omitempty"`
+ FileSize int64 `protobuf:"varint,3,opt,name=file_size,json=fileSize,proto3" json:"file_size,omitempty"`
+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
+ IsLastChunk bool `protobuf:"varint,5,opt,name=is_last_chunk,json=isLastChunk,proto3" json:"is_last_chunk,omitempty"`
+ ChunkId string `protobuf:"bytes,6,opt,name=chunk_id,json=chunkId,proto3" json:"chunk_id,omitempty"`
+ ChunkIndex int32 `protobuf:"varint,7,opt,name=chunk_index,json=chunkIndex,proto3" json:"chunk_index,omitempty"`
+ TotalChunks int32 `protobuf:"varint,8,opt,name=total_chunks,json=totalChunks,proto3" json:"total_chunks,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UploadRequest) Reset() {
+ *x = UploadRequest{}
+ mi := &file_cloudprint_proto_msgTypes[10]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UploadRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UploadRequest) ProtoMessage() {}
+
+func (x *UploadRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[10]
+ 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 UploadRequest.ProtoReflect.Descriptor instead.
+func (*UploadRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *UploadRequest) GetFileName() string {
+ if x != nil {
+ return x.FileName
+ }
+ return ""
+}
+
+func (x *UploadRequest) GetFileType() string {
+ if x != nil {
+ return x.FileType
+ }
+ return ""
+}
+
+func (x *UploadRequest) GetFileSize() int64 {
+ if x != nil {
+ return x.FileSize
+ }
+ return 0
+}
+
+func (x *UploadRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *UploadRequest) GetIsLastChunk() bool {
+ if x != nil {
+ return x.IsLastChunk
+ }
+ return false
+}
+
+func (x *UploadRequest) GetChunkId() string {
+ if x != nil {
+ return x.ChunkId
+ }
+ return ""
+}
+
+func (x *UploadRequest) GetChunkIndex() int32 {
+ if x != nil {
+ return x.ChunkIndex
+ }
+ return 0
+}
+
+func (x *UploadRequest) GetTotalChunks() int32 {
+ if x != nil {
+ return x.TotalChunks
+ }
+ return 0
+}
+
+type UploadResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileId int32 `protobuf:"varint,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
+ FileUrl string `protobuf:"bytes,3,opt,name=file_url,json=fileUrl,proto3" json:"file_url,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UploadResponse) Reset() {
+ *x = UploadResponse{}
+ mi := &file_cloudprint_proto_msgTypes[11]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UploadResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UploadResponse) ProtoMessage() {}
+
+func (x *UploadResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[11]
+ 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 UploadResponse.ProtoReflect.Descriptor instead.
+func (*UploadResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *UploadResponse) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+func (x *UploadResponse) GetFilePath() string {
+ if x != nil {
+ return x.FilePath
+ }
+ return ""
+}
+
+func (x *UploadResponse) GetFileUrl() string {
+ if x != nil {
+ return x.FileUrl
+ }
+ return ""
+}
+
+type GetFileRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileId int32 `protobuf:"varint,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetFileRequest) Reset() {
+ *x = GetFileRequest{}
+ mi := &file_cloudprint_proto_msgTypes[12]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetFileRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetFileRequest) ProtoMessage() {}
+
+func (x *GetFileRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[12]
+ 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 GetFileRequest.ProtoReflect.Descriptor instead.
+func (*GetFileRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{12}
+}
+
+func (x *GetFileRequest) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+type FileData struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+ IsLast bool `protobuf:"varint,2,opt,name=is_last,json=isLast,proto3" json:"is_last,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *FileData) Reset() {
+ *x = FileData{}
+ mi := &file_cloudprint_proto_msgTypes[13]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *FileData) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileData) ProtoMessage() {}
+
+func (x *FileData) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[13]
+ 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 FileData.ProtoReflect.Descriptor instead.
+func (*FileData) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{13}
+}
+
+func (x *FileData) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *FileData) GetIsLast() bool {
+ if x != nil {
+ return x.IsLast
+ }
+ return false
+}
+
+type DeleteFileRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileId int32 `protobuf:"varint,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteFileRequest) Reset() {
+ *x = DeleteFileRequest{}
+ mi := &file_cloudprint_proto_msgTypes[14]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteFileRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteFileRequest) ProtoMessage() {}
+
+func (x *DeleteFileRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[14]
+ 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 DeleteFileRequest.ProtoReflect.Descriptor instead.
+func (*DeleteFileRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{14}
+}
+
+func (x *DeleteFileRequest) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+type WatermarkRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileId int32 `protobuf:"varint,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
+ Opacity float32 `protobuf:"fixed32,3,opt,name=opacity,proto3" json:"opacity,omitempty"`
+ Position int32 `protobuf:"varint,4,opt,name=position,proto3" json:"position,omitempty"` // 1: 左上 2: 右上 3: 左下 4: 右下 5: 居中
+ FontSize int32 `protobuf:"varint,5,opt,name=font_size,json=fontSize,proto3" json:"font_size,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WatermarkRequest) Reset() {
+ *x = WatermarkRequest{}
+ mi := &file_cloudprint_proto_msgTypes[15]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WatermarkRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WatermarkRequest) ProtoMessage() {}
+
+func (x *WatermarkRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[15]
+ 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 WatermarkRequest.ProtoReflect.Descriptor instead.
+func (*WatermarkRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{15}
+}
+
+func (x *WatermarkRequest) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+func (x *WatermarkRequest) GetText() string {
+ if x != nil {
+ return x.Text
+ }
+ return ""
+}
+
+func (x *WatermarkRequest) GetOpacity() float32 {
+ if x != nil {
+ return x.Opacity
+ }
+ return 0
+}
+
+func (x *WatermarkRequest) GetPosition() int32 {
+ if x != nil {
+ return x.Position
+ }
+ return 0
+}
+
+func (x *WatermarkRequest) GetFontSize() int32 {
+ if x != nil {
+ return x.FontSize
+ }
+ return 0
+}
+
+type WatermarkResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileId int32 `protobuf:"varint,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WatermarkResponse) Reset() {
+ *x = WatermarkResponse{}
+ mi := &file_cloudprint_proto_msgTypes[16]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WatermarkResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WatermarkResponse) ProtoMessage() {}
+
+func (x *WatermarkResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[16]
+ 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 WatermarkResponse.ProtoReflect.Descriptor instead.
+func (*WatermarkResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{16}
+}
+
+func (x *WatermarkResponse) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+func (x *WatermarkResponse) GetFilePath() string {
+ if x != nil {
+ return x.FilePath
+ }
+ return ""
+}
+
+type GetFileListRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ UploaderType string `protobuf:"bytes,1,opt,name=uploader_type,json=uploaderType,proto3" json:"uploader_type,omitempty"`
+ UploaderId int32 `protobuf:"varint,2,opt,name=uploader_id,json=uploaderId,proto3" json:"uploader_id,omitempty"`
+ Page int32 `protobuf:"varint,3,opt,name=page,proto3" json:"page,omitempty"`
+ PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetFileListRequest) Reset() {
+ *x = GetFileListRequest{}
+ mi := &file_cloudprint_proto_msgTypes[17]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetFileListRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetFileListRequest) ProtoMessage() {}
+
+func (x *GetFileListRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[17]
+ 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 GetFileListRequest.ProtoReflect.Descriptor instead.
+func (*GetFileListRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{17}
+}
+
+func (x *GetFileListRequest) GetUploaderType() string {
+ if x != nil {
+ return x.UploaderType
+ }
+ return ""
+}
+
+func (x *GetFileListRequest) GetUploaderId() int32 {
+ if x != nil {
+ return x.UploaderId
+ }
+ return 0
+}
+
+func (x *GetFileListRequest) GetPage() int32 {
+ if x != nil {
+ return x.Page
+ }
+ return 0
+}
+
+func (x *GetFileListRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+type FileListResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Files []*FileInfo `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
+ Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *FileListResponse) Reset() {
+ *x = FileListResponse{}
+ mi := &file_cloudprint_proto_msgTypes[18]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *FileListResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FileListResponse) ProtoMessage() {}
+
+func (x *FileListResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[18]
+ 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 FileListResponse.ProtoReflect.Descriptor instead.
+func (*FileListResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *FileListResponse) GetFiles() []*FileInfo {
+ if x != nil {
+ return x.Files
+ }
+ return nil
+}
+
+func (x *FileListResponse) GetTotal() int32 {
+ if x != nil {
+ return x.Total
+ }
+ return 0
+}
+
+type Order struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ OrderNo string `protobuf:"bytes,2,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ UserId int32 `protobuf:"varint,3,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
+ Status int32 `protobuf:"varint,4,opt,name=status,proto3" json:"status,omitempty"`
+ TotalAmount float64 `protobuf:"fixed64,5,opt,name=total_amount,json=totalAmount,proto3" json:"total_amount,omitempty"`
+ Remark string `protobuf:"bytes,6,opt,name=remark,proto3" json:"remark,omitempty"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+ PaidAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=paid_at,json=paidAt,proto3" json:"paid_at,omitempty"`
+ Items []*OrderItem `protobuf:"bytes,9,rep,name=items,proto3" json:"items,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Order) Reset() {
+ *x = Order{}
+ mi := &file_cloudprint_proto_msgTypes[19]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Order) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Order) ProtoMessage() {}
+
+func (x *Order) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[19]
+ 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 Order.ProtoReflect.Descriptor instead.
+func (*Order) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{19}
+}
+
+func (x *Order) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *Order) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+func (x *Order) GetUserId() int32 {
+ if x != nil {
+ return x.UserId
+ }
+ return 0
+}
+
+func (x *Order) GetStatus() int32 {
+ if x != nil {
+ return x.Status
+ }
+ return 0
+}
+
+func (x *Order) GetTotalAmount() float64 {
+ if x != nil {
+ return x.TotalAmount
+ }
+ return 0
+}
+
+func (x *Order) GetRemark() string {
+ if x != nil {
+ return x.Remark
+ }
+ return ""
+}
+
+func (x *Order) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+func (x *Order) GetPaidAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.PaidAt
+ }
+ return nil
+}
+
+func (x *Order) GetItems() []*OrderItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+type OrderItem struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ OrderId int32 `protobuf:"varint,2,opt,name=order_id,json=orderId,proto3" json:"order_id,omitempty"`
+ FileId int32 `protobuf:"varint,3,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ File *FileInfo `protobuf:"bytes,4,opt,name=file,proto3" json:"file,omitempty"`
+ PrinterId int32 `protobuf:"varint,5,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ Copies int32 `protobuf:"varint,6,opt,name=copies,proto3" json:"copies,omitempty"`
+ Color bool `protobuf:"varint,7,opt,name=color,proto3" json:"color,omitempty"`
+ Duplex bool `protobuf:"varint,8,opt,name=duplex,proto3" json:"duplex,omitempty"`
+ PageRange string `protobuf:"bytes,9,opt,name=page_range,json=pageRange,proto3" json:"page_range,omitempty"`
+ Price float64 `protobuf:"fixed64,10,opt,name=price,proto3" json:"price,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *OrderItem) Reset() {
+ *x = OrderItem{}
+ mi := &file_cloudprint_proto_msgTypes[20]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *OrderItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OrderItem) ProtoMessage() {}
+
+func (x *OrderItem) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[20]
+ 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 OrderItem.ProtoReflect.Descriptor instead.
+func (*OrderItem) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{20}
+}
+
+func (x *OrderItem) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *OrderItem) GetOrderId() int32 {
+ if x != nil {
+ return x.OrderId
+ }
+ return 0
+}
+
+func (x *OrderItem) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+func (x *OrderItem) GetFile() *FileInfo {
+ if x != nil {
+ return x.File
+ }
+ return nil
+}
+
+func (x *OrderItem) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *OrderItem) GetCopies() int32 {
+ if x != nil {
+ return x.Copies
+ }
+ return 0
+}
+
+func (x *OrderItem) GetColor() bool {
+ if x != nil {
+ return x.Color
+ }
+ return false
+}
+
+func (x *OrderItem) GetDuplex() bool {
+ if x != nil {
+ return x.Duplex
+ }
+ return false
+}
+
+func (x *OrderItem) GetPageRange() string {
+ if x != nil {
+ return x.PageRange
+ }
+ return ""
+}
+
+func (x *OrderItem) GetPrice() float64 {
+ if x != nil {
+ return x.Price
+ }
+ return 0
+}
+
+type CreateOrderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Items []*CreateOrderItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
+ Remark string `protobuf:"bytes,2,opt,name=remark,proto3" json:"remark,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateOrderRequest) Reset() {
+ *x = CreateOrderRequest{}
+ mi := &file_cloudprint_proto_msgTypes[21]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CreateOrderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateOrderRequest) ProtoMessage() {}
+
+func (x *CreateOrderRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[21]
+ 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 CreateOrderRequest.ProtoReflect.Descriptor instead.
+func (*CreateOrderRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{21}
+}
+
+func (x *CreateOrderRequest) GetItems() []*CreateOrderItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+func (x *CreateOrderRequest) GetRemark() string {
+ if x != nil {
+ return x.Remark
+ }
+ return ""
+}
+
+type CreateOrderItem struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ FileId int32 `protobuf:"varint,1,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ PrinterId int32 `protobuf:"varint,2,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ Copies int32 `protobuf:"varint,3,opt,name=copies,proto3" json:"copies,omitempty"`
+ Color bool `protobuf:"varint,4,opt,name=color,proto3" json:"color,omitempty"`
+ Duplex bool `protobuf:"varint,5,opt,name=duplex,proto3" json:"duplex,omitempty"`
+ PageRange string `protobuf:"bytes,6,opt,name=page_range,json=pageRange,proto3" json:"page_range,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateOrderItem) Reset() {
+ *x = CreateOrderItem{}
+ mi := &file_cloudprint_proto_msgTypes[22]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CreateOrderItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateOrderItem) ProtoMessage() {}
+
+func (x *CreateOrderItem) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[22]
+ 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 CreateOrderItem.ProtoReflect.Descriptor instead.
+func (*CreateOrderItem) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{22}
+}
+
+func (x *CreateOrderItem) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+func (x *CreateOrderItem) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *CreateOrderItem) GetCopies() int32 {
+ if x != nil {
+ return x.Copies
+ }
+ return 0
+}
+
+func (x *CreateOrderItem) GetColor() bool {
+ if x != nil {
+ return x.Color
+ }
+ return false
+}
+
+func (x *CreateOrderItem) GetDuplex() bool {
+ if x != nil {
+ return x.Duplex
+ }
+ return false
+}
+
+func (x *CreateOrderItem) GetPageRange() string {
+ if x != nil {
+ return x.PageRange
+ }
+ return ""
+}
+
+type CreateOrderResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ TotalAmount float64 `protobuf:"fixed64,2,opt,name=total_amount,json=totalAmount,proto3" json:"total_amount,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreateOrderResponse) Reset() {
+ *x = CreateOrderResponse{}
+ mi := &file_cloudprint_proto_msgTypes[23]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CreateOrderResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreateOrderResponse) ProtoMessage() {}
+
+func (x *CreateOrderResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[23]
+ 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 CreateOrderResponse.ProtoReflect.Descriptor instead.
+func (*CreateOrderResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{23}
+}
+
+func (x *CreateOrderResponse) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+func (x *CreateOrderResponse) GetTotalAmount() float64 {
+ if x != nil {
+ return x.TotalAmount
+ }
+ return 0
+}
+
+type GetOrderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetOrderRequest) Reset() {
+ *x = GetOrderRequest{}
+ mi := &file_cloudprint_proto_msgTypes[24]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetOrderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetOrderRequest) ProtoMessage() {}
+
+func (x *GetOrderRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[24]
+ 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 GetOrderRequest.ProtoReflect.Descriptor instead.
+func (*GetOrderRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{24}
+}
+
+func (x *GetOrderRequest) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+type GetOrderListRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ UserId int32 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
+ Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
+ Page int32 `protobuf:"varint,3,opt,name=page,proto3" json:"page,omitempty"`
+ PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetOrderListRequest) Reset() {
+ *x = GetOrderListRequest{}
+ mi := &file_cloudprint_proto_msgTypes[25]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetOrderListRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetOrderListRequest) ProtoMessage() {}
+
+func (x *GetOrderListRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[25]
+ 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 GetOrderListRequest.ProtoReflect.Descriptor instead.
+func (*GetOrderListRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{25}
+}
+
+func (x *GetOrderListRequest) GetUserId() int32 {
+ if x != nil {
+ return x.UserId
+ }
+ return 0
+}
+
+func (x *GetOrderListRequest) GetStatus() int32 {
+ if x != nil {
+ return x.Status
+ }
+ return 0
+}
+
+func (x *GetOrderListRequest) GetPage() int32 {
+ if x != nil {
+ return x.Page
+ }
+ return 0
+}
+
+func (x *GetOrderListRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+type OrderListResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Orders []*Order `protobuf:"bytes,1,rep,name=orders,proto3" json:"orders,omitempty"`
+ Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *OrderListResponse) Reset() {
+ *x = OrderListResponse{}
+ mi := &file_cloudprint_proto_msgTypes[26]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *OrderListResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OrderListResponse) ProtoMessage() {}
+
+func (x *OrderListResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[26]
+ 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 OrderListResponse.ProtoReflect.Descriptor instead.
+func (*OrderListResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{26}
+}
+
+func (x *OrderListResponse) GetOrders() []*Order {
+ if x != nil {
+ return x.Orders
+ }
+ return nil
+}
+
+func (x *OrderListResponse) GetTotal() int32 {
+ if x != nil {
+ return x.Total
+ }
+ return 0
+}
+
+type UpdateOrderStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdateOrderStatusRequest) Reset() {
+ *x = UpdateOrderStatusRequest{}
+ mi := &file_cloudprint_proto_msgTypes[27]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdateOrderStatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateOrderStatusRequest) ProtoMessage() {}
+
+func (x *UpdateOrderStatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[27]
+ 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 UpdateOrderStatusRequest.ProtoReflect.Descriptor instead.
+func (*UpdateOrderStatusRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{27}
+}
+
+func (x *UpdateOrderStatusRequest) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+func (x *UpdateOrderStatusRequest) GetStatus() int32 {
+ if x != nil {
+ return x.Status
+ }
+ return 0
+}
+
+type CancelOrderRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CancelOrderRequest) Reset() {
+ *x = CancelOrderRequest{}
+ mi := &file_cloudprint_proto_msgTypes[28]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CancelOrderRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CancelOrderRequest) ProtoMessage() {}
+
+func (x *CancelOrderRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[28]
+ 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 CancelOrderRequest.ProtoReflect.Descriptor instead.
+func (*CancelOrderRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{28}
+}
+
+func (x *CancelOrderRequest) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+type Printer struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ IsActive bool `protobuf:"varint,4,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
+ Status int32 `protobuf:"varint,5,opt,name=status,proto3" json:"status,omitempty"` // 0: 空闲 1: 打印中 2: 离线
+ LastHeartbeat *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=last_heartbeat,json=lastHeartbeat,proto3" json:"last_heartbeat,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Printer) Reset() {
+ *x = Printer{}
+ mi := &file_cloudprint_proto_msgTypes[29]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Printer) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Printer) ProtoMessage() {}
+
+func (x *Printer) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[29]
+ 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 Printer.ProtoReflect.Descriptor instead.
+func (*Printer) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{29}
+}
+
+func (x *Printer) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *Printer) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *Printer) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+func (x *Printer) GetIsActive() bool {
+ if x != nil {
+ return x.IsActive
+ }
+ return false
+}
+
+func (x *Printer) GetStatus() int32 {
+ if x != nil {
+ return x.Status
+ }
+ return 0
+}
+
+func (x *Printer) GetLastHeartbeat() *timestamppb.Timestamp {
+ if x != nil {
+ return x.LastHeartbeat
+ }
+ return nil
+}
+
+type GetPrintersRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetPrintersRequest) Reset() {
+ *x = GetPrintersRequest{}
+ mi := &file_cloudprint_proto_msgTypes[30]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetPrintersRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetPrintersRequest) ProtoMessage() {}
+
+func (x *GetPrintersRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[30]
+ 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 GetPrintersRequest.ProtoReflect.Descriptor instead.
+func (*GetPrintersRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{30}
+}
+
+type PrinterListResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Printers []*Printer `protobuf:"bytes,1,rep,name=printers,proto3" json:"printers,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PrinterListResponse) Reset() {
+ *x = PrinterListResponse{}
+ mi := &file_cloudprint_proto_msgTypes[31]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PrinterListResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrinterListResponse) ProtoMessage() {}
+
+func (x *PrinterListResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[31]
+ 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 PrinterListResponse.ProtoReflect.Descriptor instead.
+func (*PrinterListResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{31}
+}
+
+func (x *PrinterListResponse) GetPrinters() []*Printer {
+ if x != nil {
+ return x.Printers
+ }
+ return nil
+}
+
+type GetPrinterStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ PrinterId int32 `protobuf:"varint,1,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetPrinterStatusRequest) Reset() {
+ *x = GetPrinterStatusRequest{}
+ mi := &file_cloudprint_proto_msgTypes[32]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetPrinterStatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetPrinterStatusRequest) ProtoMessage() {}
+
+func (x *GetPrinterStatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[32]
+ 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 GetPrinterStatusRequest.ProtoReflect.Descriptor instead.
+func (*GetPrinterStatusRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{32}
+}
+
+func (x *GetPrinterStatusRequest) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+type PrinterStatusResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Printer *Printer `protobuf:"bytes,1,opt,name=printer,proto3" json:"printer,omitempty"`
+ QueueCount int32 `protobuf:"varint,2,opt,name=queue_count,json=queueCount,proto3" json:"queue_count,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PrinterStatusResponse) Reset() {
+ *x = PrinterStatusResponse{}
+ mi := &file_cloudprint_proto_msgTypes[33]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PrinterStatusResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrinterStatusResponse) ProtoMessage() {}
+
+func (x *PrinterStatusResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[33]
+ 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 PrinterStatusResponse.ProtoReflect.Descriptor instead.
+func (*PrinterStatusResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{33}
+}
+
+func (x *PrinterStatusResponse) GetPrinter() *Printer {
+ if x != nil {
+ return x.Printer
+ }
+ return nil
+}
+
+func (x *PrinterStatusResponse) GetQueueCount() int32 {
+ if x != nil {
+ return x.QueueCount
+ }
+ return 0
+}
+
+type RegisterPrinterRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
+ ApiKey string `protobuf:"bytes,3,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RegisterPrinterRequest) Reset() {
+ *x = RegisterPrinterRequest{}
+ mi := &file_cloudprint_proto_msgTypes[34]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RegisterPrinterRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RegisterPrinterRequest) ProtoMessage() {}
+
+func (x *RegisterPrinterRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[34]
+ 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 RegisterPrinterRequest.ProtoReflect.Descriptor instead.
+func (*RegisterPrinterRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{34}
+}
+
+func (x *RegisterPrinterRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *RegisterPrinterRequest) GetDisplayName() string {
+ if x != nil {
+ return x.DisplayName
+ }
+ return ""
+}
+
+func (x *RegisterPrinterRequest) GetApiKey() string {
+ if x != nil {
+ return x.ApiKey
+ }
+ return ""
+}
+
+type RegisterPrinterResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ PrinterId int32 `protobuf:"varint,1,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *RegisterPrinterResponse) Reset() {
+ *x = RegisterPrinterResponse{}
+ mi := &file_cloudprint_proto_msgTypes[35]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *RegisterPrinterResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*RegisterPrinterResponse) ProtoMessage() {}
+
+func (x *RegisterPrinterResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[35]
+ 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 RegisterPrinterResponse.ProtoReflect.Descriptor instead.
+func (*RegisterPrinterResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{35}
+}
+
+func (x *RegisterPrinterResponse) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *RegisterPrinterResponse) GetToken() string {
+ if x != nil {
+ return x.Token
+ }
+ return ""
+}
+
+type PrinterHeartbeatRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ PrinterId int32 `protobuf:"varint,1,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"`
+ Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PrinterHeartbeatRequest) Reset() {
+ *x = PrinterHeartbeatRequest{}
+ mi := &file_cloudprint_proto_msgTypes[36]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PrinterHeartbeatRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrinterHeartbeatRequest) ProtoMessage() {}
+
+func (x *PrinterHeartbeatRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[36]
+ 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 PrinterHeartbeatRequest.ProtoReflect.Descriptor instead.
+func (*PrinterHeartbeatRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{36}
+}
+
+func (x *PrinterHeartbeatRequest) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *PrinterHeartbeatRequest) GetStatus() int32 {
+ if x != nil {
+ return x.Status
+ }
+ return 0
+}
+
+func (x *PrinterHeartbeatRequest) GetToken() string {
+ if x != nil {
+ return x.Token
+ }
+ return ""
+}
+
+type PrintJob struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ JobNo string `protobuf:"bytes,2,opt,name=job_no,json=jobNo,proto3" json:"job_no,omitempty"`
+ PrinterId int32 `protobuf:"varint,3,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ OrderItemId int32 `protobuf:"varint,4,opt,name=order_item_id,json=orderItemId,proto3" json:"order_item_id,omitempty"`
+ Status string `protobuf:"bytes,5,opt,name=status,proto3" json:"status,omitempty"` // pending/printing/completed/failed/cancelled
+ Progress int32 `protobuf:"varint,6,opt,name=progress,proto3" json:"progress,omitempty"`
+ ErrorMsg string `protobuf:"bytes,7,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"`
+ StartedAt *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=started_at,json=startedAt,proto3" json:"started_at,omitempty"`
+ CompletedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=completed_at,json=completedAt,proto3" json:"completed_at,omitempty"`
+ OrderItem *OrderItem `protobuf:"bytes,10,opt,name=order_item,json=orderItem,proto3" json:"order_item,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PrintJob) Reset() {
+ *x = PrintJob{}
+ mi := &file_cloudprint_proto_msgTypes[37]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PrintJob) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PrintJob) ProtoMessage() {}
+
+func (x *PrintJob) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[37]
+ 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 PrintJob.ProtoReflect.Descriptor instead.
+func (*PrintJob) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{37}
+}
+
+func (x *PrintJob) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *PrintJob) GetJobNo() string {
+ if x != nil {
+ return x.JobNo
+ }
+ return ""
+}
+
+func (x *PrintJob) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *PrintJob) GetOrderItemId() int32 {
+ if x != nil {
+ return x.OrderItemId
+ }
+ return 0
+}
+
+func (x *PrintJob) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (x *PrintJob) GetProgress() int32 {
+ if x != nil {
+ return x.Progress
+ }
+ return 0
+}
+
+func (x *PrintJob) GetErrorMsg() string {
+ if x != nil {
+ return x.ErrorMsg
+ }
+ return ""
+}
+
+func (x *PrintJob) GetStartedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.StartedAt
+ }
+ return nil
+}
+
+func (x *PrintJob) GetCompletedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CompletedAt
+ }
+ return nil
+}
+
+func (x *PrintJob) GetOrderItem() *OrderItem {
+ if x != nil {
+ return x.OrderItem
+ }
+ return nil
+}
+
+type SubmitPrintJobRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderItemId int32 `protobuf:"varint,1,opt,name=order_item_id,json=orderItemId,proto3" json:"order_item_id,omitempty"`
+ PrinterId int32 `protobuf:"varint,2,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ FilePath string `protobuf:"bytes,3,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"`
+ Copies int32 `protobuf:"varint,4,opt,name=copies,proto3" json:"copies,omitempty"`
+ Color bool `protobuf:"varint,5,opt,name=color,proto3" json:"color,omitempty"`
+ Duplex bool `protobuf:"varint,6,opt,name=duplex,proto3" json:"duplex,omitempty"`
+ PageRange string `protobuf:"bytes,7,opt,name=page_range,json=pageRange,proto3" json:"page_range,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SubmitPrintJobRequest) Reset() {
+ *x = SubmitPrintJobRequest{}
+ mi := &file_cloudprint_proto_msgTypes[38]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SubmitPrintJobRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubmitPrintJobRequest) ProtoMessage() {}
+
+func (x *SubmitPrintJobRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[38]
+ 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 SubmitPrintJobRequest.ProtoReflect.Descriptor instead.
+func (*SubmitPrintJobRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{38}
+}
+
+func (x *SubmitPrintJobRequest) GetOrderItemId() int32 {
+ if x != nil {
+ return x.OrderItemId
+ }
+ return 0
+}
+
+func (x *SubmitPrintJobRequest) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *SubmitPrintJobRequest) GetFilePath() string {
+ if x != nil {
+ return x.FilePath
+ }
+ return ""
+}
+
+func (x *SubmitPrintJobRequest) GetCopies() int32 {
+ if x != nil {
+ return x.Copies
+ }
+ return 0
+}
+
+func (x *SubmitPrintJobRequest) GetColor() bool {
+ if x != nil {
+ return x.Color
+ }
+ return false
+}
+
+func (x *SubmitPrintJobRequest) GetDuplex() bool {
+ if x != nil {
+ return x.Duplex
+ }
+ return false
+}
+
+func (x *SubmitPrintJobRequest) GetPageRange() string {
+ if x != nil {
+ return x.PageRange
+ }
+ return ""
+}
+
+type SubmitPrintJobResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ JobNo string `protobuf:"bytes,1,opt,name=job_no,json=jobNo,proto3" json:"job_no,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SubmitPrintJobResponse) Reset() {
+ *x = SubmitPrintJobResponse{}
+ mi := &file_cloudprint_proto_msgTypes[39]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SubmitPrintJobResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubmitPrintJobResponse) ProtoMessage() {}
+
+func (x *SubmitPrintJobResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[39]
+ 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 SubmitPrintJobResponse.ProtoReflect.Descriptor instead.
+func (*SubmitPrintJobResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{39}
+}
+
+func (x *SubmitPrintJobResponse) GetJobNo() string {
+ if x != nil {
+ return x.JobNo
+ }
+ return ""
+}
+
+type CancelPrintJobRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ JobNo string `protobuf:"bytes,1,opt,name=job_no,json=jobNo,proto3" json:"job_no,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CancelPrintJobRequest) Reset() {
+ *x = CancelPrintJobRequest{}
+ mi := &file_cloudprint_proto_msgTypes[40]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CancelPrintJobRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CancelPrintJobRequest) ProtoMessage() {}
+
+func (x *CancelPrintJobRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[40]
+ 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 CancelPrintJobRequest.ProtoReflect.Descriptor instead.
+func (*CancelPrintJobRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{40}
+}
+
+func (x *CancelPrintJobRequest) GetJobNo() string {
+ if x != nil {
+ return x.JobNo
+ }
+ return ""
+}
+
+type SubscribeJobsRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ PrinterId int32 `protobuf:"varint,1,opt,name=printer_id,json=printerId,proto3" json:"printer_id,omitempty"`
+ Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *SubscribeJobsRequest) Reset() {
+ *x = SubscribeJobsRequest{}
+ mi := &file_cloudprint_proto_msgTypes[41]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *SubscribeJobsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*SubscribeJobsRequest) ProtoMessage() {}
+
+func (x *SubscribeJobsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[41]
+ 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 SubscribeJobsRequest.ProtoReflect.Descriptor instead.
+func (*SubscribeJobsRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{41}
+}
+
+func (x *SubscribeJobsRequest) GetPrinterId() int32 {
+ if x != nil {
+ return x.PrinterId
+ }
+ return 0
+}
+
+func (x *SubscribeJobsRequest) GetToken() string {
+ if x != nil {
+ return x.Token
+ }
+ return ""
+}
+
+type ReportJobStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ JobNo string `protobuf:"bytes,1,opt,name=job_no,json=jobNo,proto3" json:"job_no,omitempty"`
+ Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
+ Progress int32 `protobuf:"varint,3,opt,name=progress,proto3" json:"progress,omitempty"`
+ ErrorMsg string `protobuf:"bytes,4,opt,name=error_msg,json=errorMsg,proto3" json:"error_msg,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *ReportJobStatusRequest) Reset() {
+ *x = ReportJobStatusRequest{}
+ mi := &file_cloudprint_proto_msgTypes[42]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *ReportJobStatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReportJobStatusRequest) ProtoMessage() {}
+
+func (x *ReportJobStatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[42]
+ 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 ReportJobStatusRequest.ProtoReflect.Descriptor instead.
+func (*ReportJobStatusRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{42}
+}
+
+func (x *ReportJobStatusRequest) GetJobNo() string {
+ if x != nil {
+ return x.JobNo
+ }
+ return ""
+}
+
+func (x *ReportJobStatusRequest) GetStatus() string {
+ if x != nil {
+ return x.Status
+ }
+ return ""
+}
+
+func (x *ReportJobStatusRequest) GetProgress() int32 {
+ if x != nil {
+ return x.Progress
+ }
+ return 0
+}
+
+func (x *ReportJobStatusRequest) GetErrorMsg() string {
+ if x != nil {
+ return x.ErrorMsg
+ }
+ return ""
+}
+
+type LibraryCategory struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Icon string `protobuf:"bytes,3,opt,name=icon,proto3" json:"icon,omitempty"`
+ SortOrder int32 `protobuf:"varint,4,opt,name=sort_order,json=sortOrder,proto3" json:"sort_order,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LibraryCategory) Reset() {
+ *x = LibraryCategory{}
+ mi := &file_cloudprint_proto_msgTypes[43]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LibraryCategory) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LibraryCategory) ProtoMessage() {}
+
+func (x *LibraryCategory) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[43]
+ 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 LibraryCategory.ProtoReflect.Descriptor instead.
+func (*LibraryCategory) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{43}
+}
+
+func (x *LibraryCategory) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *LibraryCategory) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *LibraryCategory) GetIcon() string {
+ if x != nil {
+ return x.Icon
+ }
+ return ""
+}
+
+func (x *LibraryCategory) GetSortOrder() int32 {
+ if x != nil {
+ return x.SortOrder
+ }
+ return 0
+}
+
+type LibraryFile struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ CategoryId int32 `protobuf:"varint,2,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"`
+ FileId int32 `protobuf:"varint,3,opt,name=file_id,json=fileId,proto3" json:"file_id,omitempty"`
+ Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"`
+ Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"`
+ PageCount int32 `protobuf:"varint,6,opt,name=page_count,json=pageCount,proto3" json:"page_count,omitempty"`
+ DownloadCount int32 `protobuf:"varint,7,opt,name=download_count,json=downloadCount,proto3" json:"download_count,omitempty"`
+ File *FileInfo `protobuf:"bytes,8,opt,name=file,proto3" json:"file,omitempty"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LibraryFile) Reset() {
+ *x = LibraryFile{}
+ mi := &file_cloudprint_proto_msgTypes[44]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LibraryFile) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LibraryFile) ProtoMessage() {}
+
+func (x *LibraryFile) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[44]
+ 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 LibraryFile.ProtoReflect.Descriptor instead.
+func (*LibraryFile) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{44}
+}
+
+func (x *LibraryFile) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *LibraryFile) GetCategoryId() int32 {
+ if x != nil {
+ return x.CategoryId
+ }
+ return 0
+}
+
+func (x *LibraryFile) GetFileId() int32 {
+ if x != nil {
+ return x.FileId
+ }
+ return 0
+}
+
+func (x *LibraryFile) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *LibraryFile) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *LibraryFile) GetPageCount() int32 {
+ if x != nil {
+ return x.PageCount
+ }
+ return 0
+}
+
+func (x *LibraryFile) GetDownloadCount() int32 {
+ if x != nil {
+ return x.DownloadCount
+ }
+ return 0
+}
+
+func (x *LibraryFile) GetFile() *FileInfo {
+ if x != nil {
+ return x.File
+ }
+ return nil
+}
+
+func (x *LibraryFile) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+type GetCategoriesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetCategoriesRequest) Reset() {
+ *x = GetCategoriesRequest{}
+ mi := &file_cloudprint_proto_msgTypes[45]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetCategoriesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetCategoriesRequest) ProtoMessage() {}
+
+func (x *GetCategoriesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[45]
+ 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 GetCategoriesRequest.ProtoReflect.Descriptor instead.
+func (*GetCategoriesRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{45}
+}
+
+type CategoryListResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Categories []*LibraryCategory `protobuf:"bytes,1,rep,name=categories,proto3" json:"categories,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CategoryListResponse) Reset() {
+ *x = CategoryListResponse{}
+ mi := &file_cloudprint_proto_msgTypes[46]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CategoryListResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CategoryListResponse) ProtoMessage() {}
+
+func (x *CategoryListResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[46]
+ 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 CategoryListResponse.ProtoReflect.Descriptor instead.
+func (*CategoryListResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{46}
+}
+
+func (x *CategoryListResponse) GetCategories() []*LibraryCategory {
+ if x != nil {
+ return x.Categories
+ }
+ return nil
+}
+
+type GetLibraryFilesRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ CategoryId int32 `protobuf:"varint,1,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"`
+ Page int32 `protobuf:"varint,2,opt,name=page,proto3" json:"page,omitempty"`
+ PageSize int32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetLibraryFilesRequest) Reset() {
+ *x = GetLibraryFilesRequest{}
+ mi := &file_cloudprint_proto_msgTypes[47]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetLibraryFilesRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetLibraryFilesRequest) ProtoMessage() {}
+
+func (x *GetLibraryFilesRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[47]
+ 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 GetLibraryFilesRequest.ProtoReflect.Descriptor instead.
+func (*GetLibraryFilesRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{47}
+}
+
+func (x *GetLibraryFilesRequest) GetCategoryId() int32 {
+ if x != nil {
+ return x.CategoryId
+ }
+ return 0
+}
+
+func (x *GetLibraryFilesRequest) GetPage() int32 {
+ if x != nil {
+ return x.Page
+ }
+ return 0
+}
+
+func (x *GetLibraryFilesRequest) GetPageSize() int32 {
+ if x != nil {
+ return x.PageSize
+ }
+ return 0
+}
+
+type LibraryFileListResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Files []*LibraryFile `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
+ Total int32 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *LibraryFileListResponse) Reset() {
+ *x = LibraryFileListResponse{}
+ mi := &file_cloudprint_proto_msgTypes[48]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *LibraryFileListResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*LibraryFileListResponse) ProtoMessage() {}
+
+func (x *LibraryFileListResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[48]
+ 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 LibraryFileListResponse.ProtoReflect.Descriptor instead.
+func (*LibraryFileListResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{48}
+}
+
+func (x *LibraryFileListResponse) GetFiles() []*LibraryFile {
+ if x != nil {
+ return x.Files
+ }
+ return nil
+}
+
+func (x *LibraryFileListResponse) GetTotal() int32 {
+ if x != nil {
+ return x.Total
+ }
+ return 0
+}
+
+type UploadLibraryFileRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ CategoryId int32 `protobuf:"varint,1,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"`
+ Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
+ Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+ Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
+ FileName string `protobuf:"bytes,5,opt,name=file_name,json=fileName,proto3" json:"file_name,omitempty"`
+ FileType string `protobuf:"bytes,6,opt,name=file_type,json=fileType,proto3" json:"file_type,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UploadLibraryFileRequest) Reset() {
+ *x = UploadLibraryFileRequest{}
+ mi := &file_cloudprint_proto_msgTypes[49]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UploadLibraryFileRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UploadLibraryFileRequest) ProtoMessage() {}
+
+func (x *UploadLibraryFileRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[49]
+ 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 UploadLibraryFileRequest.ProtoReflect.Descriptor instead.
+func (*UploadLibraryFileRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{49}
+}
+
+func (x *UploadLibraryFileRequest) GetCategoryId() int32 {
+ if x != nil {
+ return x.CategoryId
+ }
+ return 0
+}
+
+func (x *UploadLibraryFileRequest) GetTitle() string {
+ if x != nil {
+ return x.Title
+ }
+ return ""
+}
+
+func (x *UploadLibraryFileRequest) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *UploadLibraryFileRequest) GetData() []byte {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+func (x *UploadLibraryFileRequest) GetFileName() string {
+ if x != nil {
+ return x.FileName
+ }
+ return ""
+}
+
+func (x *UploadLibraryFileRequest) GetFileType() string {
+ if x != nil {
+ return x.FileType
+ }
+ return ""
+}
+
+type UploadLibraryFileResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LibraryFileId int32 `protobuf:"varint,1,opt,name=library_file_id,json=libraryFileId,proto3" json:"library_file_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UploadLibraryFileResponse) Reset() {
+ *x = UploadLibraryFileResponse{}
+ mi := &file_cloudprint_proto_msgTypes[50]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UploadLibraryFileResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UploadLibraryFileResponse) ProtoMessage() {}
+
+func (x *UploadLibraryFileResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[50]
+ 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 UploadLibraryFileResponse.ProtoReflect.Descriptor instead.
+func (*UploadLibraryFileResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{50}
+}
+
+func (x *UploadLibraryFileResponse) GetLibraryFileId() int32 {
+ if x != nil {
+ return x.LibraryFileId
+ }
+ return 0
+}
+
+type DeleteLibraryFileRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ LibraryFileId int32 `protobuf:"varint,1,opt,name=library_file_id,json=libraryFileId,proto3" json:"library_file_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *DeleteLibraryFileRequest) Reset() {
+ *x = DeleteLibraryFileRequest{}
+ mi := &file_cloudprint_proto_msgTypes[51]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *DeleteLibraryFileRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteLibraryFileRequest) ProtoMessage() {}
+
+func (x *DeleteLibraryFileRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[51]
+ 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 DeleteLibraryFileRequest.ProtoReflect.Descriptor instead.
+func (*DeleteLibraryFileRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{51}
+}
+
+func (x *DeleteLibraryFileRequest) GetLibraryFileId() int32 {
+ if x != nil {
+ return x.LibraryFileId
+ }
+ return 0
+}
+
+type PriceItem struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ Price float64 `protobuf:"fixed64,4,opt,name=price,proto3" json:"price,omitempty"`
+ Unit string `protobuf:"bytes,5,opt,name=unit,proto3" json:"unit,omitempty"`
+ ColorEnabled bool `protobuf:"varint,6,opt,name=color_enabled,json=colorEnabled,proto3" json:"color_enabled,omitempty"`
+ IsActive bool `protobuf:"varint,7,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PriceItem) Reset() {
+ *x = PriceItem{}
+ mi := &file_cloudprint_proto_msgTypes[52]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PriceItem) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PriceItem) ProtoMessage() {}
+
+func (x *PriceItem) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[52]
+ 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 PriceItem.ProtoReflect.Descriptor instead.
+func (*PriceItem) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{52}
+}
+
+func (x *PriceItem) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *PriceItem) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *PriceItem) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *PriceItem) GetPrice() float64 {
+ if x != nil {
+ return x.Price
+ }
+ return 0
+}
+
+func (x *PriceItem) GetUnit() string {
+ if x != nil {
+ return x.Unit
+ }
+ return ""
+}
+
+func (x *PriceItem) GetColorEnabled() bool {
+ if x != nil {
+ return x.ColorEnabled
+ }
+ return false
+}
+
+func (x *PriceItem) GetIsActive() bool {
+ if x != nil {
+ return x.IsActive
+ }
+ return false
+}
+
+type GetPriceListRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetPriceListRequest) Reset() {
+ *x = GetPriceListRequest{}
+ mi := &file_cloudprint_proto_msgTypes[53]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetPriceListRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetPriceListRequest) ProtoMessage() {}
+
+func (x *GetPriceListRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[53]
+ 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 GetPriceListRequest.ProtoReflect.Descriptor instead.
+func (*GetPriceListRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{53}
+}
+
+type PriceListResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Items []*PriceItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PriceListResponse) Reset() {
+ *x = PriceListResponse{}
+ mi := &file_cloudprint_proto_msgTypes[54]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PriceListResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PriceListResponse) ProtoMessage() {}
+
+func (x *PriceListResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[54]
+ 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 PriceListResponse.ProtoReflect.Descriptor instead.
+func (*PriceListResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{54}
+}
+
+func (x *PriceListResponse) GetItems() []*PriceItem {
+ if x != nil {
+ return x.Items
+ }
+ return nil
+}
+
+type CreatePriceItemRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
+ Price float64 `protobuf:"fixed64,3,opt,name=price,proto3" json:"price,omitempty"`
+ Unit string `protobuf:"bytes,4,opt,name=unit,proto3" json:"unit,omitempty"`
+ ColorEnabled bool `protobuf:"varint,5,opt,name=color_enabled,json=colorEnabled,proto3" json:"color_enabled,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *CreatePriceItemRequest) Reset() {
+ *x = CreatePriceItemRequest{}
+ mi := &file_cloudprint_proto_msgTypes[55]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *CreatePriceItemRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CreatePriceItemRequest) ProtoMessage() {}
+
+func (x *CreatePriceItemRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[55]
+ 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 CreatePriceItemRequest.ProtoReflect.Descriptor instead.
+func (*CreatePriceItemRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{55}
+}
+
+func (x *CreatePriceItemRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *CreatePriceItemRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *CreatePriceItemRequest) GetPrice() float64 {
+ if x != nil {
+ return x.Price
+ }
+ return 0
+}
+
+func (x *CreatePriceItemRequest) GetUnit() string {
+ if x != nil {
+ return x.Unit
+ }
+ return ""
+}
+
+func (x *CreatePriceItemRequest) GetColorEnabled() bool {
+ if x != nil {
+ return x.ColorEnabled
+ }
+ return false
+}
+
+type UpdatePriceItemRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+ Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
+ Price float64 `protobuf:"fixed64,4,opt,name=price,proto3" json:"price,omitempty"`
+ Unit string `protobuf:"bytes,5,opt,name=unit,proto3" json:"unit,omitempty"`
+ ColorEnabled bool `protobuf:"varint,6,opt,name=color_enabled,json=colorEnabled,proto3" json:"color_enabled,omitempty"`
+ IsActive bool `protobuf:"varint,7,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *UpdatePriceItemRequest) Reset() {
+ *x = UpdatePriceItemRequest{}
+ mi := &file_cloudprint_proto_msgTypes[56]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *UpdatePriceItemRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdatePriceItemRequest) ProtoMessage() {}
+
+func (x *UpdatePriceItemRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[56]
+ 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 UpdatePriceItemRequest.ProtoReflect.Descriptor instead.
+func (*UpdatePriceItemRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{56}
+}
+
+func (x *UpdatePriceItemRequest) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *UpdatePriceItemRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *UpdatePriceItemRequest) GetType() string {
+ if x != nil {
+ return x.Type
+ }
+ return ""
+}
+
+func (x *UpdatePriceItemRequest) GetPrice() float64 {
+ if x != nil {
+ return x.Price
+ }
+ return 0
+}
+
+func (x *UpdatePriceItemRequest) GetUnit() string {
+ if x != nil {
+ return x.Unit
+ }
+ return ""
+}
+
+func (x *UpdatePriceItemRequest) GetColorEnabled() bool {
+ if x != nil {
+ return x.ColorEnabled
+ }
+ return false
+}
+
+func (x *UpdatePriceItemRequest) GetIsActive() bool {
+ if x != nil {
+ return x.IsActive
+ }
+ return false
+}
+
+type WxPayRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ Amount float64 `protobuf:"fixed64,2,opt,name=amount,proto3" json:"amount,omitempty"`
+ Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
+ Openid string `protobuf:"bytes,4,opt,name=openid,proto3" json:"openid,omitempty"`
+ ClientIp string `protobuf:"bytes,5,opt,name=client_ip,json=clientIp,proto3" json:"client_ip,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WxPayRequest) Reset() {
+ *x = WxPayRequest{}
+ mi := &file_cloudprint_proto_msgTypes[57]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WxPayRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WxPayRequest) ProtoMessage() {}
+
+func (x *WxPayRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[57]
+ 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 WxPayRequest.ProtoReflect.Descriptor instead.
+func (*WxPayRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{57}
+}
+
+func (x *WxPayRequest) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+func (x *WxPayRequest) GetAmount() float64 {
+ if x != nil {
+ return x.Amount
+ }
+ return 0
+}
+
+func (x *WxPayRequest) GetDescription() string {
+ if x != nil {
+ return x.Description
+ }
+ return ""
+}
+
+func (x *WxPayRequest) GetOpenid() string {
+ if x != nil {
+ return x.Openid
+ }
+ return ""
+}
+
+func (x *WxPayRequest) GetClientIp() string {
+ if x != nil {
+ return x.ClientIp
+ }
+ return ""
+}
+
+type WxPayResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ PrepayId string `protobuf:"bytes,1,opt,name=prepay_id,json=prepayId,proto3" json:"prepay_id,omitempty"`
+ CodeUrl string `protobuf:"bytes,2,opt,name=code_url,json=codeUrl,proto3" json:"code_url,omitempty"`
+ MwebUrl string `protobuf:"bytes,3,opt,name=mweb_url,json=mwebUrl,proto3" json:"mweb_url,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *WxPayResponse) Reset() {
+ *x = WxPayResponse{}
+ mi := &file_cloudprint_proto_msgTypes[58]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *WxPayResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*WxPayResponse) ProtoMessage() {}
+
+func (x *WxPayResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[58]
+ 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 WxPayResponse.ProtoReflect.Descriptor instead.
+func (*WxPayResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{58}
+}
+
+func (x *WxPayResponse) GetPrepayId() string {
+ if x != nil {
+ return x.PrepayId
+ }
+ return ""
+}
+
+func (x *WxPayResponse) GetCodeUrl() string {
+ if x != nil {
+ return x.CodeUrl
+ }
+ return ""
+}
+
+func (x *WxPayResponse) GetMwebUrl() string {
+ if x != nil {
+ return x.MwebUrl
+ }
+ return ""
+}
+
+type QueryPayStatusRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *QueryPayStatusRequest) Reset() {
+ *x = QueryPayStatusRequest{}
+ mi := &file_cloudprint_proto_msgTypes[59]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *QueryPayStatusRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QueryPayStatusRequest) ProtoMessage() {}
+
+func (x *QueryPayStatusRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[59]
+ 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 QueryPayStatusRequest.ProtoReflect.Descriptor instead.
+func (*QueryPayStatusRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{59}
+}
+
+func (x *QueryPayStatusRequest) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+type PayStatusResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"` // 0: 待支付 1: 支付中 2: 成功 3: 失败
+ TransactionId string `protobuf:"bytes,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PayStatusResponse) Reset() {
+ *x = PayStatusResponse{}
+ mi := &file_cloudprint_proto_msgTypes[60]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PayStatusResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PayStatusResponse) ProtoMessage() {}
+
+func (x *PayStatusResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[60]
+ 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 PayStatusResponse.ProtoReflect.Descriptor instead.
+func (*PayStatusResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{60}
+}
+
+func (x *PayStatusResponse) GetStatus() int32 {
+ if x != nil {
+ return x.Status
+ }
+ return 0
+}
+
+func (x *PayStatusResponse) GetTransactionId() string {
+ if x != nil {
+ return x.TransactionId
+ }
+ return ""
+}
+
+type PayCallbackRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Body string `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PayCallbackRequest) Reset() {
+ *x = PayCallbackRequest{}
+ mi := &file_cloudprint_proto_msgTypes[61]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PayCallbackRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PayCallbackRequest) ProtoMessage() {}
+
+func (x *PayCallbackRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[61]
+ 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 PayCallbackRequest.ProtoReflect.Descriptor instead.
+func (*PayCallbackRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{61}
+}
+
+func (x *PayCallbackRequest) GetBody() string {
+ if x != nil {
+ return x.Body
+ }
+ return ""
+}
+
+type PayCallbackResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ ReturnCode string `protobuf:"bytes,1,opt,name=return_code,json=returnCode,proto3" json:"return_code,omitempty"`
+ ReturnMsg string `protobuf:"bytes,2,opt,name=return_msg,json=returnMsg,proto3" json:"return_msg,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PayCallbackResponse) Reset() {
+ *x = PayCallbackResponse{}
+ mi := &file_cloudprint_proto_msgTypes[62]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PayCallbackResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PayCallbackResponse) ProtoMessage() {}
+
+func (x *PayCallbackResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[62]
+ 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 PayCallbackResponse.ProtoReflect.Descriptor instead.
+func (*PayCallbackResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{62}
+}
+
+func (x *PayCallbackResponse) GetReturnCode() string {
+ if x != nil {
+ return x.ReturnCode
+ }
+ return ""
+}
+
+func (x *PayCallbackResponse) GetReturnMsg() string {
+ if x != nil {
+ return x.ReturnMsg
+ }
+ return ""
+}
+
+type PayByBalanceRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ OrderNo string `protobuf:"bytes,1,opt,name=order_no,json=orderNo,proto3" json:"order_no,omitempty"`
+ UserId int32 `protobuf:"varint,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *PayByBalanceRequest) Reset() {
+ *x = PayByBalanceRequest{}
+ mi := &file_cloudprint_proto_msgTypes[63]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *PayByBalanceRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PayByBalanceRequest) ProtoMessage() {}
+
+func (x *PayByBalanceRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[63]
+ 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 PayByBalanceRequest.ProtoReflect.Descriptor instead.
+func (*PayByBalanceRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{63}
+}
+
+func (x *PayByBalanceRequest) GetOrderNo() string {
+ if x != nil {
+ return x.OrderNo
+ }
+ return ""
+}
+
+func (x *PayByBalanceRequest) GetUserId() int32 {
+ if x != nil {
+ return x.UserId
+ }
+ return 0
+}
+
+type Admin struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+ Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"`
+ Nickname string `protobuf:"bytes,3,opt,name=nickname,proto3" json:"nickname,omitempty"`
+ Role int32 `protobuf:"varint,4,opt,name=role,proto3" json:"role,omitempty"`
+ CreatedAt *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Admin) Reset() {
+ *x = Admin{}
+ mi := &file_cloudprint_proto_msgTypes[64]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Admin) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Admin) ProtoMessage() {}
+
+func (x *Admin) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[64]
+ 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 Admin.ProtoReflect.Descriptor instead.
+func (*Admin) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{64}
+}
+
+func (x *Admin) GetId() int32 {
+ if x != nil {
+ return x.Id
+ }
+ return 0
+}
+
+func (x *Admin) GetUsername() string {
+ if x != nil {
+ return x.Username
+ }
+ return ""
+}
+
+func (x *Admin) GetNickname() string {
+ if x != nil {
+ return x.Nickname
+ }
+ return ""
+}
+
+func (x *Admin) GetRole() int32 {
+ if x != nil {
+ return x.Role
+ }
+ return 0
+}
+
+func (x *Admin) GetCreatedAt() *timestamppb.Timestamp {
+ if x != nil {
+ return x.CreatedAt
+ }
+ return nil
+}
+
+type AdminLoginRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
+ Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AdminLoginRequest) Reset() {
+ *x = AdminLoginRequest{}
+ mi := &file_cloudprint_proto_msgTypes[65]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AdminLoginRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AdminLoginRequest) ProtoMessage() {}
+
+func (x *AdminLoginRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[65]
+ 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 AdminLoginRequest.ProtoReflect.Descriptor instead.
+func (*AdminLoginRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{65}
+}
+
+func (x *AdminLoginRequest) GetUsername() string {
+ if x != nil {
+ return x.Username
+ }
+ return ""
+}
+
+func (x *AdminLoginRequest) GetPassword() string {
+ if x != nil {
+ return x.Password
+ }
+ return ""
+}
+
+type AdminLoginResponse struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ AccessToken string `protobuf:"bytes,1,opt,name=access_token,json=accessToken,proto3" json:"access_token,omitempty"`
+ Admin *Admin `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *AdminLoginResponse) Reset() {
+ *x = AdminLoginResponse{}
+ mi := &file_cloudprint_proto_msgTypes[66]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *AdminLoginResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AdminLoginResponse) ProtoMessage() {}
+
+func (x *AdminLoginResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[66]
+ 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 AdminLoginResponse.ProtoReflect.Descriptor instead.
+func (*AdminLoginResponse) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{66}
+}
+
+func (x *AdminLoginResponse) GetAccessToken() string {
+ if x != nil {
+ return x.AccessToken
+ }
+ return ""
+}
+
+func (x *AdminLoginResponse) GetAdmin() *Admin {
+ if x != nil {
+ return x.Admin
+ }
+ return nil
+}
+
+type GetStatisticsRequest struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *GetStatisticsRequest) Reset() {
+ *x = GetStatisticsRequest{}
+ mi := &file_cloudprint_proto_msgTypes[67]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *GetStatisticsRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetStatisticsRequest) ProtoMessage() {}
+
+func (x *GetStatisticsRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[67]
+ 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 GetStatisticsRequest.ProtoReflect.Descriptor instead.
+func (*GetStatisticsRequest) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{67}
+}
+
+type Statistics struct {
+ state protoimpl.MessageState `protogen:"open.v1"`
+ TotalUsers int32 `protobuf:"varint,1,opt,name=total_users,json=totalUsers,proto3" json:"total_users,omitempty"`
+ TotalOrders int32 `protobuf:"varint,2,opt,name=total_orders,json=totalOrders,proto3" json:"total_orders,omitempty"`
+ TodayOrders int32 `protobuf:"varint,3,opt,name=today_orders,json=todayOrders,proto3" json:"today_orders,omitempty"`
+ TodayRevenue float64 `protobuf:"fixed64,4,opt,name=today_revenue,json=todayRevenue,proto3" json:"today_revenue,omitempty"`
+ PendingOrders int32 `protobuf:"varint,5,opt,name=pending_orders,json=pendingOrders,proto3" json:"pending_orders,omitempty"`
+ ActivePrinters int32 `protobuf:"varint,6,opt,name=active_printers,json=activePrinters,proto3" json:"active_printers,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *Statistics) Reset() {
+ *x = Statistics{}
+ mi := &file_cloudprint_proto_msgTypes[68]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Statistics) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Statistics) ProtoMessage() {}
+
+func (x *Statistics) ProtoReflect() protoreflect.Message {
+ mi := &file_cloudprint_proto_msgTypes[68]
+ 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 Statistics.ProtoReflect.Descriptor instead.
+func (*Statistics) Descriptor() ([]byte, []int) {
+ return file_cloudprint_proto_rawDescGZIP(), []int{68}
+}
+
+func (x *Statistics) GetTotalUsers() int32 {
+ if x != nil {
+ return x.TotalUsers
+ }
+ return 0
+}
+
+func (x *Statistics) GetTotalOrders() int32 {
+ if x != nil {
+ return x.TotalOrders
+ }
+ return 0
+}
+
+func (x *Statistics) GetTodayOrders() int32 {
+ if x != nil {
+ return x.TodayOrders
+ }
+ return 0
+}
+
+func (x *Statistics) GetTodayRevenue() float64 {
+ if x != nil {
+ return x.TodayRevenue
+ }
+ return 0
+}
+
+func (x *Statistics) GetPendingOrders() int32 {
+ if x != nil {
+ return x.PendingOrders
+ }
+ return 0
+}
+
+func (x *Statistics) GetActivePrinters() int32 {
+ if x != nil {
+ return x.ActivePrinters
+ }
+ return 0
+}
+
+var File_cloudprint_proto protoreflect.FileDescriptor
+
+const file_cloudprint_proto_rawDesc = "" +
+ "\n" +
+ "\x10cloudprint.proto\x12\n" +
+ "cloudprint\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\a\n" +
+ "\x05Empty\">\n" +
+ "\x0eStatusResponse\x12\x12\n" +
+ "\x04code\x18\x01 \x01(\x05R\x04code\x12\x18\n" +
+ "\amessage\x18\x02 \x01(\tR\amessage\"\xb7\x01\n" +
+ "\x04User\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x16\n" +
+ "\x06openid\x18\x02 \x01(\tR\x06openid\x12\x1a\n" +
+ "\bnickname\x18\x03 \x01(\tR\bnickname\x12\x16\n" +
+ "\x06avatar\x18\x04 \x01(\tR\x06avatar\x12\x18\n" +
+ "\abalance\x18\x05 \x01(\x01R\abalance\x129\n" +
+ "\n" +
+ "created_at\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\"\n" +
+ "\fLoginRequest\x12\x12\n" +
+ "\x04code\x18\x01 \x01(\tR\x04code\"}\n" +
+ "\rLoginResponse\x12!\n" +
+ "\faccess_token\x18\x01 \x01(\tR\vaccessToken\x12#\n" +
+ "\rrefresh_token\x18\x02 \x01(\tR\frefreshToken\x12$\n" +
+ "\x04user\x18\x03 \x01(\v2\x10.cloudprint.UserR\x04user\"5\n" +
+ "\x0eRefreshRequest\x12#\n" +
+ "\rrefresh_token\x18\x01 \x01(\tR\frefreshToken\"4\n" +
+ "\x0fRefreshResponse\x12!\n" +
+ "\faccess_token\x18\x01 \x01(\tR\vaccessToken\"\x14\n" +
+ "\x12GetUserInfoRequest\"G\n" +
+ "\x11UpdateUserRequest\x12\x1a\n" +
+ "\bnickname\x18\x01 \x01(\tR\bnickname\x12\x16\n" +
+ "\x06avatar\x18\x02 \x01(\tR\x06avatar\"\x8f\x02\n" +
+ "\bFileInfo\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x1b\n" +
+ "\tfile_name\x18\x02 \x01(\tR\bfileName\x12\x1b\n" +
+ "\tfile_path\x18\x03 \x01(\tR\bfilePath\x12\x1b\n" +
+ "\tfile_type\x18\x04 \x01(\tR\bfileType\x12\x1b\n" +
+ "\tfile_size\x18\x05 \x01(\x03R\bfileSize\x12#\n" +
+ "\ruploader_type\x18\x06 \x01(\tR\fuploaderType\x12\x1f\n" +
+ "\vuploader_id\x18\a \x01(\x05R\n" +
+ "uploaderId\x129\n" +
+ "\n" +
+ "created_at\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\xfd\x01\n" +
+ "\rUploadRequest\x12\x1b\n" +
+ "\tfile_name\x18\x01 \x01(\tR\bfileName\x12\x1b\n" +
+ "\tfile_type\x18\x02 \x01(\tR\bfileType\x12\x1b\n" +
+ "\tfile_size\x18\x03 \x01(\x03R\bfileSize\x12\x12\n" +
+ "\x04data\x18\x04 \x01(\fR\x04data\x12\"\n" +
+ "\ris_last_chunk\x18\x05 \x01(\bR\visLastChunk\x12\x19\n" +
+ "\bchunk_id\x18\x06 \x01(\tR\achunkId\x12\x1f\n" +
+ "\vchunk_index\x18\a \x01(\x05R\n" +
+ "chunkIndex\x12!\n" +
+ "\ftotal_chunks\x18\b \x01(\x05R\vtotalChunks\"a\n" +
+ "\x0eUploadResponse\x12\x17\n" +
+ "\afile_id\x18\x01 \x01(\x05R\x06fileId\x12\x1b\n" +
+ "\tfile_path\x18\x02 \x01(\tR\bfilePath\x12\x19\n" +
+ "\bfile_url\x18\x03 \x01(\tR\afileUrl\")\n" +
+ "\x0eGetFileRequest\x12\x17\n" +
+ "\afile_id\x18\x01 \x01(\x05R\x06fileId\"7\n" +
+ "\bFileData\x12\x12\n" +
+ "\x04data\x18\x01 \x01(\fR\x04data\x12\x17\n" +
+ "\ais_last\x18\x02 \x01(\bR\x06isLast\",\n" +
+ "\x11DeleteFileRequest\x12\x17\n" +
+ "\afile_id\x18\x01 \x01(\x05R\x06fileId\"\x92\x01\n" +
+ "\x10WatermarkRequest\x12\x17\n" +
+ "\afile_id\x18\x01 \x01(\x05R\x06fileId\x12\x12\n" +
+ "\x04text\x18\x02 \x01(\tR\x04text\x12\x18\n" +
+ "\aopacity\x18\x03 \x01(\x02R\aopacity\x12\x1a\n" +
+ "\bposition\x18\x04 \x01(\x05R\bposition\x12\x1b\n" +
+ "\tfont_size\x18\x05 \x01(\x05R\bfontSize\"I\n" +
+ "\x11WatermarkResponse\x12\x17\n" +
+ "\afile_id\x18\x01 \x01(\x05R\x06fileId\x12\x1b\n" +
+ "\tfile_path\x18\x02 \x01(\tR\bfilePath\"\x8b\x01\n" +
+ "\x12GetFileListRequest\x12#\n" +
+ "\ruploader_type\x18\x01 \x01(\tR\fuploaderType\x12\x1f\n" +
+ "\vuploader_id\x18\x02 \x01(\x05R\n" +
+ "uploaderId\x12\x12\n" +
+ "\x04page\x18\x03 \x01(\x05R\x04page\x12\x1b\n" +
+ "\tpage_size\x18\x04 \x01(\x05R\bpageSize\"T\n" +
+ "\x10FileListResponse\x12*\n" +
+ "\x05files\x18\x01 \x03(\v2\x14.cloudprint.FileInfoR\x05files\x12\x14\n" +
+ "\x05total\x18\x02 \x01(\x05R\x05total\"\xbb\x02\n" +
+ "\x05Order\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x19\n" +
+ "\border_no\x18\x02 \x01(\tR\aorderNo\x12\x17\n" +
+ "\auser_id\x18\x03 \x01(\x05R\x06userId\x12\x16\n" +
+ "\x06status\x18\x04 \x01(\x05R\x06status\x12!\n" +
+ "\ftotal_amount\x18\x05 \x01(\x01R\vtotalAmount\x12\x16\n" +
+ "\x06remark\x18\x06 \x01(\tR\x06remark\x129\n" +
+ "\n" +
+ "created_at\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\x123\n" +
+ "\apaid_at\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\x06paidAt\x12+\n" +
+ "\x05items\x18\t \x03(\v2\x15.cloudprint.OrderItemR\x05items\"\x93\x02\n" +
+ "\tOrderItem\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x19\n" +
+ "\border_id\x18\x02 \x01(\x05R\aorderId\x12\x17\n" +
+ "\afile_id\x18\x03 \x01(\x05R\x06fileId\x12(\n" +
+ "\x04file\x18\x04 \x01(\v2\x14.cloudprint.FileInfoR\x04file\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x05 \x01(\x05R\tprinterId\x12\x16\n" +
+ "\x06copies\x18\x06 \x01(\x05R\x06copies\x12\x14\n" +
+ "\x05color\x18\a \x01(\bR\x05color\x12\x16\n" +
+ "\x06duplex\x18\b \x01(\bR\x06duplex\x12\x1d\n" +
+ "\n" +
+ "page_range\x18\t \x01(\tR\tpageRange\x12\x14\n" +
+ "\x05price\x18\n" +
+ " \x01(\x01R\x05price\"_\n" +
+ "\x12CreateOrderRequest\x121\n" +
+ "\x05items\x18\x01 \x03(\v2\x1b.cloudprint.CreateOrderItemR\x05items\x12\x16\n" +
+ "\x06remark\x18\x02 \x01(\tR\x06remark\"\xae\x01\n" +
+ "\x0fCreateOrderItem\x12\x17\n" +
+ "\afile_id\x18\x01 \x01(\x05R\x06fileId\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x02 \x01(\x05R\tprinterId\x12\x16\n" +
+ "\x06copies\x18\x03 \x01(\x05R\x06copies\x12\x14\n" +
+ "\x05color\x18\x04 \x01(\bR\x05color\x12\x16\n" +
+ "\x06duplex\x18\x05 \x01(\bR\x06duplex\x12\x1d\n" +
+ "\n" +
+ "page_range\x18\x06 \x01(\tR\tpageRange\"S\n" +
+ "\x13CreateOrderResponse\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\x12!\n" +
+ "\ftotal_amount\x18\x02 \x01(\x01R\vtotalAmount\",\n" +
+ "\x0fGetOrderRequest\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\"w\n" +
+ "\x13GetOrderListRequest\x12\x17\n" +
+ "\auser_id\x18\x01 \x01(\x05R\x06userId\x12\x16\n" +
+ "\x06status\x18\x02 \x01(\x05R\x06status\x12\x12\n" +
+ "\x04page\x18\x03 \x01(\x05R\x04page\x12\x1b\n" +
+ "\tpage_size\x18\x04 \x01(\x05R\bpageSize\"T\n" +
+ "\x11OrderListResponse\x12)\n" +
+ "\x06orders\x18\x01 \x03(\v2\x11.cloudprint.OrderR\x06orders\x12\x14\n" +
+ "\x05total\x18\x02 \x01(\x05R\x05total\"M\n" +
+ "\x18UpdateOrderStatusRequest\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\x12\x16\n" +
+ "\x06status\x18\x02 \x01(\x05R\x06status\"/\n" +
+ "\x12CancelOrderRequest\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\"\xc8\x01\n" +
+ "\aPrinter\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n" +
+ "\x04name\x18\x02 \x01(\tR\x04name\x12!\n" +
+ "\fdisplay_name\x18\x03 \x01(\tR\vdisplayName\x12\x1b\n" +
+ "\tis_active\x18\x04 \x01(\bR\bisActive\x12\x16\n" +
+ "\x06status\x18\x05 \x01(\x05R\x06status\x12A\n" +
+ "\x0elast_heartbeat\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\rlastHeartbeat\"\x14\n" +
+ "\x12GetPrintersRequest\"F\n" +
+ "\x13PrinterListResponse\x12/\n" +
+ "\bprinters\x18\x01 \x03(\v2\x13.cloudprint.PrinterR\bprinters\"8\n" +
+ "\x17GetPrinterStatusRequest\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x01 \x01(\x05R\tprinterId\"g\n" +
+ "\x15PrinterStatusResponse\x12-\n" +
+ "\aprinter\x18\x01 \x01(\v2\x13.cloudprint.PrinterR\aprinter\x12\x1f\n" +
+ "\vqueue_count\x18\x02 \x01(\x05R\n" +
+ "queueCount\"h\n" +
+ "\x16RegisterPrinterRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12!\n" +
+ "\fdisplay_name\x18\x02 \x01(\tR\vdisplayName\x12\x17\n" +
+ "\aapi_key\x18\x03 \x01(\tR\x06apiKey\"N\n" +
+ "\x17RegisterPrinterResponse\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x01 \x01(\x05R\tprinterId\x12\x14\n" +
+ "\x05token\x18\x02 \x01(\tR\x05token\"f\n" +
+ "\x17PrinterHeartbeatRequest\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x01 \x01(\x05R\tprinterId\x12\x16\n" +
+ "\x06status\x18\x02 \x01(\x05R\x06status\x12\x14\n" +
+ "\x05token\x18\x03 \x01(\tR\x05token\"\xf5\x02\n" +
+ "\bPrintJob\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x15\n" +
+ "\x06job_no\x18\x02 \x01(\tR\x05jobNo\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x03 \x01(\x05R\tprinterId\x12\"\n" +
+ "\rorder_item_id\x18\x04 \x01(\x05R\vorderItemId\x12\x16\n" +
+ "\x06status\x18\x05 \x01(\tR\x06status\x12\x1a\n" +
+ "\bprogress\x18\x06 \x01(\x05R\bprogress\x12\x1b\n" +
+ "\terror_msg\x18\a \x01(\tR\berrorMsg\x129\n" +
+ "\n" +
+ "started_at\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\tstartedAt\x12=\n" +
+ "\fcompleted_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\vcompletedAt\x124\n" +
+ "\n" +
+ "order_item\x18\n" +
+ " \x01(\v2\x15.cloudprint.OrderItemR\torderItem\"\xdc\x01\n" +
+ "\x15SubmitPrintJobRequest\x12\"\n" +
+ "\rorder_item_id\x18\x01 \x01(\x05R\vorderItemId\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x02 \x01(\x05R\tprinterId\x12\x1b\n" +
+ "\tfile_path\x18\x03 \x01(\tR\bfilePath\x12\x16\n" +
+ "\x06copies\x18\x04 \x01(\x05R\x06copies\x12\x14\n" +
+ "\x05color\x18\x05 \x01(\bR\x05color\x12\x16\n" +
+ "\x06duplex\x18\x06 \x01(\bR\x06duplex\x12\x1d\n" +
+ "\n" +
+ "page_range\x18\a \x01(\tR\tpageRange\"/\n" +
+ "\x16SubmitPrintJobResponse\x12\x15\n" +
+ "\x06job_no\x18\x01 \x01(\tR\x05jobNo\".\n" +
+ "\x15CancelPrintJobRequest\x12\x15\n" +
+ "\x06job_no\x18\x01 \x01(\tR\x05jobNo\"K\n" +
+ "\x14SubscribeJobsRequest\x12\x1d\n" +
+ "\n" +
+ "printer_id\x18\x01 \x01(\x05R\tprinterId\x12\x14\n" +
+ "\x05token\x18\x02 \x01(\tR\x05token\"\x80\x01\n" +
+ "\x16ReportJobStatusRequest\x12\x15\n" +
+ "\x06job_no\x18\x01 \x01(\tR\x05jobNo\x12\x16\n" +
+ "\x06status\x18\x02 \x01(\tR\x06status\x12\x1a\n" +
+ "\bprogress\x18\x03 \x01(\x05R\bprogress\x12\x1b\n" +
+ "\terror_msg\x18\x04 \x01(\tR\berrorMsg\"h\n" +
+ "\x0fLibraryCategory\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n" +
+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
+ "\x04icon\x18\x03 \x01(\tR\x04icon\x12\x1d\n" +
+ "\n" +
+ "sort_order\x18\x04 \x01(\x05R\tsortOrder\"\xba\x02\n" +
+ "\vLibraryFile\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x1f\n" +
+ "\vcategory_id\x18\x02 \x01(\x05R\n" +
+ "categoryId\x12\x17\n" +
+ "\afile_id\x18\x03 \x01(\x05R\x06fileId\x12\x14\n" +
+ "\x05title\x18\x04 \x01(\tR\x05title\x12 \n" +
+ "\vdescription\x18\x05 \x01(\tR\vdescription\x12\x1d\n" +
+ "\n" +
+ "page_count\x18\x06 \x01(\x05R\tpageCount\x12%\n" +
+ "\x0edownload_count\x18\a \x01(\x05R\rdownloadCount\x12(\n" +
+ "\x04file\x18\b \x01(\v2\x14.cloudprint.FileInfoR\x04file\x129\n" +
+ "\n" +
+ "created_at\x18\t \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"\x16\n" +
+ "\x14GetCategoriesRequest\"S\n" +
+ "\x14CategoryListResponse\x12;\n" +
+ "\n" +
+ "categories\x18\x01 \x03(\v2\x1b.cloudprint.LibraryCategoryR\n" +
+ "categories\"j\n" +
+ "\x16GetLibraryFilesRequest\x12\x1f\n" +
+ "\vcategory_id\x18\x01 \x01(\x05R\n" +
+ "categoryId\x12\x12\n" +
+ "\x04page\x18\x02 \x01(\x05R\x04page\x12\x1b\n" +
+ "\tpage_size\x18\x03 \x01(\x05R\bpageSize\"^\n" +
+ "\x17LibraryFileListResponse\x12-\n" +
+ "\x05files\x18\x01 \x03(\v2\x17.cloudprint.LibraryFileR\x05files\x12\x14\n" +
+ "\x05total\x18\x02 \x01(\x05R\x05total\"\xc1\x01\n" +
+ "\x18UploadLibraryFileRequest\x12\x1f\n" +
+ "\vcategory_id\x18\x01 \x01(\x05R\n" +
+ "categoryId\x12\x14\n" +
+ "\x05title\x18\x02 \x01(\tR\x05title\x12 \n" +
+ "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x12\n" +
+ "\x04data\x18\x04 \x01(\fR\x04data\x12\x1b\n" +
+ "\tfile_name\x18\x05 \x01(\tR\bfileName\x12\x1b\n" +
+ "\tfile_type\x18\x06 \x01(\tR\bfileType\"C\n" +
+ "\x19UploadLibraryFileResponse\x12&\n" +
+ "\x0flibrary_file_id\x18\x01 \x01(\x05R\rlibraryFileId\"B\n" +
+ "\x18DeleteLibraryFileRequest\x12&\n" +
+ "\x0flibrary_file_id\x18\x01 \x01(\x05R\rlibraryFileId\"\xaf\x01\n" +
+ "\tPriceItem\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n" +
+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
+ "\x04type\x18\x03 \x01(\tR\x04type\x12\x14\n" +
+ "\x05price\x18\x04 \x01(\x01R\x05price\x12\x12\n" +
+ "\x04unit\x18\x05 \x01(\tR\x04unit\x12#\n" +
+ "\rcolor_enabled\x18\x06 \x01(\bR\fcolorEnabled\x12\x1b\n" +
+ "\tis_active\x18\a \x01(\bR\bisActive\"\x15\n" +
+ "\x13GetPriceListRequest\"@\n" +
+ "\x11PriceListResponse\x12+\n" +
+ "\x05items\x18\x01 \x03(\v2\x15.cloudprint.PriceItemR\x05items\"\x8f\x01\n" +
+ "\x16CreatePriceItemRequest\x12\x12\n" +
+ "\x04name\x18\x01 \x01(\tR\x04name\x12\x12\n" +
+ "\x04type\x18\x02 \x01(\tR\x04type\x12\x14\n" +
+ "\x05price\x18\x03 \x01(\x01R\x05price\x12\x12\n" +
+ "\x04unit\x18\x04 \x01(\tR\x04unit\x12#\n" +
+ "\rcolor_enabled\x18\x05 \x01(\bR\fcolorEnabled\"\xbc\x01\n" +
+ "\x16UpdatePriceItemRequest\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x12\n" +
+ "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
+ "\x04type\x18\x03 \x01(\tR\x04type\x12\x14\n" +
+ "\x05price\x18\x04 \x01(\x01R\x05price\x12\x12\n" +
+ "\x04unit\x18\x05 \x01(\tR\x04unit\x12#\n" +
+ "\rcolor_enabled\x18\x06 \x01(\bR\fcolorEnabled\x12\x1b\n" +
+ "\tis_active\x18\a \x01(\bR\bisActive\"\x98\x01\n" +
+ "\fWxPayRequest\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\x12\x16\n" +
+ "\x06amount\x18\x02 \x01(\x01R\x06amount\x12 \n" +
+ "\vdescription\x18\x03 \x01(\tR\vdescription\x12\x16\n" +
+ "\x06openid\x18\x04 \x01(\tR\x06openid\x12\x1b\n" +
+ "\tclient_ip\x18\x05 \x01(\tR\bclientIp\"b\n" +
+ "\rWxPayResponse\x12\x1b\n" +
+ "\tprepay_id\x18\x01 \x01(\tR\bprepayId\x12\x19\n" +
+ "\bcode_url\x18\x02 \x01(\tR\acodeUrl\x12\x19\n" +
+ "\bmweb_url\x18\x03 \x01(\tR\amwebUrl\"2\n" +
+ "\x15QueryPayStatusRequest\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\"R\n" +
+ "\x11PayStatusResponse\x12\x16\n" +
+ "\x06status\x18\x01 \x01(\x05R\x06status\x12%\n" +
+ "\x0etransaction_id\x18\x02 \x01(\tR\rtransactionId\"(\n" +
+ "\x12PayCallbackRequest\x12\x12\n" +
+ "\x04body\x18\x01 \x01(\tR\x04body\"U\n" +
+ "\x13PayCallbackResponse\x12\x1f\n" +
+ "\vreturn_code\x18\x01 \x01(\tR\n" +
+ "returnCode\x12\x1d\n" +
+ "\n" +
+ "return_msg\x18\x02 \x01(\tR\treturnMsg\"I\n" +
+ "\x13PayByBalanceRequest\x12\x19\n" +
+ "\border_no\x18\x01 \x01(\tR\aorderNo\x12\x17\n" +
+ "\auser_id\x18\x02 \x01(\x05R\x06userId\"\x9e\x01\n" +
+ "\x05Admin\x12\x0e\n" +
+ "\x02id\x18\x01 \x01(\x05R\x02id\x12\x1a\n" +
+ "\busername\x18\x02 \x01(\tR\busername\x12\x1a\n" +
+ "\bnickname\x18\x03 \x01(\tR\bnickname\x12\x12\n" +
+ "\x04role\x18\x04 \x01(\x05R\x04role\x129\n" +
+ "\n" +
+ "created_at\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\tcreatedAt\"K\n" +
+ "\x11AdminLoginRequest\x12\x1a\n" +
+ "\busername\x18\x01 \x01(\tR\busername\x12\x1a\n" +
+ "\bpassword\x18\x02 \x01(\tR\bpassword\"`\n" +
+ "\x12AdminLoginResponse\x12!\n" +
+ "\faccess_token\x18\x01 \x01(\tR\vaccessToken\x12'\n" +
+ "\x05admin\x18\x02 \x01(\v2\x11.cloudprint.AdminR\x05admin\"\x16\n" +
+ "\x14GetStatisticsRequest\"\xe8\x01\n" +
+ "\n" +
+ "Statistics\x12\x1f\n" +
+ "\vtotal_users\x18\x01 \x01(\x05R\n" +
+ "totalUsers\x12!\n" +
+ "\ftotal_orders\x18\x02 \x01(\x05R\vtotalOrders\x12!\n" +
+ "\ftoday_orders\x18\x03 \x01(\x05R\vtodayOrders\x12#\n" +
+ "\rtoday_revenue\x18\x04 \x01(\x01R\ftodayRevenue\x12%\n" +
+ "\x0epending_orders\x18\x05 \x01(\x05R\rpendingOrders\x12'\n" +
+ "\x0factive_printers\x18\x06 \x01(\x05R\x0eactivePrinters2\x94\x02\n" +
+ "\vAuthService\x12<\n" +
+ "\x05Login\x12\x18.cloudprint.LoginRequest\x1a\x19.cloudprint.LoginResponse\x12G\n" +
+ "\fRefreshToken\x12\x1a.cloudprint.RefreshRequest\x1a\x1b.cloudprint.RefreshResponse\x12?\n" +
+ "\vGetUserInfo\x12\x1e.cloudprint.GetUserInfoRequest\x1a\x10.cloudprint.User\x12=\n" +
+ "\n" +
+ "UpdateUser\x12\x1d.cloudprint.UpdateUserRequest\x1a\x10.cloudprint.User2\xe9\x02\n" +
+ "\vFileService\x12A\n" +
+ "\x06Upload\x12\x19.cloudprint.UploadRequest\x1a\x1a.cloudprint.UploadResponse(\x01\x12=\n" +
+ "\aGetFile\x12\x1a.cloudprint.GetFileRequest\x1a\x14.cloudprint.FileData0\x01\x12>\n" +
+ "\n" +
+ "DeleteFile\x12\x1d.cloudprint.DeleteFileRequest\x1a\x11.cloudprint.Empty\x12K\n" +
+ "\fAddWatermark\x12\x1c.cloudprint.WatermarkRequest\x1a\x1d.cloudprint.WatermarkResponse\x12K\n" +
+ "\vGetFileList\x12\x1e.cloudprint.GetFileListRequest\x1a\x1c.cloudprint.FileListResponse2\xfa\x02\n" +
+ "\fOrderService\x12N\n" +
+ "\vCreateOrder\x12\x1e.cloudprint.CreateOrderRequest\x1a\x1f.cloudprint.CreateOrderResponse\x12:\n" +
+ "\bGetOrder\x12\x1b.cloudprint.GetOrderRequest\x1a\x11.cloudprint.Order\x12N\n" +
+ "\fGetOrderList\x12\x1f.cloudprint.GetOrderListRequest\x1a\x1d.cloudprint.OrderListResponse\x12L\n" +
+ "\x11UpdateOrderStatus\x12$.cloudprint.UpdateOrderStatusRequest\x1a\x11.cloudprint.Empty\x12@\n" +
+ "\vCancelOrder\x12\x1e.cloudprint.CancelOrderRequest\x1a\x11.cloudprint.Empty2\x98\x05\n" +
+ "\fPrintService\x12N\n" +
+ "\vGetPrinters\x12\x1e.cloudprint.GetPrintersRequest\x1a\x1f.cloudprint.PrinterListResponse\x12Z\n" +
+ "\x10GetPrinterStatus\x12#.cloudprint.GetPrinterStatusRequest\x1a!.cloudprint.PrinterStatusResponse\x12Z\n" +
+ "\x0fRegisterPrinter\x12\".cloudprint.RegisterPrinterRequest\x1a#.cloudprint.RegisterPrinterResponse\x12J\n" +
+ "\x10PrinterHeartbeat\x12#.cloudprint.PrinterHeartbeatRequest\x1a\x11.cloudprint.Empty\x12W\n" +
+ "\x0eSubmitPrintJob\x12!.cloudprint.SubmitPrintJobRequest\x1a\".cloudprint.SubmitPrintJobResponse\x12F\n" +
+ "\x0eCancelPrintJob\x12!.cloudprint.CancelPrintJobRequest\x1a\x11.cloudprint.Empty\x12I\n" +
+ "\rSubscribeJobs\x12 .cloudprint.SubscribeJobsRequest\x1a\x14.cloudprint.PrintJob0\x01\x12H\n" +
+ "\x0fReportJobStatus\x12\".cloudprint.ReportJobStatusRequest\x1a\x11.cloudprint.Empty2\xde\x02\n" +
+ "\x0eLibraryService\x12S\n" +
+ "\rGetCategories\x12 .cloudprint.GetCategoriesRequest\x1a .cloudprint.CategoryListResponse\x12S\n" +
+ "\bGetFiles\x12\".cloudprint.GetLibraryFilesRequest\x1a#.cloudprint.LibraryFileListResponse\x12[\n" +
+ "\n" +
+ "UploadFile\x12$.cloudprint.UploadLibraryFileRequest\x1a%.cloudprint.UploadLibraryFileResponse(\x01\x12E\n" +
+ "\n" +
+ "DeleteFile\x12$.cloudprint.DeleteLibraryFileRequest\x1a\x11.cloudprint.Empty2\xfa\x01\n" +
+ "\fPriceService\x12N\n" +
+ "\fGetPriceList\x12\x1f.cloudprint.GetPriceListRequest\x1a\x1d.cloudprint.PriceListResponse\x12L\n" +
+ "\x0fCreatePriceItem\x12\".cloudprint.CreatePriceItemRequest\x1a\x15.cloudprint.PriceItem\x12L\n" +
+ "\x0fUpdatePriceItem\x12\".cloudprint.UpdatePriceItemRequest\x1a\x15.cloudprint.PriceItem2\xcc\x02\n" +
+ "\n" +
+ "PayService\x12G\n" +
+ "\x10CreateWxPayOrder\x12\x18.cloudprint.WxPayRequest\x1a\x19.cloudprint.WxPayResponse\x12R\n" +
+ "\x0eQueryPayStatus\x12!.cloudprint.QueryPayStatusRequest\x1a\x1d.cloudprint.PayStatusResponse\x12T\n" +
+ "\x11HandlePayCallback\x12\x1e.cloudprint.PayCallbackRequest\x1a\x1f.cloudprint.PayCallbackResponse\x12K\n" +
+ "\fPayByBalance\x12\x1f.cloudprint.PayByBalanceRequest\x1a\x1a.cloudprint.StatusResponse2\xa1\x01\n" +
+ "\fAdminService\x12F\n" +
+ "\x05Login\x12\x1d.cloudprint.AdminLoginRequest\x1a\x1e.cloudprint.AdminLoginResponse\x12I\n" +
+ "\rGetStatistics\x12 .cloudprint.GetStatisticsRequest\x1a\x16.cloudprint.StatisticsB:Z8github.com/cloudprint/cloudprint-backend/proto/generatedb\x06proto3"
+
+var (
+ file_cloudprint_proto_rawDescOnce sync.Once
+ file_cloudprint_proto_rawDescData []byte
+)
+
+func file_cloudprint_proto_rawDescGZIP() []byte {
+ file_cloudprint_proto_rawDescOnce.Do(func() {
+ file_cloudprint_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_cloudprint_proto_rawDesc), len(file_cloudprint_proto_rawDesc)))
+ })
+ return file_cloudprint_proto_rawDescData
+}
+
+var file_cloudprint_proto_msgTypes = make([]protoimpl.MessageInfo, 69)
+var file_cloudprint_proto_goTypes = []any{
+ (*Empty)(nil), // 0: cloudprint.Empty
+ (*StatusResponse)(nil), // 1: cloudprint.StatusResponse
+ (*User)(nil), // 2: cloudprint.User
+ (*LoginRequest)(nil), // 3: cloudprint.LoginRequest
+ (*LoginResponse)(nil), // 4: cloudprint.LoginResponse
+ (*RefreshRequest)(nil), // 5: cloudprint.RefreshRequest
+ (*RefreshResponse)(nil), // 6: cloudprint.RefreshResponse
+ (*GetUserInfoRequest)(nil), // 7: cloudprint.GetUserInfoRequest
+ (*UpdateUserRequest)(nil), // 8: cloudprint.UpdateUserRequest
+ (*FileInfo)(nil), // 9: cloudprint.FileInfo
+ (*UploadRequest)(nil), // 10: cloudprint.UploadRequest
+ (*UploadResponse)(nil), // 11: cloudprint.UploadResponse
+ (*GetFileRequest)(nil), // 12: cloudprint.GetFileRequest
+ (*FileData)(nil), // 13: cloudprint.FileData
+ (*DeleteFileRequest)(nil), // 14: cloudprint.DeleteFileRequest
+ (*WatermarkRequest)(nil), // 15: cloudprint.WatermarkRequest
+ (*WatermarkResponse)(nil), // 16: cloudprint.WatermarkResponse
+ (*GetFileListRequest)(nil), // 17: cloudprint.GetFileListRequest
+ (*FileListResponse)(nil), // 18: cloudprint.FileListResponse
+ (*Order)(nil), // 19: cloudprint.Order
+ (*OrderItem)(nil), // 20: cloudprint.OrderItem
+ (*CreateOrderRequest)(nil), // 21: cloudprint.CreateOrderRequest
+ (*CreateOrderItem)(nil), // 22: cloudprint.CreateOrderItem
+ (*CreateOrderResponse)(nil), // 23: cloudprint.CreateOrderResponse
+ (*GetOrderRequest)(nil), // 24: cloudprint.GetOrderRequest
+ (*GetOrderListRequest)(nil), // 25: cloudprint.GetOrderListRequest
+ (*OrderListResponse)(nil), // 26: cloudprint.OrderListResponse
+ (*UpdateOrderStatusRequest)(nil), // 27: cloudprint.UpdateOrderStatusRequest
+ (*CancelOrderRequest)(nil), // 28: cloudprint.CancelOrderRequest
+ (*Printer)(nil), // 29: cloudprint.Printer
+ (*GetPrintersRequest)(nil), // 30: cloudprint.GetPrintersRequest
+ (*PrinterListResponse)(nil), // 31: cloudprint.PrinterListResponse
+ (*GetPrinterStatusRequest)(nil), // 32: cloudprint.GetPrinterStatusRequest
+ (*PrinterStatusResponse)(nil), // 33: cloudprint.PrinterStatusResponse
+ (*RegisterPrinterRequest)(nil), // 34: cloudprint.RegisterPrinterRequest
+ (*RegisterPrinterResponse)(nil), // 35: cloudprint.RegisterPrinterResponse
+ (*PrinterHeartbeatRequest)(nil), // 36: cloudprint.PrinterHeartbeatRequest
+ (*PrintJob)(nil), // 37: cloudprint.PrintJob
+ (*SubmitPrintJobRequest)(nil), // 38: cloudprint.SubmitPrintJobRequest
+ (*SubmitPrintJobResponse)(nil), // 39: cloudprint.SubmitPrintJobResponse
+ (*CancelPrintJobRequest)(nil), // 40: cloudprint.CancelPrintJobRequest
+ (*SubscribeJobsRequest)(nil), // 41: cloudprint.SubscribeJobsRequest
+ (*ReportJobStatusRequest)(nil), // 42: cloudprint.ReportJobStatusRequest
+ (*LibraryCategory)(nil), // 43: cloudprint.LibraryCategory
+ (*LibraryFile)(nil), // 44: cloudprint.LibraryFile
+ (*GetCategoriesRequest)(nil), // 45: cloudprint.GetCategoriesRequest
+ (*CategoryListResponse)(nil), // 46: cloudprint.CategoryListResponse
+ (*GetLibraryFilesRequest)(nil), // 47: cloudprint.GetLibraryFilesRequest
+ (*LibraryFileListResponse)(nil), // 48: cloudprint.LibraryFileListResponse
+ (*UploadLibraryFileRequest)(nil), // 49: cloudprint.UploadLibraryFileRequest
+ (*UploadLibraryFileResponse)(nil), // 50: cloudprint.UploadLibraryFileResponse
+ (*DeleteLibraryFileRequest)(nil), // 51: cloudprint.DeleteLibraryFileRequest
+ (*PriceItem)(nil), // 52: cloudprint.PriceItem
+ (*GetPriceListRequest)(nil), // 53: cloudprint.GetPriceListRequest
+ (*PriceListResponse)(nil), // 54: cloudprint.PriceListResponse
+ (*CreatePriceItemRequest)(nil), // 55: cloudprint.CreatePriceItemRequest
+ (*UpdatePriceItemRequest)(nil), // 56: cloudprint.UpdatePriceItemRequest
+ (*WxPayRequest)(nil), // 57: cloudprint.WxPayRequest
+ (*WxPayResponse)(nil), // 58: cloudprint.WxPayResponse
+ (*QueryPayStatusRequest)(nil), // 59: cloudprint.QueryPayStatusRequest
+ (*PayStatusResponse)(nil), // 60: cloudprint.PayStatusResponse
+ (*PayCallbackRequest)(nil), // 61: cloudprint.PayCallbackRequest
+ (*PayCallbackResponse)(nil), // 62: cloudprint.PayCallbackResponse
+ (*PayByBalanceRequest)(nil), // 63: cloudprint.PayByBalanceRequest
+ (*Admin)(nil), // 64: cloudprint.Admin
+ (*AdminLoginRequest)(nil), // 65: cloudprint.AdminLoginRequest
+ (*AdminLoginResponse)(nil), // 66: cloudprint.AdminLoginResponse
+ (*GetStatisticsRequest)(nil), // 67: cloudprint.GetStatisticsRequest
+ (*Statistics)(nil), // 68: cloudprint.Statistics
+ (*timestamppb.Timestamp)(nil), // 69: google.protobuf.Timestamp
+}
+var file_cloudprint_proto_depIdxs = []int32{
+ 69, // 0: cloudprint.User.created_at:type_name -> google.protobuf.Timestamp
+ 2, // 1: cloudprint.LoginResponse.user:type_name -> cloudprint.User
+ 69, // 2: cloudprint.FileInfo.created_at:type_name -> google.protobuf.Timestamp
+ 9, // 3: cloudprint.FileListResponse.files:type_name -> cloudprint.FileInfo
+ 69, // 4: cloudprint.Order.created_at:type_name -> google.protobuf.Timestamp
+ 69, // 5: cloudprint.Order.paid_at:type_name -> google.protobuf.Timestamp
+ 20, // 6: cloudprint.Order.items:type_name -> cloudprint.OrderItem
+ 9, // 7: cloudprint.OrderItem.file:type_name -> cloudprint.FileInfo
+ 22, // 8: cloudprint.CreateOrderRequest.items:type_name -> cloudprint.CreateOrderItem
+ 19, // 9: cloudprint.OrderListResponse.orders:type_name -> cloudprint.Order
+ 69, // 10: cloudprint.Printer.last_heartbeat:type_name -> google.protobuf.Timestamp
+ 29, // 11: cloudprint.PrinterListResponse.printers:type_name -> cloudprint.Printer
+ 29, // 12: cloudprint.PrinterStatusResponse.printer:type_name -> cloudprint.Printer
+ 69, // 13: cloudprint.PrintJob.started_at:type_name -> google.protobuf.Timestamp
+ 69, // 14: cloudprint.PrintJob.completed_at:type_name -> google.protobuf.Timestamp
+ 20, // 15: cloudprint.PrintJob.order_item:type_name -> cloudprint.OrderItem
+ 9, // 16: cloudprint.LibraryFile.file:type_name -> cloudprint.FileInfo
+ 69, // 17: cloudprint.LibraryFile.created_at:type_name -> google.protobuf.Timestamp
+ 43, // 18: cloudprint.CategoryListResponse.categories:type_name -> cloudprint.LibraryCategory
+ 44, // 19: cloudprint.LibraryFileListResponse.files:type_name -> cloudprint.LibraryFile
+ 52, // 20: cloudprint.PriceListResponse.items:type_name -> cloudprint.PriceItem
+ 69, // 21: cloudprint.Admin.created_at:type_name -> google.protobuf.Timestamp
+ 64, // 22: cloudprint.AdminLoginResponse.admin:type_name -> cloudprint.Admin
+ 3, // 23: cloudprint.AuthService.Login:input_type -> cloudprint.LoginRequest
+ 5, // 24: cloudprint.AuthService.RefreshToken:input_type -> cloudprint.RefreshRequest
+ 7, // 25: cloudprint.AuthService.GetUserInfo:input_type -> cloudprint.GetUserInfoRequest
+ 8, // 26: cloudprint.AuthService.UpdateUser:input_type -> cloudprint.UpdateUserRequest
+ 10, // 27: cloudprint.FileService.Upload:input_type -> cloudprint.UploadRequest
+ 12, // 28: cloudprint.FileService.GetFile:input_type -> cloudprint.GetFileRequest
+ 14, // 29: cloudprint.FileService.DeleteFile:input_type -> cloudprint.DeleteFileRequest
+ 15, // 30: cloudprint.FileService.AddWatermark:input_type -> cloudprint.WatermarkRequest
+ 17, // 31: cloudprint.FileService.GetFileList:input_type -> cloudprint.GetFileListRequest
+ 21, // 32: cloudprint.OrderService.CreateOrder:input_type -> cloudprint.CreateOrderRequest
+ 24, // 33: cloudprint.OrderService.GetOrder:input_type -> cloudprint.GetOrderRequest
+ 25, // 34: cloudprint.OrderService.GetOrderList:input_type -> cloudprint.GetOrderListRequest
+ 27, // 35: cloudprint.OrderService.UpdateOrderStatus:input_type -> cloudprint.UpdateOrderStatusRequest
+ 28, // 36: cloudprint.OrderService.CancelOrder:input_type -> cloudprint.CancelOrderRequest
+ 30, // 37: cloudprint.PrintService.GetPrinters:input_type -> cloudprint.GetPrintersRequest
+ 32, // 38: cloudprint.PrintService.GetPrinterStatus:input_type -> cloudprint.GetPrinterStatusRequest
+ 34, // 39: cloudprint.PrintService.RegisterPrinter:input_type -> cloudprint.RegisterPrinterRequest
+ 36, // 40: cloudprint.PrintService.PrinterHeartbeat:input_type -> cloudprint.PrinterHeartbeatRequest
+ 38, // 41: cloudprint.PrintService.SubmitPrintJob:input_type -> cloudprint.SubmitPrintJobRequest
+ 40, // 42: cloudprint.PrintService.CancelPrintJob:input_type -> cloudprint.CancelPrintJobRequest
+ 41, // 43: cloudprint.PrintService.SubscribeJobs:input_type -> cloudprint.SubscribeJobsRequest
+ 42, // 44: cloudprint.PrintService.ReportJobStatus:input_type -> cloudprint.ReportJobStatusRequest
+ 45, // 45: cloudprint.LibraryService.GetCategories:input_type -> cloudprint.GetCategoriesRequest
+ 47, // 46: cloudprint.LibraryService.GetFiles:input_type -> cloudprint.GetLibraryFilesRequest
+ 49, // 47: cloudprint.LibraryService.UploadFile:input_type -> cloudprint.UploadLibraryFileRequest
+ 51, // 48: cloudprint.LibraryService.DeleteFile:input_type -> cloudprint.DeleteLibraryFileRequest
+ 53, // 49: cloudprint.PriceService.GetPriceList:input_type -> cloudprint.GetPriceListRequest
+ 55, // 50: cloudprint.PriceService.CreatePriceItem:input_type -> cloudprint.CreatePriceItemRequest
+ 56, // 51: cloudprint.PriceService.UpdatePriceItem:input_type -> cloudprint.UpdatePriceItemRequest
+ 57, // 52: cloudprint.PayService.CreateWxPayOrder:input_type -> cloudprint.WxPayRequest
+ 59, // 53: cloudprint.PayService.QueryPayStatus:input_type -> cloudprint.QueryPayStatusRequest
+ 61, // 54: cloudprint.PayService.HandlePayCallback:input_type -> cloudprint.PayCallbackRequest
+ 63, // 55: cloudprint.PayService.PayByBalance:input_type -> cloudprint.PayByBalanceRequest
+ 65, // 56: cloudprint.AdminService.Login:input_type -> cloudprint.AdminLoginRequest
+ 67, // 57: cloudprint.AdminService.GetStatistics:input_type -> cloudprint.GetStatisticsRequest
+ 4, // 58: cloudprint.AuthService.Login:output_type -> cloudprint.LoginResponse
+ 6, // 59: cloudprint.AuthService.RefreshToken:output_type -> cloudprint.RefreshResponse
+ 2, // 60: cloudprint.AuthService.GetUserInfo:output_type -> cloudprint.User
+ 2, // 61: cloudprint.AuthService.UpdateUser:output_type -> cloudprint.User
+ 11, // 62: cloudprint.FileService.Upload:output_type -> cloudprint.UploadResponse
+ 13, // 63: cloudprint.FileService.GetFile:output_type -> cloudprint.FileData
+ 0, // 64: cloudprint.FileService.DeleteFile:output_type -> cloudprint.Empty
+ 16, // 65: cloudprint.FileService.AddWatermark:output_type -> cloudprint.WatermarkResponse
+ 18, // 66: cloudprint.FileService.GetFileList:output_type -> cloudprint.FileListResponse
+ 23, // 67: cloudprint.OrderService.CreateOrder:output_type -> cloudprint.CreateOrderResponse
+ 19, // 68: cloudprint.OrderService.GetOrder:output_type -> cloudprint.Order
+ 26, // 69: cloudprint.OrderService.GetOrderList:output_type -> cloudprint.OrderListResponse
+ 0, // 70: cloudprint.OrderService.UpdateOrderStatus:output_type -> cloudprint.Empty
+ 0, // 71: cloudprint.OrderService.CancelOrder:output_type -> cloudprint.Empty
+ 31, // 72: cloudprint.PrintService.GetPrinters:output_type -> cloudprint.PrinterListResponse
+ 33, // 73: cloudprint.PrintService.GetPrinterStatus:output_type -> cloudprint.PrinterStatusResponse
+ 35, // 74: cloudprint.PrintService.RegisterPrinter:output_type -> cloudprint.RegisterPrinterResponse
+ 0, // 75: cloudprint.PrintService.PrinterHeartbeat:output_type -> cloudprint.Empty
+ 39, // 76: cloudprint.PrintService.SubmitPrintJob:output_type -> cloudprint.SubmitPrintJobResponse
+ 0, // 77: cloudprint.PrintService.CancelPrintJob:output_type -> cloudprint.Empty
+ 37, // 78: cloudprint.PrintService.SubscribeJobs:output_type -> cloudprint.PrintJob
+ 0, // 79: cloudprint.PrintService.ReportJobStatus:output_type -> cloudprint.Empty
+ 46, // 80: cloudprint.LibraryService.GetCategories:output_type -> cloudprint.CategoryListResponse
+ 48, // 81: cloudprint.LibraryService.GetFiles:output_type -> cloudprint.LibraryFileListResponse
+ 50, // 82: cloudprint.LibraryService.UploadFile:output_type -> cloudprint.UploadLibraryFileResponse
+ 0, // 83: cloudprint.LibraryService.DeleteFile:output_type -> cloudprint.Empty
+ 54, // 84: cloudprint.PriceService.GetPriceList:output_type -> cloudprint.PriceListResponse
+ 52, // 85: cloudprint.PriceService.CreatePriceItem:output_type -> cloudprint.PriceItem
+ 52, // 86: cloudprint.PriceService.UpdatePriceItem:output_type -> cloudprint.PriceItem
+ 58, // 87: cloudprint.PayService.CreateWxPayOrder:output_type -> cloudprint.WxPayResponse
+ 60, // 88: cloudprint.PayService.QueryPayStatus:output_type -> cloudprint.PayStatusResponse
+ 62, // 89: cloudprint.PayService.HandlePayCallback:output_type -> cloudprint.PayCallbackResponse
+ 1, // 90: cloudprint.PayService.PayByBalance:output_type -> cloudprint.StatusResponse
+ 66, // 91: cloudprint.AdminService.Login:output_type -> cloudprint.AdminLoginResponse
+ 68, // 92: cloudprint.AdminService.GetStatistics:output_type -> cloudprint.Statistics
+ 58, // [58:93] is the sub-list for method output_type
+ 23, // [23:58] is the sub-list for method input_type
+ 23, // [23:23] is the sub-list for extension type_name
+ 23, // [23:23] is the sub-list for extension extendee
+ 0, // [0:23] is the sub-list for field type_name
+}
+
+func init() { file_cloudprint_proto_init() }
+func file_cloudprint_proto_init() {
+ if File_cloudprint_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_cloudprint_proto_rawDesc), len(file_cloudprint_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 69,
+ NumExtensions: 0,
+ NumServices: 8,
+ },
+ GoTypes: file_cloudprint_proto_goTypes,
+ DependencyIndexes: file_cloudprint_proto_depIdxs,
+ MessageInfos: file_cloudprint_proto_msgTypes,
+ }.Build()
+ File_cloudprint_proto = out.File
+ file_cloudprint_proto_goTypes = nil
+ file_cloudprint_proto_depIdxs = nil
+}
diff --git a/cloudprint-backend/proto/generated/cloudprint_grpc.pb.go b/cloudprint-backend/proto/generated/cloudprint_grpc.pb.go
new file mode 100644
index 0000000..70d2fd2
--- /dev/null
+++ b/cloudprint-backend/proto/generated/cloudprint_grpc.pb.go
@@ -0,0 +1,1856 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.6.1
+// - protoc v6.32.0
+// source: cloudprint.proto
+
+package generated
+
+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
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.64.0 or later.
+const _ = grpc.SupportPackageIsVersion9
+
+const (
+ AuthService_Login_FullMethodName = "/cloudprint.AuthService/Login"
+ AuthService_RefreshToken_FullMethodName = "/cloudprint.AuthService/RefreshToken"
+ AuthService_GetUserInfo_FullMethodName = "/cloudprint.AuthService/GetUserInfo"
+ AuthService_UpdateUser_FullMethodName = "/cloudprint.AuthService/UpdateUser"
+)
+
+// AuthServiceClient is the client API for AuthService 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 AuthServiceClient interface {
+ Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error)
+ RefreshToken(ctx context.Context, in *RefreshRequest, opts ...grpc.CallOption) (*RefreshResponse, error)
+ GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*User, error)
+ UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error)
+}
+
+type authServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient {
+ return &authServiceClient{cc}
+}
+
+func (c *authServiceClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*LoginResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(LoginResponse)
+ err := c.cc.Invoke(ctx, AuthService_Login_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *authServiceClient) RefreshToken(ctx context.Context, in *RefreshRequest, opts ...grpc.CallOption) (*RefreshResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RefreshResponse)
+ err := c.cc.Invoke(ctx, AuthService_RefreshToken_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *authServiceClient) GetUserInfo(ctx context.Context, in *GetUserInfoRequest, opts ...grpc.CallOption) (*User, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(User)
+ err := c.cc.Invoke(ctx, AuthService_GetUserInfo_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *authServiceClient) UpdateUser(ctx context.Context, in *UpdateUserRequest, opts ...grpc.CallOption) (*User, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(User)
+ err := c.cc.Invoke(ctx, AuthService_UpdateUser_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// AuthServiceServer is the server API for AuthService service.
+// All implementations must embed UnimplementedAuthServiceServer
+// for forward compatibility.
+type AuthServiceServer interface {
+ Login(context.Context, *LoginRequest) (*LoginResponse, error)
+ RefreshToken(context.Context, *RefreshRequest) (*RefreshResponse, error)
+ GetUserInfo(context.Context, *GetUserInfoRequest) (*User, error)
+ UpdateUser(context.Context, *UpdateUserRequest) (*User, error)
+ mustEmbedUnimplementedAuthServiceServer()
+}
+
+// UnimplementedAuthServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedAuthServiceServer struct{}
+
+func (UnimplementedAuthServiceServer) Login(context.Context, *LoginRequest) (*LoginResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method Login not implemented")
+}
+func (UnimplementedAuthServiceServer) RefreshToken(context.Context, *RefreshRequest) (*RefreshResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method RefreshToken not implemented")
+}
+func (UnimplementedAuthServiceServer) GetUserInfo(context.Context, *GetUserInfoRequest) (*User, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetUserInfo not implemented")
+}
+func (UnimplementedAuthServiceServer) UpdateUser(context.Context, *UpdateUserRequest) (*User, error) {
+ return nil, status.Error(codes.Unimplemented, "method UpdateUser not implemented")
+}
+func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {}
+func (UnimplementedAuthServiceServer) testEmbeddedByValue() {}
+
+// UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AuthServiceServer will
+// result in compilation errors.
+type UnsafeAuthServiceServer interface {
+ mustEmbedUnimplementedAuthServiceServer()
+}
+
+func RegisterAuthServiceServer(s grpc.ServiceRegistrar, srv AuthServiceServer) {
+ // If the following call panics, it indicates UnimplementedAuthServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&AuthService_ServiceDesc, srv)
+}
+
+func _AuthService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(LoginRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AuthServiceServer).Login(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: AuthService_Login_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AuthServiceServer).Login(ctx, req.(*LoginRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AuthService_RefreshToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RefreshRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AuthServiceServer).RefreshToken(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: AuthService_RefreshToken_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AuthServiceServer).RefreshToken(ctx, req.(*RefreshRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AuthService_GetUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetUserInfoRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AuthServiceServer).GetUserInfo(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: AuthService_GetUserInfo_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AuthServiceServer).GetUserInfo(ctx, req.(*GetUserInfoRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AuthService_UpdateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateUserRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AuthServiceServer).UpdateUser(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: AuthService_UpdateUser_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AuthServiceServer).UpdateUser(ctx, req.(*UpdateUserRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AuthService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.AuthService",
+ HandlerType: (*AuthServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Login",
+ Handler: _AuthService_Login_Handler,
+ },
+ {
+ MethodName: "RefreshToken",
+ Handler: _AuthService_RefreshToken_Handler,
+ },
+ {
+ MethodName: "GetUserInfo",
+ Handler: _AuthService_GetUserInfo_Handler,
+ },
+ {
+ MethodName: "UpdateUser",
+ Handler: _AuthService_UpdateUser_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ FileService_Upload_FullMethodName = "/cloudprint.FileService/Upload"
+ FileService_GetFile_FullMethodName = "/cloudprint.FileService/GetFile"
+ FileService_DeleteFile_FullMethodName = "/cloudprint.FileService/DeleteFile"
+ FileService_AddWatermark_FullMethodName = "/cloudprint.FileService/AddWatermark"
+ FileService_GetFileList_FullMethodName = "/cloudprint.FileService/GetFileList"
+)
+
+// FileServiceClient is the client API for FileService 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 FileServiceClient interface {
+ Upload(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[UploadRequest, UploadResponse], error)
+ GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[FileData], error)
+ DeleteFile(ctx context.Context, in *DeleteFileRequest, opts ...grpc.CallOption) (*Empty, error)
+ AddWatermark(ctx context.Context, in *WatermarkRequest, opts ...grpc.CallOption) (*WatermarkResponse, error)
+ GetFileList(ctx context.Context, in *GetFileListRequest, opts ...grpc.CallOption) (*FileListResponse, error)
+}
+
+type fileServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewFileServiceClient(cc grpc.ClientConnInterface) FileServiceClient {
+ return &fileServiceClient{cc}
+}
+
+func (c *fileServiceClient) Upload(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[UploadRequest, UploadResponse], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &FileService_ServiceDesc.Streams[0], FileService_Upload_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[UploadRequest, UploadResponse]{ClientStream: stream}
+ return x, nil
+}
+
+// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
+type FileService_UploadClient = grpc.ClientStreamingClient[UploadRequest, UploadResponse]
+
+func (c *fileServiceClient) GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[FileData], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &FileService_ServiceDesc.Streams[1], FileService_GetFile_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[GetFileRequest, FileData]{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 FileService_GetFileClient = grpc.ServerStreamingClient[FileData]
+
+func (c *fileServiceClient) DeleteFile(ctx context.Context, in *DeleteFileRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, FileService_DeleteFile_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *fileServiceClient) AddWatermark(ctx context.Context, in *WatermarkRequest, opts ...grpc.CallOption) (*WatermarkResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(WatermarkResponse)
+ err := c.cc.Invoke(ctx, FileService_AddWatermark_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *fileServiceClient) GetFileList(ctx context.Context, in *GetFileListRequest, opts ...grpc.CallOption) (*FileListResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(FileListResponse)
+ err := c.cc.Invoke(ctx, FileService_GetFileList_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// FileServiceServer is the server API for FileService service.
+// All implementations must embed UnimplementedFileServiceServer
+// for forward compatibility.
+type FileServiceServer interface {
+ Upload(grpc.ClientStreamingServer[UploadRequest, UploadResponse]) error
+ GetFile(*GetFileRequest, grpc.ServerStreamingServer[FileData]) error
+ DeleteFile(context.Context, *DeleteFileRequest) (*Empty, error)
+ AddWatermark(context.Context, *WatermarkRequest) (*WatermarkResponse, error)
+ GetFileList(context.Context, *GetFileListRequest) (*FileListResponse, error)
+ mustEmbedUnimplementedFileServiceServer()
+}
+
+// UnimplementedFileServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedFileServiceServer struct{}
+
+func (UnimplementedFileServiceServer) Upload(grpc.ClientStreamingServer[UploadRequest, UploadResponse]) error {
+ return status.Error(codes.Unimplemented, "method Upload not implemented")
+}
+func (UnimplementedFileServiceServer) GetFile(*GetFileRequest, grpc.ServerStreamingServer[FileData]) error {
+ return status.Error(codes.Unimplemented, "method GetFile not implemented")
+}
+func (UnimplementedFileServiceServer) DeleteFile(context.Context, *DeleteFileRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteFile not implemented")
+}
+func (UnimplementedFileServiceServer) AddWatermark(context.Context, *WatermarkRequest) (*WatermarkResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method AddWatermark not implemented")
+}
+func (UnimplementedFileServiceServer) GetFileList(context.Context, *GetFileListRequest) (*FileListResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetFileList not implemented")
+}
+func (UnimplementedFileServiceServer) mustEmbedUnimplementedFileServiceServer() {}
+func (UnimplementedFileServiceServer) testEmbeddedByValue() {}
+
+// UnsafeFileServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to FileServiceServer will
+// result in compilation errors.
+type UnsafeFileServiceServer interface {
+ mustEmbedUnimplementedFileServiceServer()
+}
+
+func RegisterFileServiceServer(s grpc.ServiceRegistrar, srv FileServiceServer) {
+ // If the following call panics, it indicates UnimplementedFileServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&FileService_ServiceDesc, srv)
+}
+
+func _FileService_Upload_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(FileServiceServer).Upload(&grpc.GenericServerStream[UploadRequest, UploadResponse]{ServerStream: stream})
+}
+
+// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
+type FileService_UploadServer = grpc.ClientStreamingServer[UploadRequest, UploadResponse]
+
+func _FileService_GetFile_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(GetFileRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(FileServiceServer).GetFile(m, &grpc.GenericServerStream[GetFileRequest, FileData]{ServerStream: stream})
+}
+
+// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
+type FileService_GetFileServer = grpc.ServerStreamingServer[FileData]
+
+func _FileService_DeleteFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteFileRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(FileServiceServer).DeleteFile(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: FileService_DeleteFile_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(FileServiceServer).DeleteFile(ctx, req.(*DeleteFileRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _FileService_AddWatermark_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(WatermarkRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(FileServiceServer).AddWatermark(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: FileService_AddWatermark_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(FileServiceServer).AddWatermark(ctx, req.(*WatermarkRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _FileService_GetFileList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetFileListRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(FileServiceServer).GetFileList(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: FileService_GetFileList_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(FileServiceServer).GetFileList(ctx, req.(*GetFileListRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// FileService_ServiceDesc is the grpc.ServiceDesc for FileService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var FileService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.FileService",
+ HandlerType: (*FileServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "DeleteFile",
+ Handler: _FileService_DeleteFile_Handler,
+ },
+ {
+ MethodName: "AddWatermark",
+ Handler: _FileService_AddWatermark_Handler,
+ },
+ {
+ MethodName: "GetFileList",
+ Handler: _FileService_GetFileList_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "Upload",
+ Handler: _FileService_Upload_Handler,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "GetFile",
+ Handler: _FileService_GetFile_Handler,
+ ServerStreams: true,
+ },
+ },
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ OrderService_CreateOrder_FullMethodName = "/cloudprint.OrderService/CreateOrder"
+ OrderService_GetOrder_FullMethodName = "/cloudprint.OrderService/GetOrder"
+ OrderService_GetOrderList_FullMethodName = "/cloudprint.OrderService/GetOrderList"
+ OrderService_UpdateOrderStatus_FullMethodName = "/cloudprint.OrderService/UpdateOrderStatus"
+ OrderService_CancelOrder_FullMethodName = "/cloudprint.OrderService/CancelOrder"
+)
+
+// OrderServiceClient is the client API for OrderService 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 OrderServiceClient interface {
+ CreateOrder(ctx context.Context, in *CreateOrderRequest, opts ...grpc.CallOption) (*CreateOrderResponse, error)
+ GetOrder(ctx context.Context, in *GetOrderRequest, opts ...grpc.CallOption) (*Order, error)
+ GetOrderList(ctx context.Context, in *GetOrderListRequest, opts ...grpc.CallOption) (*OrderListResponse, error)
+ UpdateOrderStatus(ctx context.Context, in *UpdateOrderStatusRequest, opts ...grpc.CallOption) (*Empty, error)
+ CancelOrder(ctx context.Context, in *CancelOrderRequest, opts ...grpc.CallOption) (*Empty, error)
+}
+
+type orderServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewOrderServiceClient(cc grpc.ClientConnInterface) OrderServiceClient {
+ return &orderServiceClient{cc}
+}
+
+func (c *orderServiceClient) CreateOrder(ctx context.Context, in *CreateOrderRequest, opts ...grpc.CallOption) (*CreateOrderResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(CreateOrderResponse)
+ err := c.cc.Invoke(ctx, OrderService_CreateOrder_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *orderServiceClient) GetOrder(ctx context.Context, in *GetOrderRequest, opts ...grpc.CallOption) (*Order, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Order)
+ err := c.cc.Invoke(ctx, OrderService_GetOrder_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *orderServiceClient) GetOrderList(ctx context.Context, in *GetOrderListRequest, opts ...grpc.CallOption) (*OrderListResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(OrderListResponse)
+ err := c.cc.Invoke(ctx, OrderService_GetOrderList_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *orderServiceClient) UpdateOrderStatus(ctx context.Context, in *UpdateOrderStatusRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, OrderService_UpdateOrderStatus_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *orderServiceClient) CancelOrder(ctx context.Context, in *CancelOrderRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, OrderService_CancelOrder_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// OrderServiceServer is the server API for OrderService service.
+// All implementations must embed UnimplementedOrderServiceServer
+// for forward compatibility.
+type OrderServiceServer interface {
+ CreateOrder(context.Context, *CreateOrderRequest) (*CreateOrderResponse, error)
+ GetOrder(context.Context, *GetOrderRequest) (*Order, error)
+ GetOrderList(context.Context, *GetOrderListRequest) (*OrderListResponse, error)
+ UpdateOrderStatus(context.Context, *UpdateOrderStatusRequest) (*Empty, error)
+ CancelOrder(context.Context, *CancelOrderRequest) (*Empty, error)
+ mustEmbedUnimplementedOrderServiceServer()
+}
+
+// UnimplementedOrderServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedOrderServiceServer struct{}
+
+func (UnimplementedOrderServiceServer) CreateOrder(context.Context, *CreateOrderRequest) (*CreateOrderResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method CreateOrder not implemented")
+}
+func (UnimplementedOrderServiceServer) GetOrder(context.Context, *GetOrderRequest) (*Order, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetOrder not implemented")
+}
+func (UnimplementedOrderServiceServer) GetOrderList(context.Context, *GetOrderListRequest) (*OrderListResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetOrderList not implemented")
+}
+func (UnimplementedOrderServiceServer) UpdateOrderStatus(context.Context, *UpdateOrderStatusRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method UpdateOrderStatus not implemented")
+}
+func (UnimplementedOrderServiceServer) CancelOrder(context.Context, *CancelOrderRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method CancelOrder not implemented")
+}
+func (UnimplementedOrderServiceServer) mustEmbedUnimplementedOrderServiceServer() {}
+func (UnimplementedOrderServiceServer) testEmbeddedByValue() {}
+
+// UnsafeOrderServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to OrderServiceServer will
+// result in compilation errors.
+type UnsafeOrderServiceServer interface {
+ mustEmbedUnimplementedOrderServiceServer()
+}
+
+func RegisterOrderServiceServer(s grpc.ServiceRegistrar, srv OrderServiceServer) {
+ // If the following call panics, it indicates UnimplementedOrderServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&OrderService_ServiceDesc, srv)
+}
+
+func _OrderService_CreateOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CreateOrderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OrderServiceServer).CreateOrder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OrderService_CreateOrder_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OrderServiceServer).CreateOrder(ctx, req.(*CreateOrderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OrderService_GetOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetOrderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OrderServiceServer).GetOrder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OrderService_GetOrder_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OrderServiceServer).GetOrder(ctx, req.(*GetOrderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OrderService_GetOrderList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetOrderListRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OrderServiceServer).GetOrderList(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OrderService_GetOrderList_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OrderServiceServer).GetOrderList(ctx, req.(*GetOrderListRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OrderService_UpdateOrderStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateOrderStatusRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OrderServiceServer).UpdateOrderStatus(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OrderService_UpdateOrderStatus_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OrderServiceServer).UpdateOrderStatus(ctx, req.(*UpdateOrderStatusRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _OrderService_CancelOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CancelOrderRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(OrderServiceServer).CancelOrder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: OrderService_CancelOrder_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(OrderServiceServer).CancelOrder(ctx, req.(*CancelOrderRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// OrderService_ServiceDesc is the grpc.ServiceDesc for OrderService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var OrderService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.OrderService",
+ HandlerType: (*OrderServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "CreateOrder",
+ Handler: _OrderService_CreateOrder_Handler,
+ },
+ {
+ MethodName: "GetOrder",
+ Handler: _OrderService_GetOrder_Handler,
+ },
+ {
+ MethodName: "GetOrderList",
+ Handler: _OrderService_GetOrderList_Handler,
+ },
+ {
+ MethodName: "UpdateOrderStatus",
+ Handler: _OrderService_UpdateOrderStatus_Handler,
+ },
+ {
+ MethodName: "CancelOrder",
+ Handler: _OrderService_CancelOrder_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ PrintService_GetPrinters_FullMethodName = "/cloudprint.PrintService/GetPrinters"
+ PrintService_GetPrinterStatus_FullMethodName = "/cloudprint.PrintService/GetPrinterStatus"
+ PrintService_RegisterPrinter_FullMethodName = "/cloudprint.PrintService/RegisterPrinter"
+ PrintService_PrinterHeartbeat_FullMethodName = "/cloudprint.PrintService/PrinterHeartbeat"
+ PrintService_SubmitPrintJob_FullMethodName = "/cloudprint.PrintService/SubmitPrintJob"
+ PrintService_CancelPrintJob_FullMethodName = "/cloudprint.PrintService/CancelPrintJob"
+ PrintService_SubscribeJobs_FullMethodName = "/cloudprint.PrintService/SubscribeJobs"
+ PrintService_ReportJobStatus_FullMethodName = "/cloudprint.PrintService/ReportJobStatus"
+)
+
+// PrintServiceClient is the client API for PrintService 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 PrintServiceClient interface {
+ GetPrinters(ctx context.Context, in *GetPrintersRequest, opts ...grpc.CallOption) (*PrinterListResponse, error)
+ GetPrinterStatus(ctx context.Context, in *GetPrinterStatusRequest, opts ...grpc.CallOption) (*PrinterStatusResponse, error)
+ RegisterPrinter(ctx context.Context, in *RegisterPrinterRequest, opts ...grpc.CallOption) (*RegisterPrinterResponse, error)
+ PrinterHeartbeat(ctx context.Context, in *PrinterHeartbeatRequest, opts ...grpc.CallOption) (*Empty, error)
+ SubmitPrintJob(ctx context.Context, in *SubmitPrintJobRequest, opts ...grpc.CallOption) (*SubmitPrintJobResponse, error)
+ CancelPrintJob(ctx context.Context, in *CancelPrintJobRequest, opts ...grpc.CallOption) (*Empty, error)
+ SubscribeJobs(ctx context.Context, in *SubscribeJobsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[PrintJob], error)
+ ReportJobStatus(ctx context.Context, in *ReportJobStatusRequest, opts ...grpc.CallOption) (*Empty, error)
+}
+
+type printServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewPrintServiceClient(cc grpc.ClientConnInterface) PrintServiceClient {
+ return &printServiceClient{cc}
+}
+
+func (c *printServiceClient) GetPrinters(ctx context.Context, in *GetPrintersRequest, opts ...grpc.CallOption) (*PrinterListResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PrinterListResponse)
+ err := c.cc.Invoke(ctx, PrintService_GetPrinters_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *printServiceClient) GetPrinterStatus(ctx context.Context, in *GetPrinterStatusRequest, opts ...grpc.CallOption) (*PrinterStatusResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PrinterStatusResponse)
+ err := c.cc.Invoke(ctx, PrintService_GetPrinterStatus_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *printServiceClient) RegisterPrinter(ctx context.Context, in *RegisterPrinterRequest, opts ...grpc.CallOption) (*RegisterPrinterResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(RegisterPrinterResponse)
+ err := c.cc.Invoke(ctx, PrintService_RegisterPrinter_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *printServiceClient) PrinterHeartbeat(ctx context.Context, in *PrinterHeartbeatRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, PrintService_PrinterHeartbeat_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *printServiceClient) SubmitPrintJob(ctx context.Context, in *SubmitPrintJobRequest, opts ...grpc.CallOption) (*SubmitPrintJobResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(SubmitPrintJobResponse)
+ err := c.cc.Invoke(ctx, PrintService_SubmitPrintJob_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *printServiceClient) CancelPrintJob(ctx context.Context, in *CancelPrintJobRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, PrintService_CancelPrintJob_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *printServiceClient) SubscribeJobs(ctx context.Context, in *SubscribeJobsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[PrintJob], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &PrintService_ServiceDesc.Streams[0], PrintService_SubscribeJobs_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[SubscribeJobsRequest, PrintJob]{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 PrintService_SubscribeJobsClient = grpc.ServerStreamingClient[PrintJob]
+
+func (c *printServiceClient) ReportJobStatus(ctx context.Context, in *ReportJobStatusRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, PrintService_ReportJobStatus_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// PrintServiceServer is the server API for PrintService service.
+// All implementations must embed UnimplementedPrintServiceServer
+// for forward compatibility.
+type PrintServiceServer interface {
+ GetPrinters(context.Context, *GetPrintersRequest) (*PrinterListResponse, error)
+ GetPrinterStatus(context.Context, *GetPrinterStatusRequest) (*PrinterStatusResponse, error)
+ RegisterPrinter(context.Context, *RegisterPrinterRequest) (*RegisterPrinterResponse, error)
+ PrinterHeartbeat(context.Context, *PrinterHeartbeatRequest) (*Empty, error)
+ SubmitPrintJob(context.Context, *SubmitPrintJobRequest) (*SubmitPrintJobResponse, error)
+ CancelPrintJob(context.Context, *CancelPrintJobRequest) (*Empty, error)
+ SubscribeJobs(*SubscribeJobsRequest, grpc.ServerStreamingServer[PrintJob]) error
+ ReportJobStatus(context.Context, *ReportJobStatusRequest) (*Empty, error)
+ mustEmbedUnimplementedPrintServiceServer()
+}
+
+// UnimplementedPrintServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedPrintServiceServer struct{}
+
+func (UnimplementedPrintServiceServer) GetPrinters(context.Context, *GetPrintersRequest) (*PrinterListResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetPrinters not implemented")
+}
+func (UnimplementedPrintServiceServer) GetPrinterStatus(context.Context, *GetPrinterStatusRequest) (*PrinterStatusResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetPrinterStatus not implemented")
+}
+func (UnimplementedPrintServiceServer) RegisterPrinter(context.Context, *RegisterPrinterRequest) (*RegisterPrinterResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method RegisterPrinter not implemented")
+}
+func (UnimplementedPrintServiceServer) PrinterHeartbeat(context.Context, *PrinterHeartbeatRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method PrinterHeartbeat not implemented")
+}
+func (UnimplementedPrintServiceServer) SubmitPrintJob(context.Context, *SubmitPrintJobRequest) (*SubmitPrintJobResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method SubmitPrintJob not implemented")
+}
+func (UnimplementedPrintServiceServer) CancelPrintJob(context.Context, *CancelPrintJobRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method CancelPrintJob not implemented")
+}
+func (UnimplementedPrintServiceServer) SubscribeJobs(*SubscribeJobsRequest, grpc.ServerStreamingServer[PrintJob]) error {
+ return status.Error(codes.Unimplemented, "method SubscribeJobs not implemented")
+}
+func (UnimplementedPrintServiceServer) ReportJobStatus(context.Context, *ReportJobStatusRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method ReportJobStatus not implemented")
+}
+func (UnimplementedPrintServiceServer) mustEmbedUnimplementedPrintServiceServer() {}
+func (UnimplementedPrintServiceServer) testEmbeddedByValue() {}
+
+// UnsafePrintServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to PrintServiceServer will
+// result in compilation errors.
+type UnsafePrintServiceServer interface {
+ mustEmbedUnimplementedPrintServiceServer()
+}
+
+func RegisterPrintServiceServer(s grpc.ServiceRegistrar, srv PrintServiceServer) {
+ // If the following call panics, it indicates UnimplementedPrintServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&PrintService_ServiceDesc, srv)
+}
+
+func _PrintService_GetPrinters_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetPrintersRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).GetPrinters(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_GetPrinters_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).GetPrinters(ctx, req.(*GetPrintersRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PrintService_GetPrinterStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetPrinterStatusRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).GetPrinterStatus(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_GetPrinterStatus_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).GetPrinterStatus(ctx, req.(*GetPrinterStatusRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PrintService_RegisterPrinter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(RegisterPrinterRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).RegisterPrinter(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_RegisterPrinter_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).RegisterPrinter(ctx, req.(*RegisterPrinterRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PrintService_PrinterHeartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PrinterHeartbeatRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).PrinterHeartbeat(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_PrinterHeartbeat_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).PrinterHeartbeat(ctx, req.(*PrinterHeartbeatRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PrintService_SubmitPrintJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(SubmitPrintJobRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).SubmitPrintJob(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_SubmitPrintJob_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).SubmitPrintJob(ctx, req.(*SubmitPrintJobRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PrintService_CancelPrintJob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CancelPrintJobRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).CancelPrintJob(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_CancelPrintJob_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).CancelPrintJob(ctx, req.(*CancelPrintJobRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PrintService_SubscribeJobs_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(SubscribeJobsRequest)
+ if err := stream.RecvMsg(m); err != nil {
+ return err
+ }
+ return srv.(PrintServiceServer).SubscribeJobs(m, &grpc.GenericServerStream[SubscribeJobsRequest, PrintJob]{ServerStream: stream})
+}
+
+// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
+type PrintService_SubscribeJobsServer = grpc.ServerStreamingServer[PrintJob]
+
+func _PrintService_ReportJobStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(ReportJobStatusRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PrintServiceServer).ReportJobStatus(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PrintService_ReportJobStatus_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PrintServiceServer).ReportJobStatus(ctx, req.(*ReportJobStatusRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// PrintService_ServiceDesc is the grpc.ServiceDesc for PrintService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var PrintService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.PrintService",
+ HandlerType: (*PrintServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "GetPrinters",
+ Handler: _PrintService_GetPrinters_Handler,
+ },
+ {
+ MethodName: "GetPrinterStatus",
+ Handler: _PrintService_GetPrinterStatus_Handler,
+ },
+ {
+ MethodName: "RegisterPrinter",
+ Handler: _PrintService_RegisterPrinter_Handler,
+ },
+ {
+ MethodName: "PrinterHeartbeat",
+ Handler: _PrintService_PrinterHeartbeat_Handler,
+ },
+ {
+ MethodName: "SubmitPrintJob",
+ Handler: _PrintService_SubmitPrintJob_Handler,
+ },
+ {
+ MethodName: "CancelPrintJob",
+ Handler: _PrintService_CancelPrintJob_Handler,
+ },
+ {
+ MethodName: "ReportJobStatus",
+ Handler: _PrintService_ReportJobStatus_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "SubscribeJobs",
+ Handler: _PrintService_SubscribeJobs_Handler,
+ ServerStreams: true,
+ },
+ },
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ LibraryService_GetCategories_FullMethodName = "/cloudprint.LibraryService/GetCategories"
+ LibraryService_GetFiles_FullMethodName = "/cloudprint.LibraryService/GetFiles"
+ LibraryService_UploadFile_FullMethodName = "/cloudprint.LibraryService/UploadFile"
+ LibraryService_DeleteFile_FullMethodName = "/cloudprint.LibraryService/DeleteFile"
+)
+
+// LibraryServiceClient is the client API for LibraryService 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 LibraryServiceClient interface {
+ GetCategories(ctx context.Context, in *GetCategoriesRequest, opts ...grpc.CallOption) (*CategoryListResponse, error)
+ GetFiles(ctx context.Context, in *GetLibraryFilesRequest, opts ...grpc.CallOption) (*LibraryFileListResponse, error)
+ UploadFile(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[UploadLibraryFileRequest, UploadLibraryFileResponse], error)
+ DeleteFile(ctx context.Context, in *DeleteLibraryFileRequest, opts ...grpc.CallOption) (*Empty, error)
+}
+
+type libraryServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewLibraryServiceClient(cc grpc.ClientConnInterface) LibraryServiceClient {
+ return &libraryServiceClient{cc}
+}
+
+func (c *libraryServiceClient) GetCategories(ctx context.Context, in *GetCategoriesRequest, opts ...grpc.CallOption) (*CategoryListResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(CategoryListResponse)
+ err := c.cc.Invoke(ctx, LibraryService_GetCategories_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *libraryServiceClient) GetFiles(ctx context.Context, in *GetLibraryFilesRequest, opts ...grpc.CallOption) (*LibraryFileListResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(LibraryFileListResponse)
+ err := c.cc.Invoke(ctx, LibraryService_GetFiles_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *libraryServiceClient) UploadFile(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[UploadLibraryFileRequest, UploadLibraryFileResponse], error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ stream, err := c.cc.NewStream(ctx, &LibraryService_ServiceDesc.Streams[0], LibraryService_UploadFile_FullMethodName, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ x := &grpc.GenericClientStream[UploadLibraryFileRequest, UploadLibraryFileResponse]{ClientStream: stream}
+ return x, nil
+}
+
+// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
+type LibraryService_UploadFileClient = grpc.ClientStreamingClient[UploadLibraryFileRequest, UploadLibraryFileResponse]
+
+func (c *libraryServiceClient) DeleteFile(ctx context.Context, in *DeleteLibraryFileRequest, opts ...grpc.CallOption) (*Empty, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Empty)
+ err := c.cc.Invoke(ctx, LibraryService_DeleteFile_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// LibraryServiceServer is the server API for LibraryService service.
+// All implementations must embed UnimplementedLibraryServiceServer
+// for forward compatibility.
+type LibraryServiceServer interface {
+ GetCategories(context.Context, *GetCategoriesRequest) (*CategoryListResponse, error)
+ GetFiles(context.Context, *GetLibraryFilesRequest) (*LibraryFileListResponse, error)
+ UploadFile(grpc.ClientStreamingServer[UploadLibraryFileRequest, UploadLibraryFileResponse]) error
+ DeleteFile(context.Context, *DeleteLibraryFileRequest) (*Empty, error)
+ mustEmbedUnimplementedLibraryServiceServer()
+}
+
+// UnimplementedLibraryServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedLibraryServiceServer struct{}
+
+func (UnimplementedLibraryServiceServer) GetCategories(context.Context, *GetCategoriesRequest) (*CategoryListResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetCategories not implemented")
+}
+func (UnimplementedLibraryServiceServer) GetFiles(context.Context, *GetLibraryFilesRequest) (*LibraryFileListResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetFiles not implemented")
+}
+func (UnimplementedLibraryServiceServer) UploadFile(grpc.ClientStreamingServer[UploadLibraryFileRequest, UploadLibraryFileResponse]) error {
+ return status.Error(codes.Unimplemented, "method UploadFile not implemented")
+}
+func (UnimplementedLibraryServiceServer) DeleteFile(context.Context, *DeleteLibraryFileRequest) (*Empty, error) {
+ return nil, status.Error(codes.Unimplemented, "method DeleteFile not implemented")
+}
+func (UnimplementedLibraryServiceServer) mustEmbedUnimplementedLibraryServiceServer() {}
+func (UnimplementedLibraryServiceServer) testEmbeddedByValue() {}
+
+// UnsafeLibraryServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to LibraryServiceServer will
+// result in compilation errors.
+type UnsafeLibraryServiceServer interface {
+ mustEmbedUnimplementedLibraryServiceServer()
+}
+
+func RegisterLibraryServiceServer(s grpc.ServiceRegistrar, srv LibraryServiceServer) {
+ // If the following call panics, it indicates UnimplementedLibraryServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&LibraryService_ServiceDesc, srv)
+}
+
+func _LibraryService_GetCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetCategoriesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(LibraryServiceServer).GetCategories(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: LibraryService_GetCategories_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(LibraryServiceServer).GetCategories(ctx, req.(*GetCategoriesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _LibraryService_GetFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetLibraryFilesRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(LibraryServiceServer).GetFiles(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: LibraryService_GetFiles_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(LibraryServiceServer).GetFiles(ctx, req.(*GetLibraryFilesRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _LibraryService_UploadFile_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(LibraryServiceServer).UploadFile(&grpc.GenericServerStream[UploadLibraryFileRequest, UploadLibraryFileResponse]{ServerStream: stream})
+}
+
+// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
+type LibraryService_UploadFileServer = grpc.ClientStreamingServer[UploadLibraryFileRequest, UploadLibraryFileResponse]
+
+func _LibraryService_DeleteFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteLibraryFileRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(LibraryServiceServer).DeleteFile(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: LibraryService_DeleteFile_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(LibraryServiceServer).DeleteFile(ctx, req.(*DeleteLibraryFileRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// LibraryService_ServiceDesc is the grpc.ServiceDesc for LibraryService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var LibraryService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.LibraryService",
+ HandlerType: (*LibraryServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "GetCategories",
+ Handler: _LibraryService_GetCategories_Handler,
+ },
+ {
+ MethodName: "GetFiles",
+ Handler: _LibraryService_GetFiles_Handler,
+ },
+ {
+ MethodName: "DeleteFile",
+ Handler: _LibraryService_DeleteFile_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "UploadFile",
+ Handler: _LibraryService_UploadFile_Handler,
+ ClientStreams: true,
+ },
+ },
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ PriceService_GetPriceList_FullMethodName = "/cloudprint.PriceService/GetPriceList"
+ PriceService_CreatePriceItem_FullMethodName = "/cloudprint.PriceService/CreatePriceItem"
+ PriceService_UpdatePriceItem_FullMethodName = "/cloudprint.PriceService/UpdatePriceItem"
+)
+
+// PriceServiceClient is the client API for PriceService 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 PriceServiceClient interface {
+ GetPriceList(ctx context.Context, in *GetPriceListRequest, opts ...grpc.CallOption) (*PriceListResponse, error)
+ CreatePriceItem(ctx context.Context, in *CreatePriceItemRequest, opts ...grpc.CallOption) (*PriceItem, error)
+ UpdatePriceItem(ctx context.Context, in *UpdatePriceItemRequest, opts ...grpc.CallOption) (*PriceItem, error)
+}
+
+type priceServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewPriceServiceClient(cc grpc.ClientConnInterface) PriceServiceClient {
+ return &priceServiceClient{cc}
+}
+
+func (c *priceServiceClient) GetPriceList(ctx context.Context, in *GetPriceListRequest, opts ...grpc.CallOption) (*PriceListResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PriceListResponse)
+ err := c.cc.Invoke(ctx, PriceService_GetPriceList_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *priceServiceClient) CreatePriceItem(ctx context.Context, in *CreatePriceItemRequest, opts ...grpc.CallOption) (*PriceItem, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PriceItem)
+ err := c.cc.Invoke(ctx, PriceService_CreatePriceItem_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *priceServiceClient) UpdatePriceItem(ctx context.Context, in *UpdatePriceItemRequest, opts ...grpc.CallOption) (*PriceItem, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PriceItem)
+ err := c.cc.Invoke(ctx, PriceService_UpdatePriceItem_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// PriceServiceServer is the server API for PriceService service.
+// All implementations must embed UnimplementedPriceServiceServer
+// for forward compatibility.
+type PriceServiceServer interface {
+ GetPriceList(context.Context, *GetPriceListRequest) (*PriceListResponse, error)
+ CreatePriceItem(context.Context, *CreatePriceItemRequest) (*PriceItem, error)
+ UpdatePriceItem(context.Context, *UpdatePriceItemRequest) (*PriceItem, error)
+ mustEmbedUnimplementedPriceServiceServer()
+}
+
+// UnimplementedPriceServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedPriceServiceServer struct{}
+
+func (UnimplementedPriceServiceServer) GetPriceList(context.Context, *GetPriceListRequest) (*PriceListResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetPriceList not implemented")
+}
+func (UnimplementedPriceServiceServer) CreatePriceItem(context.Context, *CreatePriceItemRequest) (*PriceItem, error) {
+ return nil, status.Error(codes.Unimplemented, "method CreatePriceItem not implemented")
+}
+func (UnimplementedPriceServiceServer) UpdatePriceItem(context.Context, *UpdatePriceItemRequest) (*PriceItem, error) {
+ return nil, status.Error(codes.Unimplemented, "method UpdatePriceItem not implemented")
+}
+func (UnimplementedPriceServiceServer) mustEmbedUnimplementedPriceServiceServer() {}
+func (UnimplementedPriceServiceServer) testEmbeddedByValue() {}
+
+// UnsafePriceServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to PriceServiceServer will
+// result in compilation errors.
+type UnsafePriceServiceServer interface {
+ mustEmbedUnimplementedPriceServiceServer()
+}
+
+func RegisterPriceServiceServer(s grpc.ServiceRegistrar, srv PriceServiceServer) {
+ // If the following call panics, it indicates UnimplementedPriceServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&PriceService_ServiceDesc, srv)
+}
+
+func _PriceService_GetPriceList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetPriceListRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PriceServiceServer).GetPriceList(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PriceService_GetPriceList_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PriceServiceServer).GetPriceList(ctx, req.(*GetPriceListRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PriceService_CreatePriceItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(CreatePriceItemRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PriceServiceServer).CreatePriceItem(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PriceService_CreatePriceItem_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PriceServiceServer).CreatePriceItem(ctx, req.(*CreatePriceItemRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PriceService_UpdatePriceItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdatePriceItemRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PriceServiceServer).UpdatePriceItem(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PriceService_UpdatePriceItem_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PriceServiceServer).UpdatePriceItem(ctx, req.(*UpdatePriceItemRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// PriceService_ServiceDesc is the grpc.ServiceDesc for PriceService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var PriceService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.PriceService",
+ HandlerType: (*PriceServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "GetPriceList",
+ Handler: _PriceService_GetPriceList_Handler,
+ },
+ {
+ MethodName: "CreatePriceItem",
+ Handler: _PriceService_CreatePriceItem_Handler,
+ },
+ {
+ MethodName: "UpdatePriceItem",
+ Handler: _PriceService_UpdatePriceItem_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ PayService_CreateWxPayOrder_FullMethodName = "/cloudprint.PayService/CreateWxPayOrder"
+ PayService_QueryPayStatus_FullMethodName = "/cloudprint.PayService/QueryPayStatus"
+ PayService_HandlePayCallback_FullMethodName = "/cloudprint.PayService/HandlePayCallback"
+ PayService_PayByBalance_FullMethodName = "/cloudprint.PayService/PayByBalance"
+)
+
+// PayServiceClient is the client API for PayService 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 PayServiceClient interface {
+ CreateWxPayOrder(ctx context.Context, in *WxPayRequest, opts ...grpc.CallOption) (*WxPayResponse, error)
+ QueryPayStatus(ctx context.Context, in *QueryPayStatusRequest, opts ...grpc.CallOption) (*PayStatusResponse, error)
+ HandlePayCallback(ctx context.Context, in *PayCallbackRequest, opts ...grpc.CallOption) (*PayCallbackResponse, error)
+ PayByBalance(ctx context.Context, in *PayByBalanceRequest, opts ...grpc.CallOption) (*StatusResponse, error)
+}
+
+type payServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewPayServiceClient(cc grpc.ClientConnInterface) PayServiceClient {
+ return &payServiceClient{cc}
+}
+
+func (c *payServiceClient) CreateWxPayOrder(ctx context.Context, in *WxPayRequest, opts ...grpc.CallOption) (*WxPayResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(WxPayResponse)
+ err := c.cc.Invoke(ctx, PayService_CreateWxPayOrder_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *payServiceClient) QueryPayStatus(ctx context.Context, in *QueryPayStatusRequest, opts ...grpc.CallOption) (*PayStatusResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PayStatusResponse)
+ err := c.cc.Invoke(ctx, PayService_QueryPayStatus_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *payServiceClient) HandlePayCallback(ctx context.Context, in *PayCallbackRequest, opts ...grpc.CallOption) (*PayCallbackResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(PayCallbackResponse)
+ err := c.cc.Invoke(ctx, PayService_HandlePayCallback_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *payServiceClient) PayByBalance(ctx context.Context, in *PayByBalanceRequest, opts ...grpc.CallOption) (*StatusResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(StatusResponse)
+ err := c.cc.Invoke(ctx, PayService_PayByBalance_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// PayServiceServer is the server API for PayService service.
+// All implementations must embed UnimplementedPayServiceServer
+// for forward compatibility.
+type PayServiceServer interface {
+ CreateWxPayOrder(context.Context, *WxPayRequest) (*WxPayResponse, error)
+ QueryPayStatus(context.Context, *QueryPayStatusRequest) (*PayStatusResponse, error)
+ HandlePayCallback(context.Context, *PayCallbackRequest) (*PayCallbackResponse, error)
+ PayByBalance(context.Context, *PayByBalanceRequest) (*StatusResponse, error)
+ mustEmbedUnimplementedPayServiceServer()
+}
+
+// UnimplementedPayServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedPayServiceServer struct{}
+
+func (UnimplementedPayServiceServer) CreateWxPayOrder(context.Context, *WxPayRequest) (*WxPayResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method CreateWxPayOrder not implemented")
+}
+func (UnimplementedPayServiceServer) QueryPayStatus(context.Context, *QueryPayStatusRequest) (*PayStatusResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method QueryPayStatus not implemented")
+}
+func (UnimplementedPayServiceServer) HandlePayCallback(context.Context, *PayCallbackRequest) (*PayCallbackResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method HandlePayCallback not implemented")
+}
+func (UnimplementedPayServiceServer) PayByBalance(context.Context, *PayByBalanceRequest) (*StatusResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method PayByBalance not implemented")
+}
+func (UnimplementedPayServiceServer) mustEmbedUnimplementedPayServiceServer() {}
+func (UnimplementedPayServiceServer) testEmbeddedByValue() {}
+
+// UnsafePayServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to PayServiceServer will
+// result in compilation errors.
+type UnsafePayServiceServer interface {
+ mustEmbedUnimplementedPayServiceServer()
+}
+
+func RegisterPayServiceServer(s grpc.ServiceRegistrar, srv PayServiceServer) {
+ // If the following call panics, it indicates UnimplementedPayServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&PayService_ServiceDesc, srv)
+}
+
+func _PayService_CreateWxPayOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(WxPayRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PayServiceServer).CreateWxPayOrder(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PayService_CreateWxPayOrder_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PayServiceServer).CreateWxPayOrder(ctx, req.(*WxPayRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PayService_QueryPayStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(QueryPayStatusRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PayServiceServer).QueryPayStatus(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PayService_QueryPayStatus_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PayServiceServer).QueryPayStatus(ctx, req.(*QueryPayStatusRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PayService_HandlePayCallback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PayCallbackRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PayServiceServer).HandlePayCallback(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PayService_HandlePayCallback_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PayServiceServer).HandlePayCallback(ctx, req.(*PayCallbackRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _PayService_PayByBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(PayByBalanceRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(PayServiceServer).PayByBalance(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: PayService_PayByBalance_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(PayServiceServer).PayByBalance(ctx, req.(*PayByBalanceRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// PayService_ServiceDesc is the grpc.ServiceDesc for PayService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var PayService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.PayService",
+ HandlerType: (*PayServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "CreateWxPayOrder",
+ Handler: _PayService_CreateWxPayOrder_Handler,
+ },
+ {
+ MethodName: "QueryPayStatus",
+ Handler: _PayService_QueryPayStatus_Handler,
+ },
+ {
+ MethodName: "HandlePayCallback",
+ Handler: _PayService_HandlePayCallback_Handler,
+ },
+ {
+ MethodName: "PayByBalance",
+ Handler: _PayService_PayByBalance_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "cloudprint.proto",
+}
+
+const (
+ AdminService_Login_FullMethodName = "/cloudprint.AdminService/Login"
+ AdminService_GetStatistics_FullMethodName = "/cloudprint.AdminService/GetStatistics"
+)
+
+// AdminServiceClient is the client API for AdminService 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 AdminServiceClient interface {
+ Login(ctx context.Context, in *AdminLoginRequest, opts ...grpc.CallOption) (*AdminLoginResponse, error)
+ GetStatistics(ctx context.Context, in *GetStatisticsRequest, opts ...grpc.CallOption) (*Statistics, error)
+}
+
+type adminServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewAdminServiceClient(cc grpc.ClientConnInterface) AdminServiceClient {
+ return &adminServiceClient{cc}
+}
+
+func (c *adminServiceClient) Login(ctx context.Context, in *AdminLoginRequest, opts ...grpc.CallOption) (*AdminLoginResponse, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(AdminLoginResponse)
+ err := c.cc.Invoke(ctx, AdminService_Login_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *adminServiceClient) GetStatistics(ctx context.Context, in *GetStatisticsRequest, opts ...grpc.CallOption) (*Statistics, error) {
+ cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
+ out := new(Statistics)
+ err := c.cc.Invoke(ctx, AdminService_GetStatistics_FullMethodName, in, out, cOpts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// AdminServiceServer is the server API for AdminService service.
+// All implementations must embed UnimplementedAdminServiceServer
+// for forward compatibility.
+type AdminServiceServer interface {
+ Login(context.Context, *AdminLoginRequest) (*AdminLoginResponse, error)
+ GetStatistics(context.Context, *GetStatisticsRequest) (*Statistics, error)
+ mustEmbedUnimplementedAdminServiceServer()
+}
+
+// UnimplementedAdminServiceServer must be embedded to have
+// forward compatible implementations.
+//
+// NOTE: this should be embedded by value instead of pointer to avoid a nil
+// pointer dereference when methods are called.
+type UnimplementedAdminServiceServer struct{}
+
+func (UnimplementedAdminServiceServer) Login(context.Context, *AdminLoginRequest) (*AdminLoginResponse, error) {
+ return nil, status.Error(codes.Unimplemented, "method Login not implemented")
+}
+func (UnimplementedAdminServiceServer) GetStatistics(context.Context, *GetStatisticsRequest) (*Statistics, error) {
+ return nil, status.Error(codes.Unimplemented, "method GetStatistics not implemented")
+}
+func (UnimplementedAdminServiceServer) mustEmbedUnimplementedAdminServiceServer() {}
+func (UnimplementedAdminServiceServer) testEmbeddedByValue() {}
+
+// UnsafeAdminServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to AdminServiceServer will
+// result in compilation errors.
+type UnsafeAdminServiceServer interface {
+ mustEmbedUnimplementedAdminServiceServer()
+}
+
+func RegisterAdminServiceServer(s grpc.ServiceRegistrar, srv AdminServiceServer) {
+ // If the following call panics, it indicates UnimplementedAdminServiceServer was
+ // embedded by pointer and is nil. This will cause panics if an
+ // unimplemented method is ever invoked, so we test this at initialization
+ // time to prevent it from happening at runtime later due to I/O.
+ if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
+ t.testEmbeddedByValue()
+ }
+ s.RegisterService(&AdminService_ServiceDesc, srv)
+}
+
+func _AdminService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(AdminLoginRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AdminServiceServer).Login(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: AdminService_Login_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AdminServiceServer).Login(ctx, req.(*AdminLoginRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _AdminService_GetStatistics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetStatisticsRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(AdminServiceServer).GetStatistics(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: AdminService_GetStatistics_FullMethodName,
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(AdminServiceServer).GetStatistics(ctx, req.(*GetStatisticsRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// AdminService_ServiceDesc is the grpc.ServiceDesc for AdminService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var AdminService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "cloudprint.AdminService",
+ HandlerType: (*AdminServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Login",
+ Handler: _AdminService_Login_Handler,
+ },
+ {
+ MethodName: "GetStatistics",
+ Handler: _AdminService_GetStatistics_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "cloudprint.proto",
+}
diff --git a/cloudprint-backend/scripts/db.sql b/cloudprint-backend/scripts/db.sql
new file mode 100644
index 0000000..13c24db
--- /dev/null
+++ b/cloudprint-backend/scripts/db.sql
@@ -0,0 +1,182 @@
+-- 云印享 - 付费打印服务系统数据库初始化脚本
+-- 数据库: cloudprint
+
+CREATE DATABASE IF NOT EXISTS `cloudprint` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+USE `cloudprint`;
+
+-- 用户表
+CREATE TABLE IF NOT EXISTS `user` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `openid` VARCHAR(64) UNIQUE NOT NULL COMMENT '微信OpenID',
+ `nickname` VARCHAR(128) DEFAULT '' COMMENT '昵称',
+ `avatar` VARCHAR(512) DEFAULT '' COMMENT '头像URL',
+ `balance` DECIMAL(10,2) DEFAULT 0.00 COMMENT '余额',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ INDEX `idx_openid` (`openid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
+
+-- 管理员表
+CREATE TABLE IF NOT EXISTS `admin` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `username` VARCHAR(64) UNIQUE NOT NULL COMMENT '用户名',
+ `password_hash` VARCHAR(256) NOT NULL COMMENT '密码哈希',
+ `nickname` VARCHAR(128) DEFAULT '' COMMENT '昵称',
+ `role` TINYINT DEFAULT 1 COMMENT '1:普通管理员 2:超级管理员',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX `idx_username` (`username`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员表';
+
+-- 打印机表
+CREATE TABLE IF NOT EXISTS `printer` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `name` VARCHAR(128) UNIQUE NOT NULL COMMENT '系统打印机名',
+ `display_name` VARCHAR(128) NOT NULL COMMENT '显示名称',
+ `api_key` VARCHAR(64) UNIQUE NOT NULL COMMENT '客户端认证Key',
+ `is_active` TINYINT DEFAULT 1 COMMENT '是否启用',
+ `status` TINYINT DEFAULT 0 COMMENT '0:空闲 1:打印中 2:离线',
+ `last_heartbeat` DATETIME DEFAULT NULL COMMENT '最后心跳时间',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX `idx_name` (`name`),
+ INDEX `idx_api_key` (`api_key`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='打印机表';
+
+-- 订单表
+CREATE TABLE IF NOT EXISTS `order` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `order_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '订单号',
+ `user_id` INT NOT NULL COMMENT '用户ID',
+ `status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:已支付 2:打印中 3:已完成 4:已取消',
+ `total_amount` DECIMAL(10,2) NOT NULL COMMENT '总金额',
+ `remark` VARCHAR(512) DEFAULT '' COMMENT '备注',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `paid_at` DATETIME DEFAULT NULL COMMENT '支付时间',
+ INDEX `idx_order_no` (`order_no`),
+ INDEX `idx_user_id` (`user_id`),
+ INDEX `idx_status` (`status`),
+ INDEX `idx_created_at` (`created_at`),
+ FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
+
+-- 订单明细表
+CREATE TABLE IF NOT EXISTS `order_item` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `order_id` INT NOT NULL COMMENT '订单ID',
+ `file_id` INT NOT NULL COMMENT '文件ID',
+ `printer_id` INT DEFAULT NULL COMMENT '打印机ID',
+ `copies` INT DEFAULT 1 COMMENT '份数',
+ `color` TINYINT DEFAULT 0 COMMENT '是否彩色 0:黑白 1:彩色',
+ `duplex` TINYINT DEFAULT 0 COMMENT '是否双面 0:单面 1:双面',
+ `page_range` VARCHAR(64) DEFAULT 'all' COMMENT '页面范围',
+ `price` DECIMAL(10,2) NOT NULL COMMENT '价格',
+ INDEX `idx_order_id` (`order_id`),
+ INDEX `idx_file_id` (`file_id`),
+ FOREIGN KEY (`order_id`) REFERENCES `order`(`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`file_id`) REFERENCES `file`(`id`) ON DELETE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单明细表';
+
+-- 文件表
+CREATE TABLE IF NOT EXISTS `file` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `file_name` VARCHAR(256) NOT NULL COMMENT '文件名',
+ `file_path` VARCHAR(512) NOT NULL COMMENT '文件路径',
+ `file_type` VARCHAR(32) NOT NULL COMMENT '文件类型',
+ `file_size` BIGINT NOT NULL COMMENT '文件大小(字节)',
+ `uploader_type` VARCHAR(16) NOT NULL COMMENT '上传者类型: user/admin/system',
+ `uploader_id` INT NOT NULL COMMENT '上传者ID',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX `idx_uploader` (`uploader_type`, `uploader_id`),
+ INDEX `idx_file_type` (`file_type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表';
+
+-- 文库分类表
+CREATE TABLE IF NOT EXISTS `library_category` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `name` VARCHAR(128) NOT NULL COMMENT '分类名称',
+ `icon` VARCHAR(128) DEFAULT '' COMMENT '图标',
+ `sort_order` INT DEFAULT 0 COMMENT '排序',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文库分类表';
+
+-- 文库文件表
+CREATE TABLE IF NOT EXISTS `library_file` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `category_id` INT NOT NULL COMMENT '分类ID',
+ `file_id` INT NOT NULL COMMENT '文件ID',
+ `title` VARCHAR(256) NOT NULL COMMENT '标题',
+ `description` VARCHAR(512) DEFAULT '' COMMENT '描述',
+ `page_count` INT DEFAULT 0 COMMENT '页数',
+ `download_count` INT DEFAULT 0 COMMENT '下载次数',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX `idx_category_id` (`category_id`),
+ INDEX `idx_file_id` (`file_id`),
+ FOREIGN KEY (`category_id`) REFERENCES `library_category`(`id`) ON DELETE CASCADE,
+ FOREIGN KEY (`file_id`) REFERENCES `file`(`id`) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文库文件表';
+
+-- 打印任务表
+CREATE TABLE IF NOT EXISTS `print_job` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `job_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '任务号',
+ `printer_id` INT NOT NULL COMMENT '打印机ID',
+ `order_item_id` INT NOT NULL COMMENT '订单明细ID',
+ `status` VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/printing/completed/failed/cancelled',
+ `progress` INT DEFAULT 0 COMMENT '进度(0-100)',
+ `error_msg` VARCHAR(512) DEFAULT '' COMMENT '错误信息',
+ `started_at` DATETIME DEFAULT NULL COMMENT '开始时间',
+ `completed_at` DATETIME DEFAULT NULL COMMENT '完成时间',
+ INDEX `idx_job_no` (`job_no`),
+ INDEX `idx_printer_id` (`printer_id`),
+ INDEX `idx_status` (`status`),
+ FOREIGN KEY (`printer_id`) REFERENCES `printer`(`id`) ON DELETE RESTRICT,
+ FOREIGN KEY (`order_item_id`) REFERENCES `order_item`(`id`) ON DELETE RESTRICT
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='打印任务表';
+
+-- 价目表
+CREATE TABLE IF NOT EXISTS `price_list` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `name` VARCHAR(128) NOT NULL COMMENT '项目名称',
+ `type` VARCHAR(32) NOT NULL COMMENT '纸张类型: A4/A3/照片纸',
+ `price` DECIMAL(10,2) NOT NULL COMMENT '单价',
+ `unit` VARCHAR(16) NOT NULL COMMENT '单位: 页/张/份',
+ `color_enabled` TINYINT DEFAULT 1 COMMENT '是否支持彩色',
+ `is_active` TINYINT DEFAULT 1 COMMENT '是否启用',
+ `sort_order` INT DEFAULT 0 COMMENT '排序',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX `idx_type` (`type`),
+ INDEX `idx_is_active` (`is_active`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='价目表';
+
+-- 支付记录表
+CREATE TABLE IF NOT EXISTS `payment` (
+ `id` INT PRIMARY KEY AUTO_INCREMENT,
+ `order_no` VARCHAR(32) UNIQUE NOT NULL COMMENT '订单号',
+ `pay_type` VARCHAR(16) DEFAULT 'wechat' COMMENT '支付类型: wechat/balance',
+ `pay_status` TINYINT DEFAULT 0 COMMENT '0:待支付 1:支付中 2:成功 3:失败',
+ `transaction_id` VARCHAR(64) DEFAULT '' COMMENT '微信交易号',
+ `paid_at` DATETIME DEFAULT NULL COMMENT '支付时间',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX `idx_order_no` (`order_no`),
+ INDEX `idx_pay_status` (`pay_status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='支付记录表';
+
+-- 初始化管理员账号 (密码: admin123)
+-- 密码哈希使用 bcrypt 生成
+INSERT INTO `admin` (`username`, `password_hash`, `nickname`, `role`) VALUES
+('admin', '$2a$10$N9qo8uLOickgx2ZMRZoMy.MqrqJlmZ2j3.N9qo8uLOickgx2ZMRZoG', '系统管理员', 2);
+
+-- 初始化默认价目表
+INSERT INTO `price_list` (`name`, `type`, `price`, `unit`, `color_enabled`, `is_active`, `sort_order`) VALUES
+('A4黑白打印', 'A4', 0.10, '页', 0, 1, 1),
+('A4彩色打印', 'A4', 0.30, '页', 1, 1, 2),
+('A3黑白打印', 'A3', 0.20, '页', 0, 1, 3),
+('A3彩色打印', 'A3', 0.60, '页', 1, 1, 4),
+('照片打印', '照片纸', 2.00, '张', 1, 1, 5);
+
+-- 初始化默认文库分类
+INSERT INTO `library_category` (`name`, `icon`, `sort_order`) VALUES
+('学习资料', 'book', 1),
+('考试真题', 'exam', 2),
+('简历模板', 'resume', 3),
+('合同协议', 'contract', 4),
+('其他资料', 'other', 5);