You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

241 lines
6.5 KiB

package app
import (
"encoding/json"
"io"
"os"
"os/user"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/wailsapp/wails"
"github.com/grvlle/constellation_wallet/backend/api"
"github.com/grvlle/constellation_wallet/backend/models"
)
// WalletApplication 保存所有特定于应用程序的对象
// 例如客户端/服务器事件总线和记录器
type WalletApplication struct {
Version string
RT *wails.Runtime
log *logrus.Logger
wallet models.Wallet
DB *gorm.DB
killSignal chan struct{}
Network struct {
URL string
Handles struct {
Send string // Takes TX Object, returns TX Hash (200)
Transaction string // Takes TX Object, returns TX Hash (200)
Balance string // Polls the wallets available balance
}
BlockExplorer struct {
URL string
Handles struct {
Transactions string // Takes TX Hash, returns TX info
Checkpoints string // Takes Checkpoint block hash, returns checkpoint block info
Snapshots string // Takes SnapshotHash, returns info
CollectTX string // Takes DAG address, returns tx objects
}
}
}
paths struct {
HomeDir string
DAGDir string
TMPDir string
EncryptedDir string
EmptyTXFile string
PrevTXFile string
LastTXFile string
AddressFile string
ImageDir string
Java string
}
KeyStoreAccess bool
TransactionFinished bool
TransactionFailed bool
UserLoggedIn bool
NewUser bool
WalletImported bool
FirstTX bool
SecondTX bool
WidgetRunning struct {
PassKeysToFrontend bool
DashboardWidgets bool
}
WalletCLI struct {
URL string
Version string
}
}
// WailsShutdown 在应用程序关闭时调用
func (a *WalletApplication) WailsShutdown() {
a.wallet = models.Wallet{}
close(a.killSignal) //杀死 Go 例程
a.DB.Close()
}
// WailsInit 初始化客户端和服务器端绑定
func (a *WalletApplication) WailsInit(runtime *wails.Runtime) error {
var err error
// 初始化日志对象
a.log = logrus.New()
err = a.initDirectoryStructure()
if err != nil {
a.log.Errorln("无法设置目录结构。原因: ", err)
}
// 初始化输出日志
a.initLogger()
// 初始化 RPC 服务
err = api.InitRPCServer()
if err != nil {
a.log.Panicf("Unable to initialize RPC Server. Reason: %v", err)
}
a.log.Infoln("RPC Server initialized.")
a.UserLoggedIn = false
a.NewUser = false
a.TransactionFinished = true
a.RT = runtime
a.killSignal = make(chan struct{}) // 用于终止go例程并交还系统资源
a.wallet.Currency = "USD" // 设置默认货币
a.WalletCLI.URL = "https://github.com/Constellation-Labs/constellation/releases/download"
a.WalletCLI.Version = "2.6.0"
a.Version = "1.2.0"
// 创建数据库连接
a.DB, err = gorm.Open("sqlite3", a.paths.DAGDir+"/store.db")
if err != nil {
a.log.Panicln("failed to connect database", err)
}
// Migrate the schema::迁移架构
a.DB.AutoMigrate(&models.Wallet{}, &models.TXHistory{}, &models.Path{})
// 查询 JDK 目录信息
a.detectJavaPath()
a.initMainnetConnection()
// TODO a.newReleaseAvailable()
return nil
}
// initLogger writes logs to STDOUT and a.paths.DAGDir/wallet.log
func (a *WalletApplication) initLogger() {
logFile, err := os.OpenFile(a.paths.DAGDir+"/wallet.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664)
if err != nil {
a.log.Fatal("Unable to create log file.")
}
mw := io.MultiWriter(os.Stdout, logFile)
a.log.SetOutput(mw)
a.log.SetFormatter(&log.TextFormatter{
ForceColors: true,
FullTimestamp: true,
})
}
// 初始化目录结构并存储 WalletApplication 结构的路径。
func (a *WalletApplication) initDirectoryStructure() error {
user, err := user.Current()
if err != nil {
return err
}
a.paths.HomeDir = user.HomeDir // Home directory of the user
a.paths.DAGDir = a.paths.HomeDir + "/.dag" // DAG directory for configuration files and wallet specific data
a.paths.TMPDir = a.paths.DAGDir + "/tmp"
a.paths.LastTXFile = a.paths.TMPDir + "/last_tx"
a.paths.PrevTXFile = a.paths.TMPDir + "/prev_tx"
a.paths.EmptyTXFile = a.paths.TMPDir + "/genesis_tx"
a.paths.ImageDir = "./frontend/src/assets/img/" // Image Folder
a.log.Info("DAG Directory: ", a.paths.DAGDir)
err = a.directoryCreator(a.paths.DAGDir, a.paths.TMPDir)
if err != nil {
return err
}
return nil
}
// initMainnetConnection 用主网数据填充 WalletApplication 结构
func (a *WalletApplication) initMainnetConnection() {
a.Network.URL = "http://lb.constellationnetwork.io:9000" // Temp
a.Network.Handles.Send = "/send"
a.Network.Handles.Transaction = "/transaction"
a.Network.Handles.Balance = "/address/"
a.Network.BlockExplorer.URL = "https://xju69fets2.execute-api.us-west-1.amazonaws.com/cl-block-explorer-mainnet"
a.Network.BlockExplorer.Handles.Transactions = "/transactions/"
a.Network.BlockExplorer.Handles.Checkpoints = "/checkpoints/"
a.Network.BlockExplorer.Handles.Snapshots = "/snapshots/"
a.Network.BlockExplorer.Handles.CollectTX = "/transactions?sender="
}
// APIError 由 blockexplerer/loadbalancer 报告的 APIError 按以下格式报告
// {“error”: “找不到发件人的交易”}
type APIError struct {
Error string
}
// verifyAPIResponse 将 API 响应转换为字节数组,并检查 API 是否返回了一个错误。如果是这样,它将返回错误消息。
func (a *WalletApplication) verifyAPIResponse(r []byte) (bool, string) {
APIErr := APIError{}
if string(r[3:8]) == "error" {
err := json.Unmarshal(r, &APIErr)
if err != nil {
a.log.Errorln("无法解析 API 错误。原因: ", err)
}
return false, APIErr.Error
}
return true, ""
}
func (a *WalletApplication) sendSuccess(msg string) {
if len(msg) > 200 {
msg = msg[:200] // 限制前端的错误大小
a.RT.Events.Emit("success", msg)
return
}
a.RT.Events.Emit("success", msg)
}
func (a *WalletApplication) sendWarning(msg string) {
if len(msg) > 200 {
msg = msg[:200] // 限制前端的错误大小
a.RT.Events.Emit("warning", msg)
return
}
a.RT.Events.Emit("warning", msg)
}
func (a *WalletApplication) sendError(msg string, err error) {
var errStr string
if err != nil {
b := []byte(err.Error())
if len(b) > 80 {
errStr = string(b[:80]) // 限制前端的错误大小
} else if len(b) < 80 {
errStr = string(b)
} else {
errStr = ""
}
a.RT.Events.Emit("error_handling", msg, errStr+" ...")
} else {
a.RT.Events.Emit("error_handling", msg+" ...")
}
}