first commit
This commit is contained in:
commit
961cb16a70
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build
|
||||
.idea
|
||||
21
DockerfileBase
Normal file
21
DockerfileBase
Normal file
@ -0,0 +1,21 @@
|
||||
FROM ubuntu:22.04
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
COPY ./conf/Shanghai /usr/share/zoneinfo/Asia/Shanghai
|
||||
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
|
||||
|
||||
# 换用阿里云镜像源加速下载
|
||||
RUN sed -i 's|http://archive.ubuntu.com|http://mirrors.aliyun.com|g' /etc/apt/sources.list \
|
||||
&& sed -i 's|http://security.ubuntu.com|http://mirrors.aliyun.com|g' /etc/apt/sources.list
|
||||
|
||||
# 安装libreoffice以及Calibri、Arial、Times New Roman 等微软字体 + 中文黑体
|
||||
RUN apt-get update && apt-get install -y \
|
||||
tzdata \
|
||||
libreoffice \
|
||||
fonts-dejavu \
|
||||
ttf-mscorefonts-installer \
|
||||
fontconfig \
|
||||
fonts-wqy-zenhei\
|
||||
fonts-wqy-microhei \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN fc-cache -fv
|
||||
14
DockerfileForLocal
Normal file
14
DockerfileForLocal
Normal file
@ -0,0 +1,14 @@
|
||||
FROM libreoffice-base:v1
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV MODE_ENV=local
|
||||
ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
COPY ./build/app /app/bin/app
|
||||
COPY ./conf /app/conf/
|
||||
COPY ./docker-entrypoint.sh /app/bin/docker-entrypoint.sh
|
||||
RUN chmod +x /app/bin/docker-entrypoint.sh
|
||||
|
||||
WORKDIR /app/bin
|
||||
ENTRYPOINT ["./docker-entrypoint.sh"]
|
||||
CMD ["./app"]
|
||||
14
DockerfileForTest
Normal file
14
DockerfileForTest
Normal file
@ -0,0 +1,14 @@
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/dorlolo_j/xjj/libreoffice-base:v1
|
||||
|
||||
ENV TZ=Asia/Shanghai
|
||||
ENV MODE_ENV=test
|
||||
ENV PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
COPY ./build/app /app/bin/app
|
||||
COPY ./conf /app/conf/
|
||||
COPY ./docker-entrypoint.sh /app/bin/docker-entrypoint.sh
|
||||
RUN chmod +x /app/bin/docker-entrypoint.sh
|
||||
|
||||
WORKDIR /app/bin
|
||||
ENTRYPOINT ["./docker-entrypoint.sh"]
|
||||
CMD ["./app"]
|
||||
202
README.md
Normal file
202
README.md
Normal file
@ -0,0 +1,202 @@
|
||||
# libreofficeMicro
|
||||
|
||||
基于 Dubbo-Go (Triple 协议) 的 LibreOffice 文档转换微服务,提供 Office 文档(docx/xlsx/pptx 等)转 PDF 的 RPC 能力。
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
libreofficeMicro/
|
||||
├── cmd/
|
||||
│ ├── app.go # 服务入口
|
||||
│ ├── service/
|
||||
│ │ └── libreofficeService.go # Dubbo Provider 注册层
|
||||
│ └── logic/
|
||||
│ └── libreofficeLogic.go # 业务逻辑(调用 LibreOffice CLI)
|
||||
├── pb/
|
||||
│ ├── libreoffice.proto # Protobuf 接口定义
|
||||
│ └── libreoffice/ # 生成的 Go 代码
|
||||
├── conf/
|
||||
│ ├── local/ # 联调环境配置
|
||||
│ │ ├── dubbogo.yaml
|
||||
│ │ └── conf.ini
|
||||
│ ├── test/ # 测试环境配置
|
||||
│ └── k8s/ # 生产环境配置
|
||||
├── pkg/
|
||||
│ ├── config/ # 配置加载
|
||||
│ └── logger/ # Zap 日志
|
||||
├── build/ # 编译产物(Linux amd64 静态二进制)
|
||||
├── DockerfileForLocal # 本地联调用 Dockerfile
|
||||
├── DockerfileBase # 基础镜像 Dockerfile
|
||||
├── docker-entrypoint.sh # 容器启动脚本(自动设置注册 IP)
|
||||
├── run-local.ps1 # 本地一键编译 + 运行脚本
|
||||
└── build-image.ps1 # 仅构建镜像脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 服务接口
|
||||
|
||||
接口定义见 `pb/libreoffice.proto`,服务名为 `com.fontree.microservices.common.libreoffice`。
|
||||
|
||||
| RPC 方法 | 请求 | 响应 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `ConvertToPdf` | 文件 URL + 文件名 | PDF 二进制数据 | 服务端下载文件后转换,适合文件已在可访问 URL 上的场景 |
|
||||
| `ConvertToPdfFromBytes` | 文件二进制数据 + 文件名 | PDF 二进制数据 | 直接传字节流转换,调用方无需先上传文件,**推荐使用** |
|
||||
|
||||
---
|
||||
|
||||
## 环境要求
|
||||
|
||||
- Go 1.23+
|
||||
- Docker(本地运行需要)
|
||||
- ZooKeeper(作为服务注册中心)
|
||||
|
||||
容器运行时依赖基础镜像 `registry.cn-hangzhou.aliyuncs.com/dorlolo_j/xjj/libreoffice:v1`,该镜像已内置 LibreOffice。
|
||||
|
||||
---
|
||||
|
||||
## 配置说明
|
||||
|
||||
通过环境变量 `MODE_ENV` 选择配置目录:
|
||||
|
||||
| `MODE_ENV` | 配置目录 | 适用场景 |
|
||||
|---|---|---|
|
||||
| `local`(默认) | `conf/local/` | 本地联调 |
|
||||
| `test` | `conf/test/` | 测试环境 |
|
||||
| `prod` | `conf/k8s/` | 生产环境(K8s) |
|
||||
|
||||
### dubbogo.yaml 关键配置
|
||||
|
||||
```yaml
|
||||
dubbo:
|
||||
registries:
|
||||
demoZK:
|
||||
protocol: zookeeper
|
||||
address: zookeeper:2181 # ZooKeeper 地址
|
||||
protocols:
|
||||
triple:
|
||||
name: tri
|
||||
ip: 0.0.0.0
|
||||
port: 20119 # 服务监听端口
|
||||
provider:
|
||||
services:
|
||||
LibreofficeProvider:
|
||||
interface: com.fontree.microservices.common.libreoffice
|
||||
retries: 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 本地运行(Docker)
|
||||
|
||||
完整流程分三步:**构建基础镜像 → 构建项目镜像 → 启动容器**。
|
||||
|
||||
### 第一步:构建基础镜像
|
||||
|
||||
基础镜像基于 Ubuntu 22.04,安装了 LibreOffice、中文字体(文泉驿黑体/微米黑)以及微软常用字体(Calibri、Arial、Times New Roman 等),**只需构建一次**,后续迭代项目代码无需重复执行。
|
||||
|
||||
```bash
|
||||
docker build -f DockerfileBase -t libreoffice-base:v1 .
|
||||
```
|
||||
|
||||
> **注意**:
|
||||
> - 构建时会通过 `apt-get` 安装 LibreOffice,**耗时较长(5~15 分钟)**,请耐心等待。
|
||||
> - 需要提前将 `Shanghai` 时区文件放到 `conf/Shanghai`(或确认该路径存在),否则构建报错。
|
||||
> - 构建成功后可推送到私有镜像仓库,团队成员直接拉取,无需各自重新构建:
|
||||
> ```bash
|
||||
> docker tag libreoffice-base:v1 registry.cn-hangzhou.aliyuncs.com/dorlolo_j/xjj/libreoffice:v1
|
||||
> docker push registry.cn-hangzhou.aliyuncs.com/dorlolo_j/xjj/libreoffice:v1
|
||||
> ```
|
||||
|
||||
### 第二步:构建项目镜像
|
||||
|
||||
项目镜像基于第一步的基础镜像,将编译好的 Go 二进制与配置文件打包进去。执行:
|
||||
|
||||
```powershell
|
||||
.\build-image.ps1
|
||||
```
|
||||
|
||||
脚本执行流程:
|
||||
1. 设置 `GOPROXY` 并执行 `go mod tidy`
|
||||
2. 交叉编译为 Linux amd64 静态二进制,输出到 `./build/app`
|
||||
3. 使用 `DockerfileForLocal` 构建镜像 `libreoffice-micro:v1`
|
||||
|
||||
> **注意**:
|
||||
> - 每次修改业务代码后,重新执行此脚本即可,无需重新构建基础镜像。
|
||||
|
||||
### 第三步:启动项目容器
|
||||
|
||||
```powershell
|
||||
.\run-local.ps1
|
||||
```
|
||||
|
||||
脚本执行流程:
|
||||
1. 停止并删除同名旧容器(如存在)
|
||||
2. 重新编译并构建镜像(包含第二步的操作)
|
||||
3. 启动容器
|
||||
|
||||
容器启动参数说明:
|
||||
|
||||
| 参数 | 值 | 说明 |
|
||||
|---|---|---|
|
||||
| `--network` | `microservicebaseenv_dockercompose_backend` | 与 ZooKeeper 等基础服务同网络,确保能连通注册中心 |
|
||||
| `-p 20119:20119` | 宿主机端口映射 | 允许宿主机上运行的客户端通过 `127.0.0.1:20119` 访问 |
|
||||
| `-e MODE_ENV` | `local` | 使用 `conf/local/` 联调环境配置 |
|
||||
| `-e DUBBO_IP_TO_REGISTRY` | `127.0.0.1` | 向 ZooKeeper 注册宿主机回环地址,供宿主机客户端访问 |
|
||||
| `--restart unless-stopped` | — | 宿主机重启后自动拉起容器 |
|
||||
|
||||
> **注意**:
|
||||
> - `DUBBO_IP_TO_REGISTRY=127.0.0.1` 适用于**客户端(如 performance-client)在宿主机**直接运行的场景。若客户端也在 Docker 容器内,去掉该变量,`docker-entrypoint.sh` 会自动将容器 IP 注册到 ZooKeeper。
|
||||
> - 启动前确保 `microservicebaseenv_dockercompose_backend` 网络已存在(即基础环境的 docker-compose 已启动)。
|
||||
|
||||
查看运行日志:
|
||||
|
||||
```bash
|
||||
docker logs -f libreoffice-micro
|
||||
```
|
||||
|
||||
停止并删除容器:
|
||||
|
||||
```bash
|
||||
docker stop libreoffice-micro && docker rm libreoffice-micro
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 重新生成 Protobuf 代码
|
||||
|
||||
```bash
|
||||
cd pb
|
||||
protoc libreoffice.proto --go_out=. --go-triple_out=useOldVersion=true:. libreoffice.proto
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 客户端接入(Dubbo-Go 消费方)
|
||||
|
||||
在消费方的 `dubbogo.yaml` 中添加引用:
|
||||
|
||||
```yaml
|
||||
dubbo:
|
||||
consumer:
|
||||
references:
|
||||
LibreofficeServiceClientImpl:
|
||||
protocol: tri
|
||||
interface: com.fontree.microservices.common.libreoffice
|
||||
retries: 0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
**Q: 容器内找不到 `libreoffice` 可执行文件?**
|
||||
A: 确认使用的是正确基础镜像。服务启动时会依次在 `PATH`、`/usr/bin/libreoffice`、`/usr/lib/libreoffice/program/soffice`、`/opt/libreoffice/program/soffice` 中查找。
|
||||
|
||||
**Q: 客户端连接超时(`i/o timeout`)?**
|
||||
A: 检查 ZooKeeper 中注册的服务 IP 是否可被客户端访问。若客户端在宿主机,启动容器时需设置 `-e DUBBO_IP_TO_REGISTRY=127.0.0.1` 并映射端口 `-p 20119:20119`。
|
||||
|
||||
**Q: 二进制文件在容器内运行报 Windows 相关错误?**
|
||||
A: 编译时必须设置 `$env:GOOS="linux"`,不能使用 `go env -w GOOS=linux`(PowerShell 中后者对当前进程无效)。
|
||||
37
build-image.ps1
Normal file
37
build-image.ps1
Normal file
@ -0,0 +1,37 @@
|
||||
# 构建Docker镜像脚本
|
||||
# 编码: UTF-8
|
||||
|
||||
# 设置变量
|
||||
$IMAGE_NAME = "libreoffice-micro"
|
||||
$IMAGE_TAG = "v1"
|
||||
$DOCKERFILE = "./DockerfileForLocal"
|
||||
|
||||
# 构建镜像
|
||||
Write-Host "build docker file starting: ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
# 构建编译文件
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go mod tidy
|
||||
|
||||
# 用环境变量强制交叉编译为 Linux amd64 静态二进制,不修改全局 go env
|
||||
$env:GOOS = "linux"
|
||||
$env:GOARCH = "amd64"
|
||||
$env:CGO_ENABLED = "0"
|
||||
go build -ldflags="-extldflags '-static'" -o ./build/app ./cmd/app.go
|
||||
$env:GOOS = ""
|
||||
$env:GOARCH = ""
|
||||
$env:CGO_ENABLED = ""
|
||||
|
||||
try {
|
||||
docker build -f $DOCKERFILE -t "${IMAGE_NAME}:${IMAGE_TAG}" .
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "镜像构建成功: ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
Write-Host "查看镜像: docker images | findstr $IMAGE_NAME"
|
||||
} else {
|
||||
Write-Host "镜像构建失败"
|
||||
exit 1
|
||||
}
|
||||
} catch {
|
||||
Write-Host "构建过程中出现错误: $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
27
cmd/app.go
Normal file
27
cmd/app.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"libreofficeMicro/cmd/service"
|
||||
projectConf "libreofficeMicro/pkg/config"
|
||||
"libreofficeMicro/pkg/logger"
|
||||
|
||||
"dubbo.apache.org/dubbo-go/v3/config"
|
||||
_ "dubbo.apache.org/dubbo-go/v3/filter/token"
|
||||
_ "dubbo.apache.org/dubbo-go/v3/imports"
|
||||
)
|
||||
|
||||
func main() {
|
||||
iniConf := projectConf.GetOptions()
|
||||
fmt.Println("配置文件路径:", iniConf)
|
||||
logger.InitLogger()
|
||||
logger.L().Info("服务启动中...")
|
||||
|
||||
config.SetProviderService(service.NewLibreofficeProvider())
|
||||
|
||||
if err := config.Load(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
select {}
|
||||
}
|
||||
|
||||
199
cmd/logic/libreofficeLogic.go
Normal file
199
cmd/logic/libreofficeLogic.go
Normal file
@ -0,0 +1,199 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"libreofficeMicro/pb/libreoffice"
|
||||
)
|
||||
|
||||
type LibreofficeLogic struct{}
|
||||
|
||||
func NewLibreofficeLogic() *LibreofficeLogic {
|
||||
return &LibreofficeLogic{}
|
||||
}
|
||||
|
||||
// ConvertToPdf 通过 URL 下载文件并用 LibreOffice 转换为 PDF,返回 PDF 文件路径(或可访问 URL)
|
||||
func (l *LibreofficeLogic) ConvertToPdf(req *libreoffice.ConvertToPdfRequest) (*libreoffice.ConvertToPdfResponse, error) {
|
||||
// 创建临时工作目录
|
||||
workDir, err := os.MkdirTemp("", "libreoffice-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建临时目录失败: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(workDir)
|
||||
|
||||
// 下载源文件
|
||||
inputPath := filepath.Join(workDir, req.FileName)
|
||||
if err := downloadFile(req.FileUrl, inputPath); err != nil {
|
||||
return nil, fmt.Errorf("下载文件失败: %w", err)
|
||||
}
|
||||
|
||||
// 调用 LibreOffice 转换
|
||||
pdfPath, err := convertToPdfWithLibreoffice(inputPath, workDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("LibreOffice 转换失败: %w", err)
|
||||
}
|
||||
|
||||
// 将 PDF 保存到持久化目录(可替换为上传到对象存储)
|
||||
outputDir := "/tmp/pdf-output"
|
||||
if err := os.MkdirAll(outputDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("创建输出目录失败: %w", err)
|
||||
}
|
||||
outputName := fmt.Sprintf("%d_%s.pdf", time.Now().UnixNano(), strings.TrimSuffix(req.FileName, filepath.Ext(req.FileName)))
|
||||
outputPath := filepath.Join(outputDir, outputName)
|
||||
if err := copyFile(pdfPath, outputPath); err != nil {
|
||||
return nil, fmt.Errorf("保存 PDF 失败: %w", err)
|
||||
}
|
||||
|
||||
return &libreoffice.ConvertToPdfResponse{
|
||||
PdfUrl: outputPath, // 可根据实际需求替换为可访问的 URL
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConvertToPdfFromBytes 接收文件二进制数据,用 LibreOffice 转换为 PDF,返回 PDF 二进制数据
|
||||
func (l *LibreofficeLogic) ConvertToPdfFromBytes(req *libreoffice.ConvertToPdfFromBytesRequest) (*libreoffice.ConvertToPdfFromBytesResponse, error) {
|
||||
// 创建临时工作目录
|
||||
workDir, err := os.MkdirTemp("", "libreoffice-*")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建临时目录失败: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(workDir)
|
||||
fmt.Println("ConvertToPdfFromBytes --1")
|
||||
// 将二进制数据写入临时文件
|
||||
inputPath := filepath.Join(workDir, req.FileName)
|
||||
if err := os.WriteFile(inputPath, req.FileData, 0644); err != nil {
|
||||
return nil, fmt.Errorf("写入临时文件失败: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("ConvertToPdfFromBytes --2")
|
||||
// 调用 LibreOffice 转换
|
||||
pdfPath, err := convertToPdfWithLibreoffice(inputPath, workDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("LibreOffice 转换失败: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("ConvertToPdfFromBytes --3")
|
||||
// 读取 PDF 文件内容
|
||||
pdfData, err := os.ReadFile(pdfPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取 PDF 文件失败: %w", err)
|
||||
}
|
||||
|
||||
fmt.Println("ConvertToPdfFromBytes --4")
|
||||
pdfFileName := strings.TrimSuffix(req.FileName, filepath.Ext(req.FileName)) + ".pdf"
|
||||
return &libreoffice.ConvertToPdfFromBytesResponse{
|
||||
PdfData: pdfData,
|
||||
FileName: pdfFileName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetPreviewUrl 获取文件预览 URL(先转 PDF,再返回可访问路径)
|
||||
func (l *LibreofficeLogic) GetPreviewUrl(req *libreoffice.GetPreviewUrlRequest) (*libreoffice.GetPreviewUrlResponse, error) {
|
||||
convertResp, err := l.ConvertToPdf(&libreoffice.ConvertToPdfRequest{
|
||||
FileUrl: req.FileUrl,
|
||||
FileName: req.FileName,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &libreoffice.GetPreviewUrlResponse{
|
||||
PreviewUrl: convertResp.PdfUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// libreofficeExec 查找 libreoffice 可执行文件路径,优先使用 PATH,
|
||||
// 找不到则按 Ubuntu/Debian 常见安装路径回退。
|
||||
func libreofficeExec() (string, error) {
|
||||
if path, err := exec.LookPath("libreoffice"); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
candidates := []string{
|
||||
"/usr/bin/libreoffice",
|
||||
"/usr/lib/libreoffice/program/soffice",
|
||||
"/opt/libreoffice/program/soffice",
|
||||
}
|
||||
for _, p := range candidates {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("未找到 libreoffice 可执行文件,请确认容器内已安装 LibreOffice")
|
||||
}
|
||||
|
||||
// convertToPdfWithLibreoffice 调用容器内 LibreOffice CLI 将文件转换为 PDF
|
||||
func convertToPdfWithLibreoffice(inputPath, outDir string) (string, error) {
|
||||
fmt.Println("convertToPdfWithLibreoffice --1")
|
||||
bin, err := libreofficeExec()
|
||||
fmt.Println("convertToPdfWithLibreoffice --2 bin:", bin)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Println("convertToPdfWithLibreoffice --3")
|
||||
cmd := exec.Command(
|
||||
bin,
|
||||
"--headless",
|
||||
"--convert-to", "pdf",
|
||||
"--outdir", outDir,
|
||||
inputPath,
|
||||
)
|
||||
fmt.Println("convertToPdfWithLibreoffice --4")
|
||||
output, err := cmd.CombinedOutput()
|
||||
fmt.Println("convertToPdfWithLibreoffice --5 output:", string(output))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("libreoffice 执行失败: %w, 输出: %s", err, string(output))
|
||||
}
|
||||
|
||||
// LibreOffice 会将输出文件命名为 <basename>.pdf
|
||||
base := strings.TrimSuffix(filepath.Base(inputPath), filepath.Ext(inputPath))
|
||||
pdfPath := filepath.Join(outDir, base+".pdf")
|
||||
if _, err := os.Stat(pdfPath); os.IsNotExist(err) {
|
||||
return "", fmt.Errorf("转换完成但未找到 PDF 文件: %s", pdfPath)
|
||||
}
|
||||
return pdfPath, nil
|
||||
}
|
||||
|
||||
// downloadFile 从 URL 下载文件到指定路径
|
||||
func downloadFile(url, destPath string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("下载文件 HTTP 状态码异常: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
f, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
// copyFile 复制文件
|
||||
func copyFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
return err
|
||||
}
|
||||
35
cmd/service/libreofficeService.go
Normal file
35
cmd/service/libreofficeService.go
Normal file
@ -0,0 +1,35 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"libreofficeMicro/cmd/logic"
|
||||
"libreofficeMicro/pb/libreoffice"
|
||||
)
|
||||
|
||||
var _ libreoffice.LibreofficeServiceServer = new(LibreofficeProvider)
|
||||
|
||||
type LibreofficeProvider struct {
|
||||
libreoffice.UnimplementedLibreofficeServiceServer
|
||||
logic *logic.LibreofficeLogic
|
||||
}
|
||||
|
||||
func NewLibreofficeProvider() *LibreofficeProvider {
|
||||
return &LibreofficeProvider{
|
||||
logic: logic.NewLibreofficeLogic(),
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertToPdf 通过 URL 下载文件并转换为 PDF
|
||||
func (p *LibreofficeProvider) ConvertToPdf(ctx context.Context, req *libreoffice.ConvertToPdfRequest) (*libreoffice.ConvertToPdfResponse, error) {
|
||||
return p.logic.ConvertToPdf(req)
|
||||
}
|
||||
|
||||
// ConvertToPdfFromBytes 接收文件二进制数据并转换为 PDF
|
||||
func (p *LibreofficeProvider) ConvertToPdfFromBytes(ctx context.Context, req *libreoffice.ConvertToPdfFromBytesRequest) (*libreoffice.ConvertToPdfFromBytesResponse, error) {
|
||||
return p.logic.ConvertToPdfFromBytes(req)
|
||||
}
|
||||
|
||||
// GetPreviewUrl 获取文件预览 URL
|
||||
func (p *LibreofficeProvider) GetPreviewUrl(ctx context.Context, req *libreoffice.GetPreviewUrlRequest) (*libreoffice.GetPreviewUrlResponse, error) {
|
||||
return p.logic.GetPreviewUrl(req)
|
||||
}
|
||||
5
conf/k8s/conf.ini
Normal file
5
conf/k8s/conf.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[service]
|
||||
mode = prod
|
||||
|
||||
[zap_log]
|
||||
level = "error"
|
||||
39
conf/k8s/dubbogo.yaml
Normal file
39
conf/k8s/dubbogo.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
dubbo:
|
||||
registries:
|
||||
demoZK:
|
||||
protocol: zookeeper
|
||||
address: zookeeper:2181
|
||||
protocols:
|
||||
triple:
|
||||
name: tri
|
||||
ip: 0.0.0.0
|
||||
port: 20019
|
||||
provider:
|
||||
services:
|
||||
LibreofficeProvider:
|
||||
interface: com.fontree.microservices.common.libreoffice
|
||||
retries: 0
|
||||
logger:
|
||||
zap-config:
|
||||
level: error
|
||||
development: false
|
||||
disableCaller: false
|
||||
disableStacktrace: false
|
||||
encoding: "json"
|
||||
encoderConfig:
|
||||
messageKey: "message"
|
||||
levelKey: "level"
|
||||
timeKey: "time"
|
||||
nameKey: "logger"
|
||||
callerKey: "caller"
|
||||
stacktraceKey: "stacktrace"
|
||||
lineEnding: ""
|
||||
levelEncoder: "capitalColor"
|
||||
timeEncoder: "iso8601"
|
||||
durationEncoder: "seconds"
|
||||
callerEncoder: "short"
|
||||
nameEncoder: ""
|
||||
outputPaths:
|
||||
- "stderr"
|
||||
errorOutputPaths:
|
||||
- "stderr"
|
||||
6
conf/local/conf.ini
Normal file
6
conf/local/conf.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[service]
|
||||
mode = xjj
|
||||
|
||||
[zap_log]
|
||||
level = "info"
|
||||
|
||||
39
conf/local/dubbogo.yaml
Normal file
39
conf/local/dubbogo.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
dubbo:
|
||||
registries:
|
||||
demoZK:
|
||||
protocol: zookeeper
|
||||
address: zookeeper:2181
|
||||
protocols:
|
||||
triple:
|
||||
name: tri
|
||||
ip: 0.0.0.0
|
||||
port: 20119
|
||||
provider:
|
||||
services:
|
||||
LibreofficeProvider:
|
||||
interface: com.fontree.microservices.common.libreoffice
|
||||
retries: 0
|
||||
logger:
|
||||
zap-config:
|
||||
level: error
|
||||
development: false
|
||||
disableCaller: false
|
||||
disableStacktrace: false
|
||||
encoding: "json"
|
||||
encoderConfig:
|
||||
messageKey: "message"
|
||||
levelKey: "level"
|
||||
timeKey: "time"
|
||||
nameKey: "logger"
|
||||
callerKey: "caller"
|
||||
stacktraceKey: "stacktrace"
|
||||
lineEnding: ""
|
||||
levelEncoder: "capitalColor"
|
||||
timeEncoder: "iso8601"
|
||||
durationEncoder: "seconds"
|
||||
callerEncoder: "short"
|
||||
nameEncoder: ""
|
||||
outputPaths:
|
||||
- "stderr"
|
||||
errorOutputPaths:
|
||||
- "stderr"
|
||||
6
conf/test/conf.ini
Normal file
6
conf/test/conf.ini
Normal file
@ -0,0 +1,6 @@
|
||||
[service]
|
||||
mode = test
|
||||
|
||||
[zap_log]
|
||||
level = "info"
|
||||
|
||||
39
conf/test/dubbogo.yaml
Normal file
39
conf/test/dubbogo.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
dubbo:
|
||||
registries:
|
||||
demoZK:
|
||||
protocol: zookeeper
|
||||
address: zookeeper:2181
|
||||
protocols:
|
||||
triple:
|
||||
name: tri
|
||||
ip: 0.0.0.0
|
||||
port: 20019
|
||||
provider:
|
||||
services:
|
||||
LibreofficeProvider:
|
||||
interface: com.fontree.microservices.common.libreoffice
|
||||
retries: 0
|
||||
logger:
|
||||
zap-config:
|
||||
level: error
|
||||
development: false
|
||||
disableCaller: false
|
||||
disableStacktrace: false
|
||||
encoding: "json"
|
||||
encoderConfig:
|
||||
messageKey: "message"
|
||||
levelKey: "level"
|
||||
timeKey: "time"
|
||||
nameKey: "logger"
|
||||
callerKey: "caller"
|
||||
stacktraceKey: "stacktrace"
|
||||
lineEnding: ""
|
||||
levelEncoder: "capitalColor"
|
||||
timeEncoder: "iso8601"
|
||||
durationEncoder: "seconds"
|
||||
callerEncoder: "short"
|
||||
nameEncoder: ""
|
||||
outputPaths:
|
||||
- "stderr"
|
||||
errorOutputPaths:
|
||||
- "stderr"
|
||||
16
docker-entrypoint.sh
Normal file
16
docker-entrypoint.sh
Normal file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
# 若外部已通过 -e 传入 DUBBO_IP_TO_REGISTRY 则直接使用,
|
||||
# 否则自动取容器第一个 IP(适用于全容器部署场景)
|
||||
if [ -z "$DUBBO_IP_TO_REGISTRY" ]; then
|
||||
CONTAINER_IP=$(hostname -I | awk '{print $1}')
|
||||
if [ -z "$CONTAINER_IP" ]; then
|
||||
echo "警告: 无法获取容器 IP,使用默认自动探测"
|
||||
else
|
||||
export DUBBO_IP_TO_REGISTRY=$CONTAINER_IP
|
||||
echo "注册 IP (自动): $DUBBO_IP_TO_REGISTRY"
|
||||
fi
|
||||
else
|
||||
echo "注册 IP (外部指定): $DUBBO_IP_TO_REGISTRY"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
140
go.mod
Normal file
140
go.mod
Normal file
@ -0,0 +1,140 @@
|
||||
module libreofficeMicro
|
||||
|
||||
go 1.23.12
|
||||
|
||||
replace github.com/fonchain/utils/ini => ../utils/ini
|
||||
|
||||
require (
|
||||
dubbo.apache.org/dubbo-go/v3 v3.0.2
|
||||
github.com/dubbogo/grpc-go v1.42.9
|
||||
github.com/dubbogo/triple v1.1.8
|
||||
github.com/fonchain/utils/ini v0.0.0-00010101000000-000000000000
|
||||
go.uber.org/zap v1.21.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.19.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
contrib.go.opencensus.io/exporter/prometheus v0.4.1 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/RoaringBitmap/roaring v1.1.0 // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/Workiva/go-datastructures v1.0.52 // indirect
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect
|
||||
github.com/alibaba/sentinel-golang v1.0.4 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
|
||||
github.com/apache/dubbo-getty v1.4.8 // indirect
|
||||
github.com/apache/dubbo-go-hessian2 v1.11.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/creasty/defaults v1.5.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5 // indirect
|
||||
github.com/dubbogo/gost v1.11.25 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.7.4 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.10.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-co-op/gocron v1.9.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-kit/log v0.1.0 // indirect
|
||||
github.com/go-logfmt/logfmt v0.5.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||
github.com/go-resty/resty/v2 v2.7.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/vault/sdk v0.3.0 // indirect
|
||||
github.com/jinzhu/copier v0.3.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/k0kubun/pp v3.0.1+incompatible // indirect
|
||||
github.com/knadh/koanf v1.4.1 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/nacos-group/nacos-sdk-go v1.1.1 // indirect
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/polarismesh/polaris-go v1.1.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/prometheus/client_golang v1.12.2 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/statsd_exporter v0.21.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
|
||||
github.com/shirou/gopsutil v3.20.11+incompatible // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.22.2 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.3.3 // indirect
|
||||
github.com/spf13/cast v1.3.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.7.1 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||
github.com/uber/jaeger-client-go v2.29.1+incompatible // indirect
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
github.com/zouyx/agollo/v3 v3.4.5 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.4 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/crypto v0.21.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/grpc v1.56.3 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
33
pb/libreoffice.proto
Normal file
33
pb/libreoffice.proto
Normal file
@ -0,0 +1,33 @@
|
||||
syntax = "proto3";
|
||||
// protoc命令: cd pb && protoc libreoffice.proto --go_out=. --go-triple_out=useOldVersion=true:. libreoffice.proto
|
||||
package libreoffice;
|
||||
option go_package = "./libreoffice;libreoffice";
|
||||
|
||||
// 将文件转换为 PDF(通过 URL)
|
||||
message ConvertToPdfRequest {
|
||||
string fileUrl = 1; // 源文件 URL(支持 docx/xlsx/pptx 等)
|
||||
string fileName = 2; // 文件名(含扩展名),用于判断格式
|
||||
}
|
||||
|
||||
message ConvertToPdfResponse {
|
||||
bytes pdfData = 1; // 转换后的 PDF 二进制数据
|
||||
string fileName = 2; // PDF 文件名
|
||||
}
|
||||
|
||||
// 将文件转换为 PDF(通过文件二进制数据)
|
||||
message ConvertToPdfFromBytesRequest {
|
||||
bytes fileData = 1; // 文件二进制数据
|
||||
string fileName = 2; // 文件名(含扩展名),用于判断格式
|
||||
}
|
||||
|
||||
message ConvertToPdfFromBytesResponse {
|
||||
bytes pdfData = 1; // 转换后的 PDF 二进制数据
|
||||
string fileName = 2; // PDF 文件名
|
||||
}
|
||||
|
||||
service LibreofficeService {
|
||||
// 文件转 PDF(URL 方式)
|
||||
rpc ConvertToPdf(ConvertToPdfRequest) returns (ConvertToPdfResponse);
|
||||
// 文件转 PDF(二进制数据方式)
|
||||
rpc ConvertToPdfFromBytes(ConvertToPdfFromBytesRequest) returns (ConvertToPdfFromBytesResponse);
|
||||
}
|
||||
310
pb/libreoffice/libreoffice.pb.go
Normal file
310
pb/libreoffice/libreoffice.pb.go
Normal file
@ -0,0 +1,310 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.31.1
|
||||
// source: libreoffice.proto
|
||||
|
||||
// protoc命令: cd pb && protoc libreoffice.proto --go_out=. --go-triple_out=useOldVersion=true:. libreoffice.proto
|
||||
|
||||
package libreoffice
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
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)
|
||||
)
|
||||
|
||||
// 将文件转换为 PDF(通过 URL)
|
||||
type ConvertToPdfRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
FileUrl string `protobuf:"bytes,1,opt,name=fileUrl,proto3" json:"fileUrl,omitempty"` // 源文件 URL(支持 docx/xlsx/pptx 等)
|
||||
FileName string `protobuf:"bytes,2,opt,name=fileName,proto3" json:"fileName,omitempty"` // 文件名(含扩展名),用于判断格式
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfRequest) Reset() {
|
||||
*x = ConvertToPdfRequest{}
|
||||
mi := &file_libreoffice_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConvertToPdfRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ConvertToPdfRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_libreoffice_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 ConvertToPdfRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ConvertToPdfRequest) Descriptor() ([]byte, []int) {
|
||||
return file_libreoffice_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfRequest) GetFileUrl() string {
|
||||
if x != nil {
|
||||
return x.FileUrl
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfRequest) GetFileName() string {
|
||||
if x != nil {
|
||||
return x.FileName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ConvertToPdfResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
PdfData []byte `protobuf:"bytes,1,opt,name=pdfData,proto3" json:"pdfData,omitempty"` // 转换后的 PDF 二进制数据
|
||||
FileName string `protobuf:"bytes,2,opt,name=fileName,proto3" json:"fileName,omitempty"` // PDF 文件名
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfResponse) Reset() {
|
||||
*x = ConvertToPdfResponse{}
|
||||
mi := &file_libreoffice_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConvertToPdfResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ConvertToPdfResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_libreoffice_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 ConvertToPdfResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ConvertToPdfResponse) Descriptor() ([]byte, []int) {
|
||||
return file_libreoffice_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfResponse) GetPdfData() []byte {
|
||||
if x != nil {
|
||||
return x.PdfData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfResponse) GetFileName() string {
|
||||
if x != nil {
|
||||
return x.FileName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 将文件转换为 PDF(通过文件二进制数据)
|
||||
type ConvertToPdfFromBytesRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
FileData []byte `protobuf:"bytes,1,opt,name=fileData,proto3" json:"fileData,omitempty"` // 文件二进制数据
|
||||
FileName string `protobuf:"bytes,2,opt,name=fileName,proto3" json:"fileName,omitempty"` // 文件名(含扩展名),用于判断格式
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesRequest) Reset() {
|
||||
*x = ConvertToPdfFromBytesRequest{}
|
||||
mi := &file_libreoffice_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConvertToPdfFromBytesRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ConvertToPdfFromBytesRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_libreoffice_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 ConvertToPdfFromBytesRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ConvertToPdfFromBytesRequest) Descriptor() ([]byte, []int) {
|
||||
return file_libreoffice_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesRequest) GetFileData() []byte {
|
||||
if x != nil {
|
||||
return x.FileData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesRequest) GetFileName() string {
|
||||
if x != nil {
|
||||
return x.FileName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ConvertToPdfFromBytesResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
PdfData []byte `protobuf:"bytes,1,opt,name=pdfData,proto3" json:"pdfData,omitempty"` // 转换后的 PDF 二进制数据
|
||||
FileName string `protobuf:"bytes,2,opt,name=fileName,proto3" json:"fileName,omitempty"` // PDF 文件名
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesResponse) Reset() {
|
||||
*x = ConvertToPdfFromBytesResponse{}
|
||||
mi := &file_libreoffice_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ConvertToPdfFromBytesResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ConvertToPdfFromBytesResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_libreoffice_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 ConvertToPdfFromBytesResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ConvertToPdfFromBytesResponse) Descriptor() ([]byte, []int) {
|
||||
return file_libreoffice_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesResponse) GetPdfData() []byte {
|
||||
if x != nil {
|
||||
return x.PdfData
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ConvertToPdfFromBytesResponse) GetFileName() string {
|
||||
if x != nil {
|
||||
return x.FileName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_libreoffice_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_libreoffice_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x11libreoffice.proto\x12\vlibreoffice\"K\n" +
|
||||
"\x13ConvertToPdfRequest\x12\x18\n" +
|
||||
"\afileUrl\x18\x01 \x01(\tR\afileUrl\x12\x1a\n" +
|
||||
"\bfileName\x18\x02 \x01(\tR\bfileName\"L\n" +
|
||||
"\x14ConvertToPdfResponse\x12\x18\n" +
|
||||
"\apdfData\x18\x01 \x01(\fR\apdfData\x12\x1a\n" +
|
||||
"\bfileName\x18\x02 \x01(\tR\bfileName\"V\n" +
|
||||
"\x1cConvertToPdfFromBytesRequest\x12\x1a\n" +
|
||||
"\bfileData\x18\x01 \x01(\fR\bfileData\x12\x1a\n" +
|
||||
"\bfileName\x18\x02 \x01(\tR\bfileName\"U\n" +
|
||||
"\x1dConvertToPdfFromBytesResponse\x12\x18\n" +
|
||||
"\apdfData\x18\x01 \x01(\fR\apdfData\x12\x1a\n" +
|
||||
"\bfileName\x18\x02 \x01(\tR\bfileName2\xd9\x01\n" +
|
||||
"\x12LibreofficeService\x12S\n" +
|
||||
"\fConvertToPdf\x12 .libreoffice.ConvertToPdfRequest\x1a!.libreoffice.ConvertToPdfResponse\x12n\n" +
|
||||
"\x15ConvertToPdfFromBytes\x12).libreoffice.ConvertToPdfFromBytesRequest\x1a*.libreoffice.ConvertToPdfFromBytesResponseB\x1bZ\x19./libreoffice;libreofficeb\x06proto3"
|
||||
|
||||
var (
|
||||
file_libreoffice_proto_rawDescOnce sync.Once
|
||||
file_libreoffice_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_libreoffice_proto_rawDescGZIP() []byte {
|
||||
file_libreoffice_proto_rawDescOnce.Do(func() {
|
||||
file_libreoffice_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_libreoffice_proto_rawDesc), len(file_libreoffice_proto_rawDesc)))
|
||||
})
|
||||
return file_libreoffice_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_libreoffice_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_libreoffice_proto_goTypes = []any{
|
||||
(*ConvertToPdfRequest)(nil), // 0: libreoffice.ConvertToPdfRequest
|
||||
(*ConvertToPdfResponse)(nil), // 1: libreoffice.ConvertToPdfResponse
|
||||
(*ConvertToPdfFromBytesRequest)(nil), // 2: libreoffice.ConvertToPdfFromBytesRequest
|
||||
(*ConvertToPdfFromBytesResponse)(nil), // 3: libreoffice.ConvertToPdfFromBytesResponse
|
||||
}
|
||||
var file_libreoffice_proto_depIdxs = []int32{
|
||||
0, // 0: libreoffice.LibreofficeService.ConvertToPdf:input_type -> libreoffice.ConvertToPdfRequest
|
||||
2, // 1: libreoffice.LibreofficeService.ConvertToPdfFromBytes:input_type -> libreoffice.ConvertToPdfFromBytesRequest
|
||||
1, // 2: libreoffice.LibreofficeService.ConvertToPdf:output_type -> libreoffice.ConvertToPdfResponse
|
||||
3, // 3: libreoffice.LibreofficeService.ConvertToPdfFromBytes:output_type -> libreoffice.ConvertToPdfFromBytesResponse
|
||||
2, // [2:4] is the sub-list for method output_type
|
||||
0, // [0:2] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_libreoffice_proto_init() }
|
||||
func file_libreoffice_proto_init() {
|
||||
if File_libreoffice_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_libreoffice_proto_rawDesc), len(file_libreoffice_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_libreoffice_proto_goTypes,
|
||||
DependencyIndexes: file_libreoffice_proto_depIdxs,
|
||||
MessageInfos: file_libreoffice_proto_msgTypes,
|
||||
}.Build()
|
||||
File_libreoffice_proto = out.File
|
||||
file_libreoffice_proto_goTypes = nil
|
||||
file_libreoffice_proto_depIdxs = nil
|
||||
}
|
||||
196
pb/libreoffice/libreoffice_triple.pb.go
Normal file
196
pb/libreoffice/libreoffice_triple.pb.go
Normal file
@ -0,0 +1,196 @@
|
||||
// Code generated by protoc-gen-go-triple. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-triple v1.0.8
|
||||
// - protoc v6.31.1
|
||||
// source: libreoffice.proto
|
||||
|
||||
package libreoffice
|
||||
|
||||
import (
|
||||
context "context"
|
||||
protocol "dubbo.apache.org/dubbo-go/v3/protocol"
|
||||
dubbo3 "dubbo.apache.org/dubbo-go/v3/protocol/dubbo3"
|
||||
invocation "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
|
||||
grpc_go "github.com/dubbogo/grpc-go"
|
||||
codes "github.com/dubbogo/grpc-go/codes"
|
||||
metadata "github.com/dubbogo/grpc-go/metadata"
|
||||
status "github.com/dubbogo/grpc-go/status"
|
||||
common "github.com/dubbogo/triple/pkg/common"
|
||||
constant "github.com/dubbogo/triple/pkg/common/constant"
|
||||
triple "github.com/dubbogo/triple/pkg/triple"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc_go.SupportPackageIsVersion7
|
||||
|
||||
// LibreofficeServiceClient is the client API for LibreofficeService 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 LibreofficeServiceClient interface {
|
||||
// 文件转 PDF(URL 方式)
|
||||
ConvertToPdf(ctx context.Context, in *ConvertToPdfRequest, opts ...grpc_go.CallOption) (*ConvertToPdfResponse, common.ErrorWithAttachment)
|
||||
// 文件转 PDF(二进制数据方式)
|
||||
ConvertToPdfFromBytes(ctx context.Context, in *ConvertToPdfFromBytesRequest, opts ...grpc_go.CallOption) (*ConvertToPdfFromBytesResponse, common.ErrorWithAttachment)
|
||||
}
|
||||
|
||||
type libreofficeServiceClient struct {
|
||||
cc *triple.TripleConn
|
||||
}
|
||||
|
||||
type LibreofficeServiceClientImpl struct {
|
||||
ConvertToPdf func(ctx context.Context, in *ConvertToPdfRequest) (*ConvertToPdfResponse, error)
|
||||
ConvertToPdfFromBytes func(ctx context.Context, in *ConvertToPdfFromBytesRequest) (*ConvertToPdfFromBytesResponse, error)
|
||||
}
|
||||
|
||||
func (c *LibreofficeServiceClientImpl) GetDubboStub(cc *triple.TripleConn) LibreofficeServiceClient {
|
||||
return NewLibreofficeServiceClient(cc)
|
||||
}
|
||||
|
||||
func (c *LibreofficeServiceClientImpl) XXX_InterfaceName() string {
|
||||
return "libreoffice.LibreofficeService"
|
||||
}
|
||||
|
||||
func NewLibreofficeServiceClient(cc *triple.TripleConn) LibreofficeServiceClient {
|
||||
return &libreofficeServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *libreofficeServiceClient) ConvertToPdf(ctx context.Context, in *ConvertToPdfRequest, opts ...grpc_go.CallOption) (*ConvertToPdfResponse, common.ErrorWithAttachment) {
|
||||
out := new(ConvertToPdfResponse)
|
||||
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
|
||||
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ConvertToPdf", in, out)
|
||||
}
|
||||
|
||||
func (c *libreofficeServiceClient) ConvertToPdfFromBytes(ctx context.Context, in *ConvertToPdfFromBytesRequest, opts ...grpc_go.CallOption) (*ConvertToPdfFromBytesResponse, common.ErrorWithAttachment) {
|
||||
out := new(ConvertToPdfFromBytesResponse)
|
||||
interfaceKey := ctx.Value(constant.InterfaceKey).(string)
|
||||
return out, c.cc.Invoke(ctx, "/"+interfaceKey+"/ConvertToPdfFromBytes", in, out)
|
||||
}
|
||||
|
||||
// LibreofficeServiceServer is the server API for LibreofficeService service.
|
||||
// All implementations must embed UnimplementedLibreofficeServiceServer
|
||||
// for forward compatibility
|
||||
type LibreofficeServiceServer interface {
|
||||
// 文件转 PDF(URL 方式)
|
||||
ConvertToPdf(context.Context, *ConvertToPdfRequest) (*ConvertToPdfResponse, error)
|
||||
// 文件转 PDF(二进制数据方式)
|
||||
ConvertToPdfFromBytes(context.Context, *ConvertToPdfFromBytesRequest) (*ConvertToPdfFromBytesResponse, error)
|
||||
mustEmbedUnimplementedLibreofficeServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedLibreofficeServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedLibreofficeServiceServer struct {
|
||||
proxyImpl protocol.Invoker
|
||||
}
|
||||
|
||||
func (UnimplementedLibreofficeServiceServer) ConvertToPdf(context.Context, *ConvertToPdfRequest) (*ConvertToPdfResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConvertToPdf not implemented")
|
||||
}
|
||||
func (UnimplementedLibreofficeServiceServer) ConvertToPdfFromBytes(context.Context, *ConvertToPdfFromBytesRequest) (*ConvertToPdfFromBytesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ConvertToPdfFromBytes not implemented")
|
||||
}
|
||||
func (s *UnimplementedLibreofficeServiceServer) XXX_SetProxyImpl(impl protocol.Invoker) {
|
||||
s.proxyImpl = impl
|
||||
}
|
||||
|
||||
func (s *UnimplementedLibreofficeServiceServer) XXX_GetProxyImpl() protocol.Invoker {
|
||||
return s.proxyImpl
|
||||
}
|
||||
|
||||
func (s *UnimplementedLibreofficeServiceServer) XXX_ServiceDesc() *grpc_go.ServiceDesc {
|
||||
return &LibreofficeService_ServiceDesc
|
||||
}
|
||||
func (s *UnimplementedLibreofficeServiceServer) XXX_InterfaceName() string {
|
||||
return "libreoffice.LibreofficeService"
|
||||
}
|
||||
|
||||
func (UnimplementedLibreofficeServiceServer) mustEmbedUnimplementedLibreofficeServiceServer() {}
|
||||
|
||||
// UnsafeLibreofficeServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to LibreofficeServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeLibreofficeServiceServer interface {
|
||||
mustEmbedUnimplementedLibreofficeServiceServer()
|
||||
}
|
||||
|
||||
func RegisterLibreofficeServiceServer(s grpc_go.ServiceRegistrar, srv LibreofficeServiceServer) {
|
||||
s.RegisterService(&LibreofficeService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _LibreofficeService_ConvertToPdf_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ConvertToPdfRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base := srv.(dubbo3.Dubbo3GrpcService)
|
||||
args := []interface{}{}
|
||||
args = append(args, in)
|
||||
md, _ := metadata.FromIncomingContext(ctx)
|
||||
invAttachment := make(map[string]interface{}, len(md))
|
||||
for k, v := range md {
|
||||
invAttachment[k] = v
|
||||
}
|
||||
invo := invocation.NewRPCInvocation("ConvertToPdf", args, invAttachment)
|
||||
if interceptor == nil {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
info := &grpc_go.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _LibreofficeService_ConvertToPdfFromBytes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc_go.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ConvertToPdfFromBytesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base := srv.(dubbo3.Dubbo3GrpcService)
|
||||
args := []interface{}{}
|
||||
args = append(args, in)
|
||||
md, _ := metadata.FromIncomingContext(ctx)
|
||||
invAttachment := make(map[string]interface{}, len(md))
|
||||
for k, v := range md {
|
||||
invAttachment[k] = v
|
||||
}
|
||||
invo := invocation.NewRPCInvocation("ConvertToPdfFromBytes", args, invAttachment)
|
||||
if interceptor == nil {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
info := &grpc_go.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ctx.Value("XXX_TRIPLE_GO_INTERFACE_NAME").(string),
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
result := base.XXX_GetProxyImpl().Invoke(ctx, invo)
|
||||
return result, result.Error()
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// LibreofficeService_ServiceDesc is the grpc_go.ServiceDesc for LibreofficeService service.
|
||||
// It's only intended for direct use with grpc_go.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var LibreofficeService_ServiceDesc = grpc_go.ServiceDesc{
|
||||
ServiceName: "libreoffice.LibreofficeService",
|
||||
HandlerType: (*LibreofficeServiceServer)(nil),
|
||||
Methods: []grpc_go.MethodDesc{
|
||||
{
|
||||
MethodName: "ConvertToPdf",
|
||||
Handler: _LibreofficeService_ConvertToPdf_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ConvertToPdfFromBytes",
|
||||
Handler: _LibreofficeService_ConvertToPdfFromBytes_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc_go.StreamDesc{},
|
||||
Metadata: "libreoffice.proto",
|
||||
}
|
||||
32
pkg/config/bos.go
Normal file
32
pkg/config/bos.go
Normal file
@ -0,0 +1,32 @@
|
||||
// Package config -----------------------------
|
||||
// @file : bos.go
|
||||
// @author : JJXu
|
||||
// @contact : wavingbear@163.com
|
||||
// @time : 2023/10/19 10:50
|
||||
// -------------------------------------------
|
||||
package projectConf
|
||||
|
||||
import "fmt"
|
||||
|
||||
var Bos = new(bosConfig)
|
||||
|
||||
type bosConfig struct {
|
||||
AK string `ini:"Ak"`
|
||||
SK string `ini:"Sk"`
|
||||
BucketName string `ini:"BucketName"`
|
||||
BaseDir string `ini:"BosBaseDir"`
|
||||
Url string `ini:"BosUrl"`
|
||||
}
|
||||
|
||||
func (b *bosConfig) SectionName() string {
|
||||
return "bos"
|
||||
}
|
||||
|
||||
func (b *bosConfig) LoadAfter() {
|
||||
fmt.Println("bos config:")
|
||||
fmt.Println("\tBosAK:", b.AK)
|
||||
fmt.Println("\tBosSK:", b.SK)
|
||||
fmt.Println("\tBosBucketName:", b.BucketName)
|
||||
fmt.Println("\tBosBaseDir:", b.BaseDir)
|
||||
fmt.Println("\tBosUrl:", b.Url)
|
||||
}
|
||||
30
pkg/config/db.go
Normal file
30
pkg/config/db.go
Normal file
@ -0,0 +1,30 @@
|
||||
package projectConf
|
||||
|
||||
import "fmt"
|
||||
|
||||
var DB = NewDBConfig("mysql")
|
||||
|
||||
type DBConfig struct {
|
||||
DB string `ini:"DB"`
|
||||
DBHost string `ini:"DBHost"`
|
||||
DBPort string `ini:"DBPort"`
|
||||
DBName string `ini:"DBName"`
|
||||
DBUser string `ini:"DBUser"`
|
||||
DBPassWord string `ini:"DBPassWord"`
|
||||
DBLogLevel string `ini:"DBLogLevel"` //Silent,Error,Warn,Info
|
||||
sectionName string
|
||||
}
|
||||
|
||||
func NewDBConfig(sectionName string) *DBConfig {
|
||||
return &DBConfig{
|
||||
sectionName: sectionName,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DBConfig) SectionName() string {
|
||||
return d.sectionName
|
||||
}
|
||||
|
||||
func (d *DBConfig) LoadAfter() {
|
||||
fmt.Printf("数据库配置加载完成: %s:%s/%s\n", d.DBHost, d.DBPort, d.DBName)
|
||||
}
|
||||
53
pkg/config/init.go
Normal file
53
pkg/config/init.go
Normal file
@ -0,0 +1,53 @@
|
||||
package projectConf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"libreofficeMicro/pkg/m"
|
||||
|
||||
"dubbo.apache.org/dubbo-go/v3/common/constant"
|
||||
"github.com/fonchain/utils/ini"
|
||||
)
|
||||
|
||||
var (
|
||||
Mode string
|
||||
)
|
||||
|
||||
func GetOptions() string {
|
||||
iniConfPath, err := GetConf()
|
||||
fmt.Println("配置文件路径:", iniConfPath)
|
||||
if err != nil {
|
||||
panic("iniConf error")
|
||||
}
|
||||
err = LoadConfig(iniConfPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return iniConfPath
|
||||
}
|
||||
|
||||
func GetConf() (iniConf string, err error) {
|
||||
thisEnv := os.Getenv(m.MODE_ENV)
|
||||
if thisEnv != "" {
|
||||
if err = os.Setenv(constant.ConfigFileEnvKey, fmt.Sprintf("../conf/%s/%s", thisEnv, m.SERVER_DUBBOGO_CONFIG)); err != nil {
|
||||
return
|
||||
}
|
||||
iniConf = fmt.Sprintf("../conf/%s/%s", thisEnv, m.SERVER_CONFIG)
|
||||
} else {
|
||||
iniConf = fmt.Sprintf("../conf/%s", m.SERVER_CONFIG)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func LoadConfig(configPath string) error {
|
||||
err := ini.LoadFileToStructs(configPath,
|
||||
Zap,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Mode = ini.String("service.mode")
|
||||
return nil
|
||||
}
|
||||
|
||||
35
pkg/config/oss.go
Normal file
35
pkg/config/oss.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Package config -----------------------------
|
||||
// @file : oss.go
|
||||
// @author : JJXu
|
||||
// @contact : wavingbear@163.com
|
||||
// @time : 2023/10/19 10:50
|
||||
// -------------------------------------------
|
||||
package projectConf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var Oss = new(ossConfig)
|
||||
|
||||
type ossConfig struct {
|
||||
AK string `ini:"Ak"`
|
||||
SK string `ini:"Sk"`
|
||||
BucketName string `ini:"BucketName"`
|
||||
BaseDir string `ini:"BosBaseDir"`
|
||||
Url string `ini:"BosUrl"`
|
||||
Endpoint string `ini:"Endpoint"`
|
||||
}
|
||||
|
||||
func (i *ossConfig) SectionName() string {
|
||||
return "oss"
|
||||
}
|
||||
|
||||
func (b *ossConfig) LoadAfter() {
|
||||
fmt.Println("oss config:")
|
||||
fmt.Println("\tossAK:", b.AK)
|
||||
fmt.Println("\tossSK:", b.SK)
|
||||
fmt.Println("\tossBucketName:", b.BucketName)
|
||||
fmt.Println("\tossBaseDir:", b.BaseDir)
|
||||
fmt.Println("\tossUrl:", b.Url)
|
||||
}
|
||||
36
pkg/config/rabbitMq.go
Normal file
36
pkg/config/rabbitMq.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Package config -----------------------------
|
||||
// @file : rabbitMq.go
|
||||
// @author : JJXu
|
||||
// @contact : wavingbear@163.com
|
||||
// @time : 2024/5/7 上午10:07
|
||||
// -------------------------------------------
|
||||
package projectConf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var RabbitMq = new(rabbitMqConfig)
|
||||
|
||||
type rabbitMqConfig struct {
|
||||
Host string `ini:"host"`
|
||||
Port string `ini:"port"`
|
||||
User string `ini:"user"`
|
||||
Password string `ini:"password"`
|
||||
Queues string `ini:"queues"`
|
||||
VHost string `ini:"vhost"`
|
||||
}
|
||||
|
||||
func (f *rabbitMqConfig) SectionName() string {
|
||||
return "rabbitmq"
|
||||
}
|
||||
|
||||
func (f *rabbitMqConfig) LoadAfter() {
|
||||
fmt.Println("rabbitMq config")
|
||||
fmt.Println("\thost:", f.Host)
|
||||
fmt.Println("\tport:", f.Port)
|
||||
fmt.Println("\tuser:", f.User)
|
||||
fmt.Println("\tpassword:", f.Password)
|
||||
fmt.Println("\tvhost:", f.VHost)
|
||||
fmt.Println("\tqueues:", f.Queues)
|
||||
}
|
||||
22
pkg/config/redis.go
Normal file
22
pkg/config/redis.go
Normal file
@ -0,0 +1,22 @@
|
||||
// Package config -----------------------------
|
||||
// @file : redis.go
|
||||
// @author : JJXu
|
||||
// @contact : wavingbear@163.com
|
||||
// @time : 2023/10/19 13:20
|
||||
// -------------------------------------------
|
||||
package projectConf
|
||||
|
||||
var Redis = new(RedisConfig)
|
||||
|
||||
type RedisConfig struct {
|
||||
RedisDB int `ini:"RedisDB"`
|
||||
RedisAddr string `ini:"RedisAddr"`
|
||||
RedisPW string `ini:"RedisPW"`
|
||||
//RedisDBName string `ini:"RedisDBName"`
|
||||
}
|
||||
|
||||
func (r *RedisConfig) SectionName() string {
|
||||
return "redis"
|
||||
}
|
||||
|
||||
func (f *RedisConfig) LoadAfter() {}
|
||||
19
pkg/config/sentry.go
Normal file
19
pkg/config/sentry.go
Normal file
@ -0,0 +1,19 @@
|
||||
// Package config -----------------------------
|
||||
// @file : sentry.go
|
||||
// @author : JJXu
|
||||
// @contact : wavingbear@163.com
|
||||
// @time : 2024/7/25 下午2:53
|
||||
// -------------------------------------------
|
||||
package projectConf
|
||||
|
||||
var Sentry = new(sentryConfig)
|
||||
|
||||
type sentryConfig struct {
|
||||
Dsn string `ini:"dsn"`
|
||||
}
|
||||
|
||||
func (b *sentryConfig) SectionName() string {
|
||||
return "sentry_config"
|
||||
}
|
||||
|
||||
func (f *sentryConfig) LoadAfter() {}
|
||||
74
pkg/config/zapLog.go
Normal file
74
pkg/config/zapLog.go
Normal file
@ -0,0 +1,74 @@
|
||||
// Package config -----------------------------
|
||||
// @file : zapLog.go
|
||||
// @author : JJXu
|
||||
// @contact : wavingbear@163.com
|
||||
// @time : 2024/7/2 上午11:14
|
||||
// -------------------------------------------
|
||||
package projectConf
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var Zap = new(ZapConfig)
|
||||
|
||||
type ZapConfig struct {
|
||||
Level string `ini:"level"` //日志级别,示例:"info"
|
||||
DbLogLevel string `ini:"db_log_level"` //数据库日志级别 Silent,Error,Warn,Info,示例:"Error"
|
||||
}
|
||||
|
||||
func (b *ZapConfig) SectionName() string {
|
||||
return "zap_log"
|
||||
}
|
||||
|
||||
func (b *ZapConfig) LoadAfter() {
|
||||
|
||||
}
|
||||
|
||||
func (b *ZapConfig) Levels() []zapcore.Level {
|
||||
levels := make([]zapcore.Level, 0, 7)
|
||||
for _, l := range strings.Split(strings.ToLower(b.Level), ",") {
|
||||
level, err := zapcore.ParseLevel(l)
|
||||
if err != nil {
|
||||
level = zapcore.DebugLevel
|
||||
}
|
||||
for ; level <= zapcore.FatalLevel; level++ {
|
||||
levels = append(levels, level)
|
||||
}
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
func (b *ZapConfig) IsNull() bool {
|
||||
if b.Level == "" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (c *ZapConfig) Encoder() zapcore.Encoder {
|
||||
config := zapcore.EncoderConfig{
|
||||
TimeKey: "time",
|
||||
NameKey: "name",
|
||||
LevelKey: "level",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "message",
|
||||
StacktraceKey: "stackTrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
|
||||
encoder.AppendString(t.Format("2006-01-02 15:04:05.000"))
|
||||
},
|
||||
EncodeLevel: c.LevelEncoder(),
|
||||
EncodeCaller: zapcore.FullCallerEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
}
|
||||
//json 编码输出
|
||||
return zapcore.NewJSONEncoder(config)
|
||||
//控制台编码输出
|
||||
//return zapcore.NewConsoleEncoder(config)
|
||||
}
|
||||
func (c *ZapConfig) LevelEncoder() zapcore.LevelEncoder {
|
||||
return zapcore.CapitalLevelEncoder
|
||||
}
|
||||
5
pkg/logger/consts.go
Normal file
5
pkg/logger/consts.go
Normal file
@ -0,0 +1,5 @@
|
||||
package logger
|
||||
|
||||
const (
|
||||
DEFAULT_LEVEL = "info"
|
||||
)
|
||||
94
pkg/logger/logger.go
Normal file
94
pkg/logger/logger.go
Normal file
@ -0,0 +1,94 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
projectConf "libreofficeMicro/pkg/config"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var logger *Logger
|
||||
|
||||
func L() *Logger {
|
||||
if logger == nil {
|
||||
InitLogger()
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
type Logger struct {
|
||||
*zap.Logger
|
||||
}
|
||||
|
||||
func InitLogger() {
|
||||
if projectConf.Zap.IsNull() {
|
||||
projectConf.Zap.Level = DEFAULT_LEVEL
|
||||
}
|
||||
|
||||
var minLevel zapcore.Level
|
||||
if projectConf.Zap.Level == "" {
|
||||
minLevel = zapcore.InfoLevel
|
||||
} else {
|
||||
var err error
|
||||
minLevel, err = zapcore.ParseLevel(projectConf.Zap.Level)
|
||||
if err != nil {
|
||||
minLevel = zapcore.InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
encoderConfig := zapcore.EncoderConfig{
|
||||
TimeKey: "time",
|
||||
NameKey: "name",
|
||||
LevelKey: "level",
|
||||
CallerKey: "caller",
|
||||
MessageKey: "message",
|
||||
StacktraceKey: "stackTrace",
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
|
||||
encoder.AppendString(t.Format("2006-01-02 15:04:05.000"))
|
||||
},
|
||||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||||
EncodeCaller: zapcore.FullCallerEncoder,
|
||||
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||
}
|
||||
|
||||
encoder := zapcore.NewJSONEncoder(encoderConfig)
|
||||
writeSyncer := zapcore.AddSync(os.Stdout)
|
||||
core := zapcore.NewCore(encoder, writeSyncer, minLevel)
|
||||
|
||||
logger = &Logger{
|
||||
Logger: zap.New(
|
||||
core,
|
||||
zap.AddCaller(),
|
||||
zap.AddCallerSkip(1),
|
||||
zap.AddStacktrace(zap.ErrorLevel),
|
||||
zap.WithCaller(true),
|
||||
),
|
||||
}
|
||||
|
||||
zap.ReplaceGlobals(logger.Logger)
|
||||
}
|
||||
|
||||
func (log *Logger) Debug(msg string, fields ...zap.Field) {
|
||||
log.Logger.Debug(msg, fields...)
|
||||
}
|
||||
|
||||
func (log *Logger) Info(msg string, fields ...zap.Field) {
|
||||
log.Logger.Info(msg, fields...)
|
||||
}
|
||||
|
||||
func (log *Logger) Warn(msg string, fields ...zap.Field) {
|
||||
log.Logger.Warn(msg, fields...)
|
||||
}
|
||||
|
||||
func (log *Logger) Error(msg string, fields ...zap.Field) {
|
||||
log.Logger.Error(msg, fields...)
|
||||
}
|
||||
|
||||
func (log *Logger) Fatal(msg string, fields ...zap.Field) {
|
||||
log.Logger.Fatal(msg, fields...)
|
||||
}
|
||||
|
||||
2
pkg/logger/sentry.go
Normal file
2
pkg/logger/sentry.go
Normal file
@ -0,0 +1,2 @@
|
||||
package logger
|
||||
|
||||
13
pkg/m/msg.go
Normal file
13
pkg/m/msg.go
Normal file
@ -0,0 +1,13 @@
|
||||
package m
|
||||
|
||||
const (
|
||||
SERVER_CONFIG = "conf.ini"
|
||||
SERVER_DUBBOGO_CONFIG = "dubbogo.yaml"
|
||||
MODE_ENV = "MODE_ENV"
|
||||
)
|
||||
|
||||
const (
|
||||
DBError = "数据库错误"
|
||||
PrimaryKeyCannotBeEmpty = "主键不能为空"
|
||||
RecordNotFound = "record not found"
|
||||
)
|
||||
61
run-local.ps1
Normal file
61
run-local.ps1
Normal file
@ -0,0 +1,61 @@
|
||||
# 本地运行 libreoffice-micro 镜像脚本
|
||||
# 编码: UTF-8
|
||||
|
||||
$IMAGE_NAME = "libreoffice-micro"
|
||||
$IMAGE_TAG = "v1"
|
||||
$CONTAINER_NAME = "libreoffice-micro"
|
||||
$NETWORK = "microservicebaseenv_dockercompose_backend"
|
||||
|
||||
# 停止并移除旧容器(如存在)
|
||||
$existing = docker ps -aq --filter "name=^${CONTAINER_NAME}$"
|
||||
if ($existing) {
|
||||
Write-Host "停止并移除旧容器: $CONTAINER_NAME"
|
||||
docker stop $CONTAINER_NAME | Out-Null
|
||||
docker rm $CONTAINER_NAME | Out-Null
|
||||
}
|
||||
|
||||
# 先构建最新镜像
|
||||
Write-Host "编译并构建镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go mod tidy
|
||||
|
||||
# 用环境变量强制交叉编译为 Linux amd64 静态二进制,不修改全局 go env
|
||||
$env:GOOS = "linux"
|
||||
$env:GOARCH = "amd64"
|
||||
$env:CGO_ENABLED = "0"
|
||||
go build -ldflags="-extldflags '-static'" -o ./build/app ./cmd/app.go
|
||||
$env:GOOS = ""
|
||||
$env:GOARCH = ""
|
||||
$env:CGO_ENABLED = ""
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "编译失败,退出"
|
||||
exit 1
|
||||
}
|
||||
|
||||
docker build -f ./DockerfileForLocal -t "${IMAGE_NAME}:${IMAGE_TAG}" .
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "镜像构建失败,退出"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 启动容器
|
||||
Write-Host "启动容器: $CONTAINER_NAME"
|
||||
docker run -d `
|
||||
--name $CONTAINER_NAME `
|
||||
--network $NETWORK `
|
||||
-p 20119:20119 `
|
||||
-e MODE_ENV=xjj `
|
||||
-e DUBBO_IP_TO_REGISTRY=127.0.0.1 `
|
||||
--restart unless-stopped `
|
||||
"${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "容器启动成功"
|
||||
Write-Host "查看日志: docker logs -f $CONTAINER_NAME"
|
||||
} else {
|
||||
Write-Host "容器启动失败"
|
||||
exit 1
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user