feat: wrap message by fluent ui toast
This commit is contained in:
parent
77dff6649d
commit
b2c13508f4
@ -7,6 +7,7 @@ export interface Resp<T> {
|
|||||||
data: T;
|
data: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 类型保护函数
|
// 类型保护函数
|
||||||
function isResp<T>(obj: any): obj is Resp<T> {
|
function isResp<T>(obj: any): obj is Resp<T> {
|
||||||
return (
|
return (
|
||||||
@ -18,23 +19,32 @@ function isResp<T>(obj: any): obj is Resp<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const invoke = async <T>(path: string, req: any): Promise<Resp<T>> => {
|
export async function Dial<T>(path: string, req: any = null): Promise<Resp<T>> {
|
||||||
const bs = JSON.stringify(req)
|
const bs = JSON.stringify(req)
|
||||||
console.log(`[DEBUG] invoke req: path = ${path}, req =`, req)
|
console.log(`[DEBUG] invoke req: path = ${path}, req =`, req)
|
||||||
const res = await Invoke(path, bs)
|
|
||||||
console.log(`[DEBUG] invoke res: path = ${path}, res =`, res)
|
let result: Resp<T>;
|
||||||
|
let ok = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const res = await Invoke(path, bs)
|
||||||
const parsed = JSON.parse(res);
|
const parsed = JSON.parse(res);
|
||||||
if (isResp<T>(parsed)) {
|
if (isResp<T>(parsed)) {
|
||||||
return parsed;
|
result = parsed;
|
||||||
|
ok = true
|
||||||
} else {
|
} else {
|
||||||
console.error('[ERROR] invoke: resp not valid =', res)
|
console.error('[ERROR] invoke: resp not valid =', res)
|
||||||
throw new Error('Parsed response does not match Resp<T> structure');
|
result = {status: 500, msg: "发生错误(0)", err: res} as Resp<T>;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[ERROR] invoke: resp parse err, err = ${error}, res =`, res);
|
result = {status: 500, msg: "发生错误(-1)", err: "backend method(Invoke) not found in window"} as Resp<T>;
|
||||||
throw new Error('Invalid response format');
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export const Dial = invoke;
|
if (ok) {
|
||||||
|
console.log(`[DEBUG] invoke res: path = ${path}, res =`, result)
|
||||||
|
} else {
|
||||||
|
console.error(`[ERROR] invoke res: path = ${path}, res =`, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
9
frontend/src/interfaces/connection.ts
Normal file
9
frontend/src/interfaces/connection.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface Connection {
|
||||||
|
id: number;
|
||||||
|
created_at: number;
|
||||||
|
updated_at: number;
|
||||||
|
deleted_at: number;
|
||||||
|
name: string;
|
||||||
|
endpoint: string;
|
||||||
|
active: boolean;
|
||||||
|
}
|
@ -1,22 +1,25 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {createRoot} from 'react-dom/client'
|
import {createRoot} from 'react-dom/client'
|
||||||
import './style.css'
|
import './style.css'
|
||||||
import { FluentProvider, webLightTheme } from '@fluentui/react-components';
|
import {FluentProvider, webLightTheme} from '@fluentui/react-components';
|
||||||
import {createBrowserRouter,RouterProvider} from "react-router-dom";
|
import {createBrowserRouter, RouterProvider} from "react-router-dom";
|
||||||
import Home from "./page/home/home";
|
import Home from "./page/home/home";
|
||||||
import Connection from "./page/connection/connection";
|
import Connection from "./page/connection/connection";
|
||||||
|
import {ToastProvider} from "./message";
|
||||||
|
|
||||||
const container = document.getElementById('root')
|
const container = document.getElementById('root')
|
||||||
|
|
||||||
const root = createRoot(container!)
|
const root = createRoot(container!)
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{path:'/', element: <Home />},
|
{path: '/', element: <Home/>},
|
||||||
{path:'/connection', element: <Connection />},
|
{path: '/connection', element: <Connection/>},
|
||||||
])
|
])
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<FluentProvider theme={webLightTheme}>
|
<FluentProvider theme={webLightTheme}>
|
||||||
<RouterProvider router={router} />
|
<ToastProvider>
|
||||||
|
<RouterProvider router={router}/>
|
||||||
|
</ToastProvider>
|
||||||
</FluentProvider>,
|
</FluentProvider>,
|
||||||
);
|
);
|
||||||
|
37
frontend/src/message.tsx
Normal file
37
frontend/src/message.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {createContext, FC, ReactNode, useContext} from "react";
|
||||||
|
import {Toast, Toaster, ToastTitle, useId, useToastController} from "@fluentui/react-components";
|
||||||
|
|
||||||
|
|
||||||
|
interface ToastContextType {
|
||||||
|
dispatchMessage: (content: string, type: "success" | "error" | "warning" | "info") => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ToastContext = createContext<ToastContextType | undefined>(undefined);
|
||||||
|
|
||||||
|
export const ToastProvider: FC<{ children: ReactNode }> = ({children}) => {
|
||||||
|
|
||||||
|
const toasterId = useId("toaster");
|
||||||
|
const {dispatchToast} = useToastController(toasterId);
|
||||||
|
|
||||||
|
const dispatchMessage = (content: string, type: "success" | "error" | "warning" | "info" = "info") => {
|
||||||
|
dispatchToast(
|
||||||
|
<Toast>
|
||||||
|
<ToastTitle>{content}</ToastTitle>
|
||||||
|
</Toast>,
|
||||||
|
{position: "top-end", intent: type}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <ToastContext.Provider value={{dispatchMessage}}>
|
||||||
|
{children}
|
||||||
|
<Toaster toasterId={toasterId}/>
|
||||||
|
</ToastContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useToast = () => {
|
||||||
|
const context = useContext(ToastContext);
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useToast must be used within a ToastProvider");
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
@ -3,23 +3,28 @@ import {
|
|||||||
useId,
|
useId,
|
||||||
Button,
|
Button,
|
||||||
FieldProps,
|
FieldProps,
|
||||||
useToastController,
|
Spinner
|
||||||
Toast,
|
|
||||||
ToastTitle,
|
|
||||||
ToastIntent,
|
|
||||||
Toaster
|
|
||||||
} from "@fluentui/react-components";
|
} from "@fluentui/react-components";
|
||||||
import {Field, Input} from "@fluentui/react-components";
|
import {Field, Input} from "@fluentui/react-components";
|
||||||
import {useNavigate} from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
import {Dial} from "../../api";
|
import {Dial} from "../../api";
|
||||||
|
import {useToast} from "../../message";
|
||||||
|
import {CheckmarkFilled, DismissRegular} from "@fluentui/react-icons";
|
||||||
|
|
||||||
|
|
||||||
const Connection = (props: Partial<FieldProps>) => {
|
const Connection = (props: Partial<FieldProps>) => {
|
||||||
|
const { dispatchMessage } = useToast();
|
||||||
const toasterId = useId("toaster");
|
|
||||||
const {dispatchToast} = useToastController(toasterId);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [testLoading, setTestLoading] = useState<"initial" | "loading" | "success" | "error">("initial");
|
||||||
|
const buttonIcon =
|
||||||
|
testLoading === "loading" ? (
|
||||||
|
<Spinner size="tiny"/>
|
||||||
|
) : testLoading === "success" ? (
|
||||||
|
<CheckmarkFilled/>
|
||||||
|
) : testLoading === "error" ? (
|
||||||
|
<DismissRegular/>
|
||||||
|
) : null;
|
||||||
const [value, setValue] = useState<{ name: string, endpoint: string, access: string, key: string }>({
|
const [value, setValue] = useState<{ name: string, endpoint: string, access: string, key: string }>({
|
||||||
name: '',
|
name: '',
|
||||||
endpoint: '',
|
endpoint: '',
|
||||||
@ -28,16 +33,24 @@ const Connection = (props: Partial<FieldProps>) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
const val = JSON.stringify(value);
|
setTestLoading("loading")
|
||||||
console.log('[DEBUG] connection.test: value =', val)
|
|
||||||
Dial<string>("/api/connection/test", value).then(res => {
|
Dial<string>("/api/connection/test", value).then(res => {
|
||||||
|
let status: "success" | "error" = "error"
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
dispatchToast(
|
status = "success"
|
||||||
<Toast>
|
}
|
||||||
<ToastTitle>连接成功!</ToastTitle>
|
|
||||||
</Toast>,
|
setTestLoading(status);
|
||||||
{position: "top-end", intent: "success"}
|
|
||||||
)
|
dispatchMessage(res.msg, status)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function create() {
|
||||||
|
Dial<unknown>("/api/connection/create", value).then(res => {
|
||||||
|
dispatchMessage(res.msg, res.status === 200?"success":"error");
|
||||||
|
if (res.status === 200) {
|
||||||
|
navigate("/");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -94,17 +107,17 @@ const Connection = (props: Partial<FieldProps>) => {
|
|||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div className='connection-form-field connection-form-field-actions'>
|
<div className='connection-form-field connection-form-field-actions'>
|
||||||
<Button appearance='transparent' onClick={() => test()}>测试连接</Button>
|
<Button appearance='transparent' icon={buttonIcon} onClick={() => test()}>测试连接</Button>
|
||||||
<div style={{marginLeft: 'auto'}}>
|
<div style={{marginLeft: 'auto'}}>
|
||||||
<Button style={{marginRight: '20px'}} className='connection-form-field-actions-cancel'
|
<Button style={{marginRight: '20px'}} className='connection-form-field-actions-cancel'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate("/")
|
navigate("/")
|
||||||
}}>取消</Button>
|
}}>取消</Button>
|
||||||
<Button className='connection-form-field-actions-confirm' appearance='primary'>新建</Button>
|
<Button className='connection-form-field-actions-confirm' appearance='primary'
|
||||||
|
onClick={() => create()}>新建</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Toaster toasterId={toasterId}/>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {useState} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
import './home.css';
|
import './home.css';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@ -6,25 +6,45 @@ import {
|
|||||||
import {
|
import {
|
||||||
CloudAddFilled, DismissRegular
|
CloudAddFilled, DismissRegular
|
||||||
} from "@fluentui/react-icons";
|
} from "@fluentui/react-icons";
|
||||||
import { useNavigate } from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
|
import {Dial} from "../../api";
|
||||||
|
import {useToast} from "../../message";
|
||||||
|
import {Connection} from "../../interfaces/connection";
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
|
const {dispatchMessage} = useToast();
|
||||||
const [connectionFilterKeywords, setConnectionFilterKeywords] = useState<string>('');
|
const [connectionFilterKeywords, setConnectionFilterKeywords] = useState<string>('');
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [connectionList, setConnectionList] = useState<Connection[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Dial<{ list: Connection[] }>("/api/connection/list").then(res => {
|
||||||
|
dispatchMessage(res.msg, res.status === 200 ? "success" : "error");
|
||||||
|
if (res.status === 200) {
|
||||||
|
setConnectionList(res.data.list)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
<Button appearance="primary" icon={<CloudAddFilled />} onClick={() => {navigate("/connection")}}>
|
<Button appearance="primary" icon={<CloudAddFilled/>} onClick={() => {
|
||||||
新建连接
|
navigate("/connection")
|
||||||
</Button>
|
}}>
|
||||||
|
新建连接
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="body">
|
<div className="body">
|
||||||
<div className="body-connections">
|
<div className="body-connections">
|
||||||
<div className="body-connections-search">
|
<div className="body-connections-search">
|
||||||
<input className="body-connections-search-input" type={"text"} placeholder="搜索连接" value={connectionFilterKeywords} onChange={(e) => setConnectionFilterKeywords(e.target.value)} />
|
<input className="body-connections-search-input" type={"text"} placeholder="搜索连接"
|
||||||
<div className="body-connections-search-dismiss" onClick={() => {setConnectionFilterKeywords('')}}>
|
value={connectionFilterKeywords}
|
||||||
<DismissRegular />
|
onChange={(e) => setConnectionFilterKeywords(e.target.value)}/>
|
||||||
|
<div className="body-connections-search-dismiss" onClick={() => {
|
||||||
|
setConnectionFilterKeywords('')
|
||||||
|
}}>
|
||||||
|
<DismissRegular/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="body-connections-list"></div>
|
<div className="body-connections-list"></div>
|
||||||
|
27
go.mod
27
go.mod
@ -1,4 +1,4 @@
|
|||||||
module nf-disk
|
module github.com/loveuer/nf-disk
|
||||||
|
|
||||||
go 1.21
|
go 1.21
|
||||||
|
|
||||||
@ -9,8 +9,15 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/config v1.27.38
|
github.com/aws/aws-sdk-go-v2/config v1.27.38
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.36
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.36
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2
|
||||||
|
github.com/aws/smithy-go v1.21.0
|
||||||
|
github.com/loveuer/go-sqlite3 v1.0.2
|
||||||
github.com/loveuer/nf v0.2.11
|
github.com/loveuer/nf v0.2.11
|
||||||
|
github.com/ncruces/go-sqlite3/gormlite v0.18.4
|
||||||
|
github.com/psanford/httpreadat v0.1.0
|
||||||
github.com/wailsapp/wails/v2 v2.9.2
|
github.com/wailsapp/wails/v2 v2.9.2
|
||||||
|
gorm.io/driver/mysql v1.5.7
|
||||||
|
gorm.io/driver/postgres v1.5.9
|
||||||
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -27,13 +34,19 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.23.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.23.2 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.31.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.31.2 // indirect
|
||||||
github.com/aws/smithy-go v1.21.0 // indirect
|
|
||||||
github.com/bep/debounce v1.2.1 // indirect
|
github.com/bep/debounce v1.2.1 // indirect
|
||||||
github.com/fatih/color v1.17.0 // indirect
|
github.com/fatih/color v1.17.0 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 // indirect
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/labstack/echo/v4 v4.10.2 // indirect
|
github.com/labstack/echo/v4 v4.10.2 // indirect
|
||||||
github.com/labstack/gommon v0.4.0 // indirect
|
github.com/labstack/gommon v0.4.0 // indirect
|
||||||
github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
|
github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
|
||||||
@ -42,20 +55,24 @@ require (
|
|||||||
github.com/leaanthony/u v1.1.0 // indirect
|
github.com/leaanthony/u v1.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/ncruces/go-sqlite3 v0.18.4 // indirect
|
||||||
|
github.com/ncruces/julianday v1.0.0 // indirect
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/samber/lo v1.38.1 // indirect
|
github.com/samber/lo v1.38.1 // indirect
|
||||||
|
github.com/tetratelabs/wazero v1.8.0 // indirect
|
||||||
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
github.com/wailsapp/go-webview2 v1.0.16 // indirect
|
github.com/wailsapp/go-webview2 v1.0.16 // indirect
|
||||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
golang.org/x/crypto v0.23.0 // indirect
|
golang.org/x/crypto v0.27.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
|
golang.org/x/text v0.18.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// replace github.com/wailsapp/wails/v2 v2.9.2 => C:\Users\loveuer\go\pkg\mod
|
// replace github.com/wailsapp/wails/v2 v2.9.2 => C:\Users\loveuer\go\pkg\mod
|
||||||
|
48
go.sum
48
go.sum
@ -43,12 +43,26 @@ github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
|||||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
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/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
|
||||||
|
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||||
|
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.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
|
||||||
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
|
||||||
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||||
@ -64,6 +78,8 @@ github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/
|
|||||||
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
|
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
|
||||||
github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
|
github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
|
||||||
github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
|
||||||
|
github.com/loveuer/go-sqlite3 v1.0.2 h1:kcENqm6mt0wPH/N9Sw+6UC74qtU8o+aMEO04I62pjDE=
|
||||||
|
github.com/loveuer/go-sqlite3 v1.0.2/go.mod h1:8+45etSlBYCtYP/ThX/e1wLgG+x6G6oXck2FhjC57tA=
|
||||||
github.com/loveuer/nf v0.2.11 h1:W775exDO8eNAHT45WDhXekMYCuWahOW9t1aVmGh3u1o=
|
github.com/loveuer/nf v0.2.11 h1:W775exDO8eNAHT45WDhXekMYCuWahOW9t1aVmGh3u1o=
|
||||||
github.com/loveuer/nf v0.2.11/go.mod h1:M6reF17/kJBis30H4DxR5hrtgo/oJL4AV4cBe4HzJLw=
|
github.com/loveuer/nf v0.2.11/go.mod h1:M6reF17/kJBis30H4DxR5hrtgo/oJL4AV4cBe4HzJLw=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
@ -75,21 +91,32 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
|||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/ncruces/go-sqlite3 v0.18.4 h1:Je8o3y33MDwPYY/Cacas8yCsuoUzpNY/AgoSlN2ekyE=
|
||||||
|
github.com/ncruces/go-sqlite3 v0.18.4/go.mod h1:4HLag13gq1k10s4dfGBhMfRVsssJRT9/5hYqVM9RUYo=
|
||||||
|
github.com/ncruces/go-sqlite3/gormlite v0.18.4 h1:NdZkzS7SkcGlUafCmF6/fpqS/JkhxXP/DRPDYmSVdL4=
|
||||||
|
github.com/ncruces/go-sqlite3/gormlite v0.18.4/go.mod h1:laAntS4laxUO47GmxhIhSeJPrRSPF9TdsOQhaqlIifI=
|
||||||
|
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
||||||
|
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/psanford/httpreadat v0.1.0 h1:VleW1HS2zO7/4c7c7zNl33fO6oYACSagjJIyMIwZLUE=
|
||||||
|
github.com/psanford/httpreadat v0.1.0/go.mod h1:Zg7P+TlBm3bYbyHTKv/EdtSJZn3qwbPwpfZ/I9GKCRE=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
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/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g=
|
||||||
|
github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||||
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
|
github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
|
||||||
github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
@ -103,13 +130,15 @@ github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhw
|
|||||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||||
github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
|
github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
|
||||||
github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs=
|
github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||||
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -120,15 +149,22 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8=
|
||||||
|
gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
32
internal/api/api.go
Normal file
32
internal/api/api.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/loveuer/nf-disk/internal/handler"
|
||||||
|
"github.com/loveuer/nf-disk/ndh"
|
||||||
|
"github.com/loveuer/nf/nft/log"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
apis = make(map[string]ndh.Handler)
|
||||||
|
)
|
||||||
|
|
||||||
|
func register(path string, h ndh.Handler) {
|
||||||
|
name := reflect.ValueOf(h).String()
|
||||||
|
log.Info("app register: path = %s, name = %s", path, name)
|
||||||
|
apis[path] = h
|
||||||
|
}
|
||||||
|
|
||||||
|
func Resolve(path string) (ndh.Handler, bool) {
|
||||||
|
h, ok := apis[path]
|
||||||
|
return h, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(ctx context.Context) error {
|
||||||
|
register("/api/connection/test", handler.ConnectionTest)
|
||||||
|
register("/api/connection/create", handler.ConnectionCreate)
|
||||||
|
register("/api/connection/list", handler.ConnectionList)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/loveuer/nf/nft/log"
|
|
||||||
"nf-disk/internal/handler"
|
|
||||||
"nf-disk/internal/ndh"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (a *App) register(path string, handler ndh.Handler) {
|
|
||||||
name := reflect.ValueOf(handler).String()
|
|
||||||
log.Info("app register: path = %s, name = %s", path, name)
|
|
||||||
a.handlers[path] = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func initApi(a *App) {
|
|
||||||
a.register("/api/connection/test", handler.ConnectionTest)
|
|
||||||
}
|
|
@ -1,13 +1,13 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"github.com/loveuer/nf-disk/internal/api"
|
||||||
|
"github.com/loveuer/nf-disk/internal/db"
|
||||||
|
"github.com/loveuer/nf-disk/internal/model"
|
||||||
|
"github.com/loveuer/nf-disk/internal/tool"
|
||||||
|
"github.com/loveuer/nf-disk/ndh"
|
||||||
"github.com/loveuer/nf/nft/log"
|
"github.com/loveuer/nf/nft/log"
|
||||||
"nf-disk/internal/ndh"
|
|
||||||
"nf-disk/internal/tool"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
@ -22,24 +22,11 @@ func NewApp() *App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Startup(ctx context.Context) {
|
func (a *App) Startup(ctx context.Context) {
|
||||||
a.ctx = ctx
|
|
||||||
log.Info("app startup!!!")
|
log.Info("app startup!!!")
|
||||||
initApi(a)
|
|
||||||
}
|
a.ctx = ctx
|
||||||
|
|
||||||
func (a *App) Invoke(path string, req string) (res string) {
|
tool.Must(db.Init(ctx, "sqlite::memory", db.OptSqliteByMem(nil)))
|
||||||
log.Info("app invoke: path = %s, req = %s", path, req)
|
tool.Must(model.Init(db.Default.Session()))
|
||||||
handler, ok := a.handlers[path]
|
tool.Must(api.Init(ctx))
|
||||||
if !ok {
|
|
||||||
return `{"err": "handler not found", "status": 404}`
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
ctx := ndh.NewCtx(tool.Timeout(), json.NewDecoder(strings.NewReader(req)), &buf)
|
|
||||||
|
|
||||||
if err := handler(ctx); err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String()
|
|
||||||
}
|
}
|
||||||
|
51
internal/controller/invoke.go
Normal file
51
internal/controller/invoke.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/loveuer/nf-disk/internal/api"
|
||||||
|
"github.com/loveuer/nf-disk/internal/opt"
|
||||||
|
"github.com/loveuer/nf-disk/internal/tool"
|
||||||
|
"github.com/loveuer/nf-disk/ndh"
|
||||||
|
"github.com/loveuer/nf/nft/log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleError(err error) string {
|
||||||
|
bs, _ := json.Marshal(map[string]any{
|
||||||
|
"err": err.Error(),
|
||||||
|
"msg": opt.Msg500,
|
||||||
|
"status": 500,
|
||||||
|
})
|
||||||
|
|
||||||
|
return string(bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleNotFound(path string) string {
|
||||||
|
bs, _ := json.Marshal(map[string]any{
|
||||||
|
"err": fmt.Sprintf("path not found, path: %s", path),
|
||||||
|
"msg": opt.Msg500,
|
||||||
|
"status": 404,
|
||||||
|
})
|
||||||
|
|
||||||
|
return string(bs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Invoke(path string, req string) (res string) {
|
||||||
|
log.Info("app invoke: path = %s, req = %s", path, req)
|
||||||
|
handler, ok := api.Resolve(path)
|
||||||
|
if !ok {
|
||||||
|
log.Warn("app invoke: path not found, path = %s", path)
|
||||||
|
return handleNotFound(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
ctx := ndh.NewCtx(tool.TimeoutCtx(a.ctx), strings.NewReader(req), &buf)
|
||||||
|
|
||||||
|
if err := handler(ctx); err != nil {
|
||||||
|
return handleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
61
internal/db/client.go
Normal file
61
internal/db/client.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/loveuer/nf-disk/internal/opt"
|
||||||
|
"github.com/loveuer/nf-disk/internal/tool"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Default *Client
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
ctx context.Context
|
||||||
|
cli *gorm.DB
|
||||||
|
ttype string
|
||||||
|
cfgSqlite *cfgSqlite
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Type() string {
|
||||||
|
return c.ttype
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Session(ctxs ...context.Context) *gorm.DB {
|
||||||
|
var ctx context.Context
|
||||||
|
if len(ctxs) > 0 && ctxs[0] != nil {
|
||||||
|
ctx = ctxs[0]
|
||||||
|
} else {
|
||||||
|
ctx = tool.Timeout(30)
|
||||||
|
}
|
||||||
|
|
||||||
|
session := c.cli.Session(&gorm.Session{Context: ctx})
|
||||||
|
|
||||||
|
if opt.Debug {
|
||||||
|
session = session.Debug()
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Close() {
|
||||||
|
d, _ := c.cli.DB()
|
||||||
|
d.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump
|
||||||
|
// Only for sqlite with mem mode to dump data to bytes(io.Reader)
|
||||||
|
func (c *Client) Dump() (reader io.ReadSeekCloser, ok bool) {
|
||||||
|
if c.ttype != "sqlite" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.cfgSqlite.fsType != "mem" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.cfgSqlite.memDump.Dump(), true
|
||||||
|
}
|
44
internal/db/db_test.go
Normal file
44
internal/db/db_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOpen(t *testing.T) {
|
||||||
|
myClient, err := New(context.TODO(), "sqlite::", OptSqliteByMem())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("TestOpen: New err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Start struct {
|
||||||
|
Id int `json:"id" gorm:"column:id;primaryKey"`
|
||||||
|
Name string `json:"name" gorm:"column:name"`
|
||||||
|
Dis float64 `json:"dis" gorm:"column:dis"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = myClient.Session().AutoMigrate(&Start{}); err != nil {
|
||||||
|
t.Fatalf("TestOpen: AutoMigrate err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = myClient.Session().Create(&Start{Name: "sun", Dis: 6631.76}).Error; err != nil {
|
||||||
|
t.Fatalf("TestOpen: Create err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = myClient.Session().Create(&Start{Name: "mar", Dis: 786.35}).Error; err != nil {
|
||||||
|
t.Fatalf("TestOpen: Create err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reader, ok := myClient.Dump(); ok {
|
||||||
|
bs, err := io.ReadAll(reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("TestOpen: ReadAll err = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.WriteFile("dump.db", bs, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
myClient.Close()
|
||||||
|
}
|
54
internal/db/init.go
Normal file
54
internal/db/init.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(ctx context.Context, uri string, opts ...Option) (*Client, error) {
|
||||||
|
strs := strings.Split(uri, "::")
|
||||||
|
|
||||||
|
if len(strs) != 2 {
|
||||||
|
return nil, fmt.Errorf("db.Init: opt db uri invalid: %s", uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Client{ttype: strs[0], cfgSqlite: &cfgSqlite{fsType: "file"}}
|
||||||
|
for _, f := range opts {
|
||||||
|
f(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
dsn = strs[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
switch strs[0] {
|
||||||
|
case "sqlite":
|
||||||
|
err = openSqlite(c, dsn)
|
||||||
|
case "mysql":
|
||||||
|
c.cli, err = gorm.Open(mysql.Open(dsn))
|
||||||
|
case "postgres":
|
||||||
|
c.cli, err = gorm.Open(postgres.Open(dsn))
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("db type only support: [sqlite, mysql, postgres], unsupported db type: %s", strs[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("db.Init: open %s with dsn:%s, err: %w", strs[0], dsn, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(ctx context.Context, uri string, opts ...Option) (err error) {
|
||||||
|
if Default, err = New(ctx, uri, opts...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
27
internal/db/option.go
Normal file
27
internal/db/option.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/loveuer/go-sqlite3/embed"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option func(c *Client)
|
||||||
|
|
||||||
|
func OptSqliteByUrl(address string) Option {
|
||||||
|
return func(c *Client) {
|
||||||
|
c.cfgSqlite.fsType = "url"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SqliteMemDumper interface {
|
||||||
|
Dump() io.ReadSeekCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果传 nil 则表示新生成一个 mem 的 sqlite
|
||||||
|
// 如果传了一个合法的 reader 则会从这个 reader 初始化 database
|
||||||
|
func OptSqliteByMem(reader io.ReadCloser) Option {
|
||||||
|
return func(c *Client) {
|
||||||
|
c.cfgSqlite.memReader = reader
|
||||||
|
c.cfgSqlite.fsType = "mem"
|
||||||
|
}
|
||||||
|
}
|
63
internal/db/sqlite.go
Normal file
63
internal/db/sqlite.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/loveuer/go-sqlite3/embed"
|
||||||
|
"github.com/loveuer/go-sqlite3/vfs/memdb"
|
||||||
|
"github.com/loveuer/go-sqlite3/vfs/readervfs"
|
||||||
|
"github.com/ncruces/go-sqlite3/gormlite"
|
||||||
|
"github.com/psanford/httpreadat"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type cfgSqlite struct {
|
||||||
|
fsType string // file, mem(bytes), url
|
||||||
|
memDump *memdb.MemDB
|
||||||
|
memReader io.ReadCloser
|
||||||
|
}
|
||||||
|
|
||||||
|
func openSqlite(c *Client, dsn string) error {
|
||||||
|
var (
|
||||||
|
db gorm.Dialector
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch c.cfgSqlite.fsType {
|
||||||
|
case "file":
|
||||||
|
db = gormlite.Open("file:" + dsn)
|
||||||
|
case "url":
|
||||||
|
name := fmt.Sprintf("%d.db", time.Now().UnixNano())
|
||||||
|
readervfs.Create(name, httpreadat.New(dsn))
|
||||||
|
uri := fmt.Sprintf("file:%s?vfs=reader", name)
|
||||||
|
db = gormlite.Open(uri)
|
||||||
|
case "mem":
|
||||||
|
var (
|
||||||
|
bs []byte
|
||||||
|
name = fmt.Sprintf("%d.db", time.Now().UnixNano())
|
||||||
|
)
|
||||||
|
|
||||||
|
if c.cfgSqlite.memReader == nil {
|
||||||
|
bs = make([]byte, 0)
|
||||||
|
} else {
|
||||||
|
if bs, err = io.ReadAll(c.cfgSqlite.memReader); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memDump := memdb.Create(name, bs)
|
||||||
|
c.cfgSqlite.memDump = memDump
|
||||||
|
uri := fmt.Sprintf("file:/%s?vfs=memdb", name)
|
||||||
|
db = gormlite.Open(uri)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported sqlite fs type: %s", c.cfgSqlite.fsType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.cli, err = gorm.Open(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"nf-disk/internal/ndh"
|
"github.com/loveuer/nf-disk/internal/db"
|
||||||
"nf-disk/internal/s3"
|
"github.com/loveuer/nf-disk/internal/manager"
|
||||||
|
"github.com/loveuer/nf-disk/internal/model"
|
||||||
|
"github.com/loveuer/nf-disk/internal/s3"
|
||||||
|
"github.com/loveuer/nf-disk/ndh"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConnectionTest(c *ndh.Ctx) error {
|
func ConnectionTest(c *ndh.Ctx) error {
|
||||||
@ -30,5 +33,69 @@ func ConnectionTest(c *ndh.Ctx) error {
|
|||||||
return c.Send500(err.Error(), "连接失败")
|
return c.Send500(err.Error(), "连接失败")
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Send200("test success")
|
return c.Send200("连接测试成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectionCreate(c *ndh.Ctx) error {
|
||||||
|
type Req struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
Access string `json:"access"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
Force bool `json:"force"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
req = new(Req)
|
||||||
|
client *s3.Client
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = c.ReqParse(req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Endpoint == "" || req.Access == "" || req.Key == "" {
|
||||||
|
return c.Send400(nil, "endpoint, secret_access, secret_key 是必填项")
|
||||||
|
}
|
||||||
|
|
||||||
|
if client, err = s3.New(c.Context(), req.Endpoint, req.Access, req.Key); err != nil {
|
||||||
|
return c.Send500(err.Error(), "连接失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Name == "" {
|
||||||
|
req.Name = req.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
connection := &model.Connection{
|
||||||
|
Name: req.Name,
|
||||||
|
Endpoint: req.Endpoint,
|
||||||
|
Access: req.Access,
|
||||||
|
Key: req.Key,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = connection.Create(db.Default.Session()); err != nil {
|
||||||
|
return c.Send500(err.Error(), "创建连接失败(1)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = manager.Register(connection, client); err != nil {
|
||||||
|
return c.Send500(err.Error(), "创建连接失败(2)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Send200(connection, "创建连接成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectionList(c *ndh.Ctx) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
list = make([]*model.Connection, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
if err = db.Default.Session().Model(&model.Connection{}).
|
||||||
|
Find(&list).
|
||||||
|
Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Send200(map[string]any{"list": list})
|
||||||
}
|
}
|
||||||
|
18
internal/manager/manager.go
Normal file
18
internal/manager/manager.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/loveuer/nf-disk/internal/model"
|
||||||
|
"github.com/loveuer/nf-disk/internal/s3"
|
||||||
|
"github.com/loveuer/nf/nft/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Init(ctx context.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Register(m *model.Connection, c *s3.Client) error {
|
||||||
|
log.Debug("manager: register connection-client: id = %d, name = %s", m.Id, m.Name)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
9
internal/model/init.go
Normal file
9
internal/model/init.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
func Init(tx *gorm.DB) error {
|
||||||
|
return tx.AutoMigrate(
|
||||||
|
&Connection{},
|
||||||
|
)
|
||||||
|
}
|
18
internal/model/s3.go
Normal file
18
internal/model/s3.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
Id uint64 `json:"id" gorm:"primaryKey;column:id"`
|
||||||
|
CreatedAt int64 `json:"created_at" gorm:"column:created_at;autoCreateTime:milli"`
|
||||||
|
UpdatedAt int64 `json:"updated_at" gorm:"column:updated_at;autoUpdateTime:milli"`
|
||||||
|
DeletedAt int64 `json:"deleted_at" gorm:"index;column:deleted_at;default:0"`
|
||||||
|
Name string `json:"name" gorm:"unique;column:name"`
|
||||||
|
Endpoint string `json:"endpoint" gorm:"column:endpoint"`
|
||||||
|
Access string `json:"access" gorm:"column:access"`
|
||||||
|
Key string `json:"key" gorm:"column:key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Create(tx *gorm.DB) error {
|
||||||
|
return tx.Create(c).Error
|
||||||
|
}
|
@ -1,5 +1,11 @@
|
|||||||
package opt
|
package opt
|
||||||
|
|
||||||
|
const (
|
||||||
|
Msg200 = "操作成功"
|
||||||
|
Msg400 = "输入不正确"
|
||||||
|
Msg500 = "发生错误"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Debug bool
|
Debug bool
|
||||||
)
|
)
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
"github.com/aws/aws-sdk-go-v2/credentials"
|
"github.com/aws/aws-sdk-go-v2/credentials"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
smithyendpoints "github.com/aws/smithy-go/endpoints"
|
smithyendpoints "github.com/aws/smithy-go/endpoints"
|
||||||
|
"github.com/loveuer/nf-disk/internal/tool"
|
||||||
"github.com/loveuer/nf/nft/log"
|
"github.com/loveuer/nf/nft/log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"nf-disk/internal/tool"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type resolverV2 struct{}
|
type resolverV2 struct{}
|
||||||
|
11
internal/tool/must.go
Normal file
11
internal/tool/must.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package tool
|
||||||
|
|
||||||
|
import "github.com/loveuer/nf/nft/log"
|
||||||
|
|
||||||
|
func Must(errs ...error) {
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
main.go
2
main.go
@ -3,8 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"flag"
|
"flag"
|
||||||
|
"github.com/loveuer/nf-disk/internal/controller"
|
||||||
"github.com/loveuer/nf/nft/nfctl/opt"
|
"github.com/loveuer/nf/nft/nfctl/opt"
|
||||||
"nf-disk/internal/controller"
|
|
||||||
|
|
||||||
"github.com/loveuer/nf/nft/log"
|
"github.com/loveuer/nf/nft/log"
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
|
@ -8,11 +8,11 @@ import (
|
|||||||
|
|
||||||
type Ctx struct {
|
type Ctx struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
req *json.Decoder
|
req io.Reader
|
||||||
res io.Writer
|
res io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCtx(ctx context.Context, req *json.Decoder, res io.Writer) *Ctx {
|
func NewCtx(ctx context.Context, req io.Reader, res io.Writer) *Ctx {
|
||||||
return &Ctx{
|
return &Ctx{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
req: req,
|
req: req,
|
||||||
@ -29,7 +29,7 @@ func (c *Ctx) Write(bs []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ctx) ReqParse(req any) error {
|
func (c *Ctx) ReqParse(req any) error {
|
||||||
return c.req.Decode(req)
|
return json.NewDecoder(c.req).Decode(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ctx) Send200(data any, msg ...string) error {
|
func (c *Ctx) Send200(data any, msg ...string) error {
|
Loading…
x
Reference in New Issue
Block a user