feat: support ssl connection
This commit is contained in:
parent
444d0ea199
commit
2db858ba9e
27
app.go
27
app.go
|
@ -1,27 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// App struct
|
|
||||||
type App struct {
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewApp creates a new App application struct
|
|
||||||
func NewApp() *App {
|
|
||||||
return &App{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// startup is called when the app starts. The context is saved
|
|
||||||
// so we can call the runtime methods
|
|
||||||
func (a *App) startup(ctx context.Context) {
|
|
||||||
a.ctx = ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// Greet returns a greeting for the given name
|
|
||||||
func (a *App) Greet(name string) string {
|
|
||||||
return fmt.Sprintf("Hello %s, It's show time!", name)
|
|
||||||
}
|
|
|
@ -2,10 +2,11 @@ package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -115,6 +116,39 @@ func (c *connectionService) buildOption(config types.ConnectionConfig) (*redis.O
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
if config.SSL.Enable {
|
||||||
|
// setup tls config
|
||||||
|
var certs []tls.Certificate
|
||||||
|
if len(config.SSL.CertFile) > 0 && len(config.SSL.KeyFile) > 0 {
|
||||||
|
if cert, err := tls.LoadX509KeyPair(config.SSL.CertFile, config.SSL.KeyFile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
certs = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var caCertPool *x509.CertPool
|
||||||
|
if len(config.SSL.CAFile) > 0 {
|
||||||
|
ca, err := os.ReadFile(config.SSL.CAFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
caCertPool = x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(ca)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(certs) <= 0 {
|
||||||
|
return nil, errors.New("tls config error")
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig = &tls.Config{
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
InsecureSkipVerify: false,
|
||||||
|
Certificates: certs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
option := &redis.Options{
|
option := &redis.Options{
|
||||||
ClientName: config.Name,
|
ClientName: config.Name,
|
||||||
Addr: fmt.Sprintf("%s:%d", config.Addr, config.Port),
|
Addr: fmt.Sprintf("%s:%d", config.Addr, config.Port),
|
||||||
|
@ -123,6 +157,7 @@ func (c *connectionService) buildOption(config types.ConnectionConfig) (*redis.O
|
||||||
DialTimeout: time.Duration(config.ConnTimeout) * time.Second,
|
DialTimeout: time.Duration(config.ConnTimeout) * time.Second,
|
||||||
ReadTimeout: time.Duration(config.ExecTimeout) * time.Second,
|
ReadTimeout: time.Duration(config.ExecTimeout) * time.Second,
|
||||||
WriteTimeout: time.Duration(config.ExecTimeout) * time.Second,
|
WriteTimeout: time.Duration(config.ExecTimeout) * time.Second,
|
||||||
|
TLSConfig: tlsConfig,
|
||||||
}
|
}
|
||||||
if sshClient != nil {
|
if sshClient != nil {
|
||||||
option.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
option.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
@ -321,23 +356,6 @@ func (c *connectionService) SaveSortedConnection(sortedConns types.Connections)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectKeyFile open file dialog to select a private key file
|
|
||||||
func (c *connectionService) SelectKeyFile(title string) (resp types.JSResp) {
|
|
||||||
filepath, err := runtime.OpenFileDialog(c.ctx, runtime.OpenDialogOptions{
|
|
||||||
Title: title,
|
|
||||||
ShowHiddenFiles: true,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
resp.Msg = err.Error()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.Success = true
|
|
||||||
resp.Data = map[string]any{
|
|
||||||
"path": filepath,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateGroup create a new group
|
// CreateGroup create a new group
|
||||||
func (c *connectionService) CreateGroup(name string) (resp types.JSResp) {
|
func (c *connectionService) CreateGroup(name string) (resp types.JSResp) {
|
||||||
err := c.conns.CreateGroup(name)
|
err := c.conns.CreateGroup(name)
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
"tinyrdm/backend/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type systemService struct {
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
var system *systemService
|
||||||
|
var onceSystem sync.Once
|
||||||
|
|
||||||
|
func System() *systemService {
|
||||||
|
if system == nil {
|
||||||
|
onceSystem.Do(func() {
|
||||||
|
system = &systemService{}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return system
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *systemService) Start(ctx context.Context) {
|
||||||
|
s.ctx = ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectFile open file dialog to select a file
|
||||||
|
func (s *systemService) SelectFile(title string) (resp types.JSResp) {
|
||||||
|
filepath, err := runtime.OpenFileDialog(s.ctx, runtime.OpenDialogOptions{
|
||||||
|
Title: title,
|
||||||
|
ShowHiddenFiles: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
resp.Msg = err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp.Success = true
|
||||||
|
resp.Data = map[string]any{
|
||||||
|
"path": filepath,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ type ConnectionConfig struct {
|
||||||
DBFilterType string `json:"dbFilterType" yaml:"db_filter_type,omitempty"`
|
DBFilterType string `json:"dbFilterType" yaml:"db_filter_type,omitempty"`
|
||||||
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
DBFilterList []int `json:"dbFilterList" yaml:"db_filter_list,omitempty"`
|
||||||
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
MarkColor string `json:"markColor,omitempty" yaml:"mark_color,omitempty"`
|
||||||
|
SSL ConnectionSSL `json:"ssl,omitempty" yaml:"ssl,omitempty"`
|
||||||
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
SSH ConnectionSSH `json:"ssh,omitempty" yaml:"ssh,omitempty"`
|
||||||
Sentinel ConnectionSentinel `json:"sentinel,omitempty" yaml:"sentinel,omitempty"`
|
Sentinel ConnectionSentinel `json:"sentinel,omitempty" yaml:"sentinel,omitempty"`
|
||||||
Cluster ConnectionCluster `json:"cluster,omitempty" yaml:"cluster,omitempty"`
|
Cluster ConnectionCluster `json:"cluster,omitempty" yaml:"cluster,omitempty"`
|
||||||
|
@ -42,6 +43,13 @@ type ConnectionDB struct {
|
||||||
AvgTTL int `json:"avgTtl,omitempty"`
|
AvgTTL int `json:"avgTtl,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ConnectionSSL struct {
|
||||||
|
Enable bool `json:"enable,omitempty" yaml:"enable,omitempty"`
|
||||||
|
KeyFile string `json:"keyFile,omitempty" yaml:"keyFile,omitempty"`
|
||||||
|
CertFile string `json:"certFile,omitempty" yaml:"certFile,omitempty"`
|
||||||
|
CAFile string `json:"caFile,omitempty" yaml:"caFile,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type ConnectionSSH struct {
|
type ConnectionSSH struct {
|
||||||
Enable bool `json:"enable,omitempty" yaml:"enable,omitempty"`
|
Enable bool `json:"enable,omitempty" yaml:"enable,omitempty"`
|
||||||
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
|
Addr string `json:"addr,omitempty" yaml:"addr,omitempty"`
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
import { every, get, includes, isEmpty, map, sortBy, toNumber } from 'lodash'
|
import { every, get, includes, isEmpty, map, sortBy, toNumber } from 'lodash'
|
||||||
import { computed, nextTick, ref, watch } from 'vue'
|
import { computed, nextTick, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { ListSentinelMasters, SelectKeyFile, TestConnection } from 'wailsjs/go/services/connectionService.js'
|
import { ListSentinelMasters, TestConnection } from 'wailsjs/go/services/connectionService.js'
|
||||||
import useDialog, { ConnDialogType } from 'stores/dialog'
|
import useDialog, { ConnDialogType } from 'stores/dialog'
|
||||||
import Close from '@/components/icons/Close.vue'
|
import Close from '@/components/icons/Close.vue'
|
||||||
import useConnectionStore from 'stores/connections.js'
|
import useConnectionStore from 'stores/connections.js'
|
||||||
|
import { SelectFile } from 'wailsjs/go/services/systemService.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog for new or edit connection
|
* Dialog for new or edit connection
|
||||||
|
@ -82,12 +83,36 @@ const sshLoginType = computed(() => {
|
||||||
return get(generalForm.value, 'ssh.loginType', 'pwd')
|
return get(generalForm.value, 'ssh.loginType', 'pwd')
|
||||||
})
|
})
|
||||||
|
|
||||||
const onChoosePKFile = async () => {
|
const onSSHChooseKey = async () => {
|
||||||
const { success, data } = await SelectKeyFile(i18n.t('dialogue.connection.ssh.pkfile_selection_title'))
|
const { success, data } = await SelectFile()
|
||||||
|
const path = get(data, 'path', '')
|
||||||
|
if (!isEmpty(path)) {
|
||||||
|
generalForm.value.ssh.pkFile = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSSLChooseCert = async () => {
|
||||||
|
const { success, data } = await SelectFile()
|
||||||
|
const path = get(data, 'path', '')
|
||||||
|
if (!isEmpty(path)) {
|
||||||
|
generalForm.value.ssl.certFile = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSSLChooseKey = async () => {
|
||||||
|
const { success, data } = await SelectFile()
|
||||||
|
const path = get(data, 'path', '')
|
||||||
|
if (!isEmpty(path)) {
|
||||||
|
generalForm.value.ssl.keyFile = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSSLChooseCA = async () => {
|
||||||
|
const { success, data } = await SelectFile()
|
||||||
if (!success) {
|
if (!success) {
|
||||||
generalForm.value.ssh.pkFile = ''
|
generalForm.value.ssl.caFile = ''
|
||||||
} else {
|
} else {
|
||||||
generalForm.value.ssh.pkFile = get(data, 'path', '')
|
generalForm.value.ssl.caFile = get(data, 'path', '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +174,13 @@ const onSaveConnection = async () => {
|
||||||
generalForm.value.dbFilterList = []
|
generalForm.value.dbFilterList = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim ssl data
|
||||||
|
if (!!!generalForm.value.ssl.enable) {
|
||||||
|
generalForm.value.ssl = {}
|
||||||
|
}
|
||||||
|
|
||||||
// trim ssh login data
|
// trim ssh login data
|
||||||
if (generalForm.value.ssh.enable) {
|
if (!!generalForm.value.ssh.enable) {
|
||||||
switch (generalForm.value.ssh.loginType) {
|
switch (generalForm.value.ssh.loginType) {
|
||||||
case 'pkfile':
|
case 'pkfile':
|
||||||
generalForm.value.ssh.password = ''
|
generalForm.value.ssh.password = ''
|
||||||
|
@ -162,15 +192,16 @@ const onSaveConnection = async () => {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ssh disabled, reset to default value
|
// ssh disabled, reset to default value
|
||||||
const { ssh } = connectionStore.newDefaultConnection()
|
generalForm.value.ssh = {}
|
||||||
generalForm.value.ssh = ssh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// trim sentinel data
|
// trim sentinel data
|
||||||
if (!generalForm.value.sentinel.enable) {
|
if (!!!generalForm.value.sentinel.enable) {
|
||||||
generalForm.value.sentinel.master = ''
|
generalForm.value.sentinel = {}
|
||||||
generalForm.value.sentinel.username = ''
|
}
|
||||||
generalForm.value.sentinel.password = ''
|
|
||||||
|
if (!!!generalForm.value.cluster.enable) {
|
||||||
|
generalForm.value.cluster = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store new connection
|
// store new connection
|
||||||
|
@ -387,6 +418,60 @@ const onClose = () => {
|
||||||
</n-form>
|
</n-form>
|
||||||
</n-tab-pane>
|
</n-tab-pane>
|
||||||
|
|
||||||
|
<!-- SSL pane -->
|
||||||
|
<n-tab-pane :tab="$t('dialogue.connection.ssl.title')" display-directive="show" name="ssl">
|
||||||
|
<n-form-item label-placement="left">
|
||||||
|
<n-checkbox v-model:checked="generalForm.ssl.enable" size="medium">
|
||||||
|
{{ $t('dialogue.connection.ssl.enable') }}
|
||||||
|
</n-checkbox>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form
|
||||||
|
:model="generalForm.ssl"
|
||||||
|
:show-require-mark="false"
|
||||||
|
:disabled="!generalForm.ssl.enable"
|
||||||
|
label-placement="top">
|
||||||
|
<n-form-item :label="$t('dialogue.connection.ssl.cert_file')">
|
||||||
|
<n-input-group>
|
||||||
|
<n-input
|
||||||
|
v-model:value="generalForm.ssl.certFile"
|
||||||
|
:placeholder="$t('dialogue.connection.ssl.cert_file_tip')"
|
||||||
|
clearable />
|
||||||
|
<n-button
|
||||||
|
:focusable="false"
|
||||||
|
:disabled="!generalForm.ssl.enable"
|
||||||
|
@click="onSSLChooseCert">
|
||||||
|
...
|
||||||
|
</n-button>
|
||||||
|
</n-input-group>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item :label="$t('dialogue.connection.ssl.key_file')">
|
||||||
|
<n-input-group>
|
||||||
|
<n-input
|
||||||
|
v-model:value="generalForm.ssl.keyFile"
|
||||||
|
:placeholder="$t('dialogue.connection.ssl.key_file_tip')"
|
||||||
|
clearable />
|
||||||
|
<n-button
|
||||||
|
:focusable="false"
|
||||||
|
:disabled="!generalForm.ssl.enable"
|
||||||
|
@click="onSSLChooseKey">
|
||||||
|
...
|
||||||
|
</n-button>
|
||||||
|
</n-input-group>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item :label="$t('dialogue.connection.ssl.ca_file')">
|
||||||
|
<n-input-group>
|
||||||
|
<n-input
|
||||||
|
v-model:value="generalForm.ssl.caFile"
|
||||||
|
:placeholder="$t('dialogue.connection.ssl.ca_file_tip')"
|
||||||
|
clearable />
|
||||||
|
<n-button :focusable="false" :disabled="!generalForm.ssl.enable" @click="onSSLChooseCA">
|
||||||
|
...
|
||||||
|
</n-button>
|
||||||
|
</n-input-group>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</n-tab-pane>
|
||||||
|
|
||||||
<!-- SSH pane -->
|
<!-- SSH pane -->
|
||||||
<n-tab-pane :tab="$t('dialogue.connection.ssh.title')" display-directive="show" name="ssh">
|
<n-tab-pane :tab="$t('dialogue.connection.ssh.title')" display-directive="show" name="ssh">
|
||||||
<n-form-item label-placement="left">
|
<n-form-item label-placement="left">
|
||||||
|
@ -435,7 +520,13 @@ const onClose = () => {
|
||||||
<n-input
|
<n-input
|
||||||
v-model:value="generalForm.ssh.pkFile"
|
v-model:value="generalForm.ssh.pkFile"
|
||||||
:placeholder="$t('dialogue.connection.ssh.pkfile_tip')" />
|
:placeholder="$t('dialogue.connection.ssh.pkfile_tip')" />
|
||||||
<n-button :focusable="false" @click="onChoosePKFile">...</n-button>
|
<n-button
|
||||||
|
:focusable="false"
|
||||||
|
:disabled="!generalForm.ssh.enable"
|
||||||
|
@click="onSSHChooseKey"
|
||||||
|
clearable>
|
||||||
|
...
|
||||||
|
</n-button>
|
||||||
</n-input-group>
|
</n-input-group>
|
||||||
</n-form-item>
|
</n-form-item>
|
||||||
<n-form-item v-if="sshLoginType === 'pkfile'" :label="$t('dialogue.connection.ssh.passphrase')">
|
<n-form-item v-if="sshLoginType === 'pkfile'" :label="$t('dialogue.connection.ssh.passphrase')">
|
||||||
|
|
|
@ -150,12 +150,12 @@
|
||||||
"ssl": {
|
"ssl": {
|
||||||
"title": "SSL/TLS",
|
"title": "SSL/TLS",
|
||||||
"enable": "Enable SSL/TLS",
|
"enable": "Enable SSL/TLS",
|
||||||
"key_file": "Public Key",
|
"cert_file": "Public Key",
|
||||||
"cert_file": "Private Key",
|
"key_file": "Private Key",
|
||||||
"ca_file": "Authority",
|
"ca_file": "Authority",
|
||||||
"key_file_tip": "Public Key File in PEM format",
|
"cert_file_tip":"Public Key File in PEM format(Cert)",
|
||||||
"cert_file_tip":"Private Key File in PEM format",
|
"key_file_tip": "Private Key File in PEM format(Key)",
|
||||||
"ca_file_tip": "Certificate Authority File in PEM format"
|
"ca_file_tip": "Certificate Authority File in PEM format(CA)"
|
||||||
},
|
},
|
||||||
"ssh": {
|
"ssh": {
|
||||||
"title": "SSH Tunnel",
|
"title": "SSH Tunnel",
|
||||||
|
@ -167,8 +167,7 @@
|
||||||
"usr_tip": "SSH Username",
|
"usr_tip": "SSH Username",
|
||||||
"pwd_tip": "SSH Password",
|
"pwd_tip": "SSH Password",
|
||||||
"pkfile_tip": "SSH Private Key File Path",
|
"pkfile_tip": "SSH Private Key File Path",
|
||||||
"passphrase_tip": "(Optional) Passphrase for Private Key",
|
"passphrase_tip": "(Optional) Passphrase for Private Key"
|
||||||
"pkfile_selection_title": "Please Select Private Key File"
|
|
||||||
},
|
},
|
||||||
"sentinel": {
|
"sentinel": {
|
||||||
"title": "Sentinel",
|
"title": "Sentinel",
|
||||||
|
|
|
@ -150,12 +150,12 @@
|
||||||
"ssl": {
|
"ssl": {
|
||||||
"title": "SSL/TLS",
|
"title": "SSL/TLS",
|
||||||
"enable": "启用SSL",
|
"enable": "启用SSL",
|
||||||
"key_file": "公钥文件",
|
"cert_file": "公钥文件",
|
||||||
"cert_file": "私钥文件",
|
"key_file": "私钥文件",
|
||||||
"ca_file": "授权文件",
|
"ca_file": "授权文件",
|
||||||
"key_file_tip": "PEM格式公钥文件",
|
"cert_file_tip":"PEM格式公钥文件(Cert)",
|
||||||
"cert_file_tip":"PEM格式私钥文件",
|
"key_file_tip": "PEM格式私钥文件(Key)",
|
||||||
"ca_file_tip": "PEM格式授权文件"
|
"ca_file_tip": "PEM格式授权文件(CA)"
|
||||||
},
|
},
|
||||||
"ssh": {
|
"ssh": {
|
||||||
"enable": "启用SSH隧道",
|
"enable": "启用SSH隧道",
|
||||||
|
@ -167,8 +167,7 @@
|
||||||
"usr_tip": "SSH登录用户名",
|
"usr_tip": "SSH登录用户名",
|
||||||
"pwd_tip": "SSH登录密码",
|
"pwd_tip": "SSH登录密码",
|
||||||
"pkfile_tip": "SSH私钥文件路径",
|
"pkfile_tip": "SSH私钥文件路径",
|
||||||
"passphrase_tip": "(可选)SSH私钥密码",
|
"passphrase_tip": "(可选)SSH私钥密码"
|
||||||
"pkfile_selection_title": "请选择私钥文件"
|
|
||||||
},
|
},
|
||||||
"sentinel": {
|
"sentinel": {
|
||||||
"title": "哨兵模式",
|
"title": "哨兵模式",
|
||||||
|
|
|
@ -231,6 +231,12 @@ const useConnectionStore = defineStore('connections', {
|
||||||
dbFilterType: 'none',
|
dbFilterType: 'none',
|
||||||
dbFilterList: [],
|
dbFilterList: [],
|
||||||
markColor: '',
|
markColor: '',
|
||||||
|
ssl: {
|
||||||
|
enable: false,
|
||||||
|
certFile: '',
|
||||||
|
keyFile: '',
|
||||||
|
caFile: '',
|
||||||
|
},
|
||||||
ssh: {
|
ssh: {
|
||||||
enable: false,
|
enable: false,
|
||||||
addr: '',
|
addr: '',
|
||||||
|
|
6
main.go
6
main.go
|
@ -26,7 +26,7 @@ var version = "0.0.0"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create an instance of the app structure
|
// Create an instance of the app structure
|
||||||
app := NewApp()
|
sysSvc := services.System()
|
||||||
connSvc := services.Connection()
|
connSvc := services.Connection()
|
||||||
prefSvc := services.Preferences()
|
prefSvc := services.Preferences()
|
||||||
prefSvc.SetAppVersion(version)
|
prefSvc.SetAppVersion(version)
|
||||||
|
@ -54,7 +54,7 @@ func main() {
|
||||||
},
|
},
|
||||||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 0},
|
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 0},
|
||||||
OnStartup: func(ctx context.Context) {
|
OnStartup: func(ctx context.Context) {
|
||||||
app.startup(ctx)
|
sysSvc.Start(ctx)
|
||||||
connSvc.Start(ctx)
|
connSvc.Start(ctx)
|
||||||
},
|
},
|
||||||
OnBeforeClose: func(ctx context.Context) (prevent bool) {
|
OnBeforeClose: func(ctx context.Context) (prevent bool) {
|
||||||
|
@ -69,7 +69,7 @@ func main() {
|
||||||
connSvc.Stop(ctx)
|
connSvc.Stop(ctx)
|
||||||
},
|
},
|
||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
app,
|
sysSvc,
|
||||||
connSvc,
|
connSvc,
|
||||||
prefSvc,
|
prefSvc,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue