mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 13:39:53 +00:00
added some optimizations
This commit is contained in:
parent
a5beb26d9d
commit
f394e34861
@ -31,18 +31,23 @@ type Deployer interface {
|
||||
Deploy(ctx context.Context) error
|
||||
}
|
||||
|
||||
func Get(record *models.Record) (Deployer, error) {
|
||||
func Get(record *models.Record, cert *applicant.Certificate) (Deployer, error) {
|
||||
access := record.ExpandedOne("targetAccess")
|
||||
option := &DeployerOption{
|
||||
DomainId: record.Id,
|
||||
Domain: record.GetString("domain"),
|
||||
Product: getProduct(record),
|
||||
Access: access.GetString("config"),
|
||||
Certificate: applicant.Certificate{
|
||||
}
|
||||
if cert != nil {
|
||||
option.Certificate = *cert
|
||||
} else {
|
||||
option.Certificate = applicant.Certificate{
|
||||
Certificate: record.GetString("certificate"),
|
||||
PrivateKey: record.GetString("privateKey"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
switch record.GetString("targetType") {
|
||||
case targetAliyunOss:
|
||||
return NewAliyun(option)
|
||||
|
@ -26,9 +26,11 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
app.GetApp().Logger().Error("部署失败", "err", r)
|
||||
}
|
||||
}()
|
||||
var certificate *applicant.Certificate
|
||||
currRecord, err := app.GetApp().Dao().FindRecordById("domains", record.Id)
|
||||
history := NewHistory(record)
|
||||
defer history.commit()
|
||||
|
||||
// ############1.检查域名配置
|
||||
history.record(checkPhase, "开始检查", nil)
|
||||
|
||||
@ -73,25 +75,21 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
app.GetApp().Logger().Error("获取applicant失败", "err", err)
|
||||
return err
|
||||
}
|
||||
certificate, err := applicant.Apply()
|
||||
certificate, err = applicant.Apply()
|
||||
if err != nil {
|
||||
history.record(applyPhase, "申请证书失败", err)
|
||||
app.GetApp().Logger().Error("申请证书失败", "err", err)
|
||||
return err
|
||||
}
|
||||
history.record(applyPhase, "申请证书成功", nil)
|
||||
if err = saveCert(ctx, record, certificate); err != nil {
|
||||
history.record(applyPhase, "保存证书失败", err)
|
||||
app.GetApp().Logger().Error("保存证书失败", "err", err)
|
||||
return err
|
||||
}
|
||||
history.setCert(certificate)
|
||||
}
|
||||
|
||||
history.record(applyPhase, "保存证书成功", nil, true)
|
||||
|
||||
// ############3.部署证书
|
||||
history.record(deployPhase, "开始部署", nil, false)
|
||||
deployer, err := deployer.Get(currRecord)
|
||||
deployer, err := deployer.Get(currRecord, certificate)
|
||||
if err != nil {
|
||||
history.record(deployPhase, "获取deployer失败", err)
|
||||
app.GetApp().Logger().Error("获取deployer失败", "err", err)
|
||||
@ -99,38 +97,14 @@ func deploy(ctx context.Context, record *models.Record) error {
|
||||
}
|
||||
|
||||
if err = deployer.Deploy(ctx); err != nil {
|
||||
setDeployed(ctx, record, false)
|
||||
|
||||
app.GetApp().Logger().Error("部署失败", "err", err)
|
||||
history.record(deployPhase, "部署失败", err)
|
||||
return err
|
||||
}
|
||||
|
||||
setDeployed(ctx, record, true)
|
||||
app.GetApp().Logger().Info("部署成功")
|
||||
history.record(deployPhase, "部署成功", nil, true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setDeployed(ctx context.Context, record *models.Record, deployed bool) error {
|
||||
record.Set("deployed", deployed)
|
||||
if err := app.GetApp().Dao().SaveRecord(record); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveCert(ctx context.Context, record *models.Record, cert *applicant.Certificate) error {
|
||||
record.Set("certUrl", cert.CertUrl)
|
||||
record.Set("certStableUrl", cert.CertStableUrl)
|
||||
record.Set("privateKey", cert.PrivateKey)
|
||||
record.Set("certificate", cert.Certificate)
|
||||
record.Set("issuerCertificate", cert.IssuerCertificate)
|
||||
record.Set("csr", cert.Csr)
|
||||
record.Set("expiredAt", time.Now().Add(time.Hour*24*90))
|
||||
|
||||
if err := app.GetApp().Dao().SaveRecord(record); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -14,10 +14,12 @@ func create(ctx context.Context, record *models.Record) error {
|
||||
}
|
||||
|
||||
if record.GetBool("rightnow") {
|
||||
go func() {
|
||||
if err := deploy(ctx, record); err != nil {
|
||||
app.GetApp().Logger().Error("deploy failed", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := deploy(ctx, record); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
scheduler := app.GetScheduler()
|
||||
@ -45,9 +47,11 @@ func update(ctx context.Context, record *models.Record) error {
|
||||
|
||||
if record.GetBool("rightnow") {
|
||||
|
||||
if err := deploy(ctx, record); err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if err := deploy(ctx, record); err != nil {
|
||||
app.GetApp().Logger().Error("deploy failed", "err", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
err := scheduler.Add(record.Id, record.GetString("crontab"), func() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package domains
|
||||
|
||||
import (
|
||||
"certimate/internal/applicant"
|
||||
"certimate/internal/utils/app"
|
||||
"certimate/internal/utils/xtime"
|
||||
"time"
|
||||
@ -20,6 +21,7 @@ type history struct {
|
||||
Phase Phase `json:"phase"`
|
||||
PhaseSuccess bool `json:"phaseSuccess"`
|
||||
DeployedAt string `json:"deployedAt"`
|
||||
Cert *applicant.Certificate `json:"cert"`
|
||||
}
|
||||
|
||||
func NewHistory(record *models.Record) *history {
|
||||
@ -52,6 +54,10 @@ func (a *history) record(phase Phase, msg string, err error, pass ...bool) {
|
||||
|
||||
}
|
||||
|
||||
func (a *history) setCert(cert *applicant.Certificate) {
|
||||
a.Cert = cert
|
||||
}
|
||||
|
||||
func (a *history) commit() error {
|
||||
collection, err := app.GetApp().Dao().FindCollectionByNameOrId("deployments")
|
||||
if err != nil {
|
||||
@ -78,6 +84,19 @@ func (a *history) commit() error {
|
||||
domainRecord.Set("lastDeployedAt", a.DeployedAt)
|
||||
domainRecord.Set("lastDeployment", record.Id)
|
||||
domainRecord.Set("rightnow", false)
|
||||
if a.Phase == deployPhase && a.PhaseSuccess {
|
||||
domainRecord.Set("deployed", true)
|
||||
}
|
||||
cert := a.Cert
|
||||
if cert != nil {
|
||||
domainRecord.Set("certUrl", cert.CertUrl)
|
||||
domainRecord.Set("certStableUrl", cert.CertStableUrl)
|
||||
domainRecord.Set("privateKey", cert.PrivateKey)
|
||||
domainRecord.Set("certificate", cert.Certificate)
|
||||
domainRecord.Set("issuerCertificate", cert.IssuerCertificate)
|
||||
domainRecord.Set("csr", cert.Csr)
|
||||
domainRecord.Set("expiredAt", time.Now().Add(time.Hour*24*90))
|
||||
}
|
||||
|
||||
if err := app.GetApp().Dao().SaveRecord(domainRecord); err != nil {
|
||||
return err
|
||||
|
File diff suppressed because one or more lines are too long
2
ui/dist/index.html
vendored
2
ui/dist/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Certimate - Your Trusted SSL Automation Partner</title>
|
||||
<script type="module" crossorigin src="/assets/index-3QHTbODC.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BI5-7Lpm.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-127rBbJX.css">
|
||||
</head>
|
||||
<body class="bg-background">
|
||||
|
31
ui/package-lock.json
generated
31
ui/package-lock.json
generated
@ -15,6 +15,7 @@
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-progress": "^1.1.0",
|
||||
"@radix-ui/react-radio-group": "^1.2.0",
|
||||
"@radix-ui/react-scroll-area": "^1.1.0",
|
||||
"@radix-ui/react-select": "^2.1.1",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
@ -1621,6 +1622,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-scroll-area": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.1.0.tgz",
|
||||
"integrity": "sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==",
|
||||
"dependencies": {
|
||||
"@radix-ui/number": "1.1.0",
|
||||
"@radix-ui/primitive": "1.1.0",
|
||||
"@radix-ui/react-compose-refs": "1.1.0",
|
||||
"@radix-ui/react-context": "1.1.0",
|
||||
"@radix-ui/react-direction": "1.1.0",
|
||||
"@radix-ui/react-presence": "1.1.0",
|
||||
"@radix-ui/react-primitive": "2.0.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/@radix-ui/react-select/-/react-select-2.1.1.tgz",
|
||||
|
@ -17,6 +17,7 @@
|
||||
"@radix-ui/react-label": "^2.1.0",
|
||||
"@radix-ui/react-progress": "^1.1.0",
|
||||
"@radix-ui/react-radio-group": "^1.2.0",
|
||||
"@radix-ui/react-scroll-area": "^1.1.0",
|
||||
"@radix-ui/react-select": "^2.1.1",
|
||||
"@radix-ui/react-separator": "^1.1.0",
|
||||
"@radix-ui/react-slot": "^1.1.0",
|
||||
|
46
ui/src/components/ui/scroll-area.tsx
Normal file
46
ui/src/components/ui/scroll-area.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import * as React from "react"
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const ScrollArea = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
))
|
||||
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
||||
|
||||
const ScrollBar = React.forwardRef<
|
||||
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
||||
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
>(({ className, orientation = "vertical", ...props }, ref) => (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
ref={ref}
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none select-none transition-colors",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
))
|
||||
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
||||
|
||||
export { ScrollArea, ScrollBar }
|
@ -169,8 +169,20 @@ export default function Dashboard() {
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</header>
|
||||
<main className="flex flex-1 flex-col gap-4 p-4 lg:gap-6 lg:p-6">
|
||||
<main className="flex flex-1 flex-col gap-4 p-4 lg:gap-6 lg:p-6 relative">
|
||||
<Outlet />
|
||||
|
||||
<div className="fixed right-0 bottom-0 w-full flex justify-between p-5">
|
||||
<div className=""></div>
|
||||
<div className="text-muted-foreground text-sm hover:text-stone-900">
|
||||
<a
|
||||
href="https://github.com/usual2970/certimate/releases"
|
||||
target="_blank"
|
||||
>
|
||||
Certimate v0.0.2
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,7 +20,13 @@ import { Tooltip, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { Domain } from "@/domain/domain";
|
||||
import { convertZulu2Beijing, getDate } from "@/lib/time";
|
||||
import { list, remove, save } from "@/repository/domains";
|
||||
import {
|
||||
list,
|
||||
remove,
|
||||
save,
|
||||
subscribeId,
|
||||
unsubscribeId,
|
||||
} from "@/repository/domains";
|
||||
|
||||
import { TooltipContent, TooltipProvider } from "@radix-ui/react-tooltip";
|
||||
import { CircleCheck, CircleX, Earth } from "lucide-react";
|
||||
@ -82,22 +88,25 @@ const Home = () => {
|
||||
|
||||
const handleRightNowClick = async (domain: Domain) => {
|
||||
try {
|
||||
unsubscribeId(domain.id);
|
||||
subscribeId(domain.id, (resp) => {
|
||||
console.log(resp);
|
||||
const updatedDomains = domains.map((domain) => {
|
||||
if (domain.id === resp.id) {
|
||||
return { ...resp };
|
||||
}
|
||||
return domain;
|
||||
});
|
||||
setDomains(updatedDomains);
|
||||
});
|
||||
domain.rightnow = true;
|
||||
const resp = await save(domain);
|
||||
const updatedDomains = domains.map((domain) => {
|
||||
if (domain.id === resp.id) {
|
||||
return { ...resp };
|
||||
}
|
||||
return domain;
|
||||
});
|
||||
setDomains(updatedDomains);
|
||||
|
||||
await save(domain);
|
||||
|
||||
toast.toast({
|
||||
title: "执行成功",
|
||||
description: "执行成功",
|
||||
title: "操作成功",
|
||||
description: "已发起部署,请稍后查看部署日志。",
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate(0);
|
||||
}, 1000);
|
||||
} catch (e) {
|
||||
toast.toast({
|
||||
title: "执行失败",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import DeployProgress from "@/components/certimate/DeployProgress";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
|
||||
import {
|
||||
Sheet,
|
||||
@ -35,7 +36,7 @@ const History = () => {
|
||||
}, [domain]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ScrollArea className="h-[80vh] overflow-hidden">
|
||||
<div className="text-muted-foreground">部署历史</div>
|
||||
{!deployments?.length ? (
|
||||
<>
|
||||
@ -184,7 +185,7 @@ const History = () => {
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -25,3 +25,24 @@ export const save = async (data: Domain) => {
|
||||
export const remove = async (id: string) => {
|
||||
return await getPb().collection("domains").delete(id);
|
||||
};
|
||||
|
||||
type Callback = (data: Domain) => void;
|
||||
export const subscribeId = (id: string, callback: Callback) => {
|
||||
return getPb()
|
||||
.collection("domains")
|
||||
.subscribe<Domain>(
|
||||
id,
|
||||
(e) => {
|
||||
if (e.action === "update") {
|
||||
callback(e.record);
|
||||
}
|
||||
},
|
||||
{
|
||||
expand: "lastDeployment",
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const unsubscribeId = (id: string) => {
|
||||
getPb().collection("domains").unsubscribe(id);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user