@@ -3,33 +3,29 @@ package app
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
- "os "
7
- "path/filepath "
6
+ "errors "
7
+ "fmt "
8
8
"sync"
9
9
10
10
"github.com/TrueBlocks/trueblocks-browse/pkg/daemons"
11
- "github.com/TrueBlocks/trueblocks-browse/pkg/messages"
12
11
"github.com/TrueBlocks/trueblocks-browse/pkg/types"
13
12
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
14
- coreConfig "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
15
13
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
16
14
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/logger"
15
+ "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/names"
17
16
"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/output"
18
17
coreTypes "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types"
19
- "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/utils"
20
18
sdk "github.com/TrueBlocks/trueblocks-sdk/v3"
21
19
"github.com/wailsapp/wails/v2/pkg/runtime"
22
20
)
23
21
24
22
type App struct {
25
- sdk.Globals `json:",inline"`
23
+ sdk.Globals
26
24
27
25
ctx context.Context
28
26
meta coreTypes.MetaData
29
27
dirty bool
30
28
31
- renderCtxs map [base.Address ][]* output.RenderCtx
32
-
33
29
// Containers
34
30
projects types.ProjectContainer
35
31
monitors types.MonitorContainer
@@ -43,101 +39,112 @@ type App struct {
43
39
config types.ConfigContainer
44
40
45
41
// Memory caches
46
- HistoryCache * types.HistoryMap `json:"historyCache"`
47
- EnsCache * sync.Map `json:"ensCache"`
48
- BalanceCache * sync.Map `json:"balanceCache"`
42
+ ensCache * sync.Map
43
+ balanceCache * sync.Map
44
+ namesMap map [base.Address ]coreTypes.Name
45
+ historyCache * types.HistoryMap
46
+ renderCtxs map [base.Address ][]* output.RenderCtx
49
47
50
48
// Controllers
51
- ScraperController * daemons.DaemonScraper
52
- FreshenController * daemons.DaemonFreshen
53
- IpfsController * daemons.DaemonIpfs
49
+ scraperController * daemons.DaemonScraper
50
+ freshenController * daemons.DaemonFreshen
51
+ ipfsController * daemons.DaemonIpfs
52
+
53
+ // During initialization, we do things that may cause errors, but
54
+ // we have not yet opened the window, so we defer them until we can
55
+ // decide what to do.
56
+ deferredErrors []error
57
+ }
58
+
59
+ func (a * App ) String () string {
60
+ bytes , _ := json .Marshal (a )
61
+ return string (bytes )
54
62
}
55
63
56
64
func NewApp () * App {
57
- a := App {
58
- renderCtxs : make (map [base.Address ][]* output.RenderCtx ),
65
+ a := & App {
66
+ ensCache : & sync.Map {},
67
+ balanceCache : & sync.Map {},
68
+ namesMap : make (map [base.Address ]coreTypes.Name ),
69
+ historyCache : & types.HistoryMap {},
70
+ renderCtxs : make (map [base.Address ][]* output.RenderCtx ),
59
71
}
60
- a .EnsCache = & sync.Map {}
61
- a .BalanceCache = & sync.Map {}
62
- a .HistoryCache = & types.HistoryMap {}
63
- a .names .NamesMap = make (map [base.Address ]coreTypes.Name )
64
- a .projects = types .NewProjectContainer ("" , []types.HistoryContainer {})
72
+ a .freshenController = daemons .NewFreshen (a , "freshen" , 3000 , a .IsShowing ("freshen" ))
73
+ a .scraperController = daemons .NewScraper (a , "scraper" , 7000 , a .IsShowing ("scraper" ))
74
+ a .ipfsController = daemons .NewIpfs (a , "ipfs" , 10000 , a .IsShowing ("ipfs" ))
65
75
a .session .LastSub = make (map [string ]string )
66
76
67
- return & a
77
+ return a
68
78
}
69
79
70
- func (a * App ) String () string {
71
- bytes , _ := json .MarshalIndent (a , "" , " " )
72
- return string (bytes )
73
- }
80
+ var ErrLoadingNames = errors .New ("error loading names" )
81
+ var ErrWindowSize = errors .New ("error fixing window size" )
74
82
75
83
func (a * App ) Startup (ctx context.Context ) {
76
84
a .ctx = ctx
77
- a .loadSession ()
78
- a .Chain = a .session .LastChain
79
85
80
- a .FreshenController = daemons .NewFreshen (a , "freshen" , 3000 , a .IsShowing ("freshen" ))
81
- a .ScraperController = daemons .NewScraper (a , "scraper" , 7000 , a .IsShowing ("scraper" ))
82
- a .IpfsController = daemons .NewIpfs (a , "ipfs" , 10000 , a .IsShowing ("ipfs" ))
83
- go a .startDaemons ()
86
+ // We do various setups prior to showing the window. Improves interactivity.
87
+ // But...something may fail, so we need to keep track of errors.
88
+ var err error
89
+ if err = a .session .Load (); err != nil {
90
+ a .deferredErrors = append (a .deferredErrors , err )
91
+ }
84
92
85
- fn := filepath . Join ( a . session . LastFolder , a . session . LastFile )
86
- if file . FileExists ( fn ) {
87
- a .LoadFile ( fn )
88
- a . dirty = false
89
- } else {
90
- a .dirty = true
93
+ // Load the trueBlocks.toml file
94
+ if err = a . config . Load (); err != nil {
95
+ a .deferredErrors = append ( a . deferredErrors , err )
96
+ }
97
+ if a . session . LastChain , err = a . config . IsValidChain ( a . session . LastChain ); err != nil {
98
+ a .deferredErrors = append ( a . deferredErrors , err )
91
99
}
100
+ a .Chain = a .session .LastChain
92
101
93
- logger .Info ("Starting freshen process..." )
94
- _ = a .Refresh ()
102
+ // We always need names, so let's load it before showing the window
103
+ if a .namesMap , err = names .LoadNamesMap (a .getChain (), coreTypes .All , nil ); err == nil {
104
+ wErr := fmt .Errorf ("%w: %v" , ErrLoadingNames , err )
105
+ a .deferredErrors = append (a .deferredErrors , wErr )
106
+ }
95
107
}
96
108
109
+ // DomReady is called by Wails when the app is ready to go. Adjust the window size and show it.
97
110
func (a * App ) DomReady (ctx context.Context ) {
98
- win := a .GetWindow ()
99
- runtime .WindowSetPosition (a .ctx , win .X , win .Y )
100
- runtime .WindowSetSize (a .ctx , win .Width , win .Height )
101
- runtime .WindowShow (a .ctx )
111
+ var err error
102
112
103
- if path , err := utils .GetConfigFn ("" , "trueBlocks.toml" ); err != nil {
104
- messages .EmitMessage (a .ctx , messages .Error , & messages.MessageMsg {
105
- String1 : err .Error (),
106
- })
107
- } else {
108
- if err := coreConfig .ReadToml (path , & a .config .Config ); err != nil {
109
- messages .EmitMessage (a .ctx , messages .Error , & messages.MessageMsg {
110
- String1 : err .Error (),
111
- })
112
- }
113
+ // We're ready to open the window, but first we need to make sure it will show...
114
+ if a .session .Window , err = a .session .CleanWindowSize (a .ctx ); err != nil {
115
+ wErr := fmt .Errorf ("%w: %v" , ErrWindowSize , err )
116
+ a .deferredErrors = append (a .deferredErrors , wErr )
117
+ }
118
+ // DO NOT COLLAPSE - A VALID WINDOW IS RETURNED EVEN ON ERROR
119
+ runtime .WindowSetPosition (a .ctx , a .session .Window .X , a .session .Window .Y )
120
+ runtime .WindowSetSize (a .ctx , a .session .Window .Width , a .session .Window .Height )
121
+ runtime .WindowShow (a .ctx )
122
+ if err != nil {
123
+ a .deferredErrors = append (a .deferredErrors , err )
113
124
}
114
- }
115
125
116
- func (a * App ) Shutdown (ctx context.Context ) {
117
- a .saveSession ()
118
- }
126
+ // We now have a window, so we can finally show any accumulated errors
127
+ for _ , err := range a .deferredErrors {
128
+ a .emitErrorMsg (err , nil )
129
+ }
119
130
120
- func ( a * App ) saveSession () {
121
- if ! isTesting {
122
- a .session . Window . X , a . session . Window . Y = runtime . WindowGetPosition ( a . ctx )
123
- a . session . Window . Width , a . session . Window . Height = runtime . WindowGetSize ( a . ctx )
124
- a .session . Window . Y += 38 // TODO: This is a hack to account for the menu bar - not sure why it's needed
131
+ fn := a . getFullPath ()
132
+ if file . FileExists ( fn ) {
133
+ a .readFile ( fn )
134
+ } else {
135
+ a .newFile ()
125
136
}
126
- _ = a .session .Save ()
127
- }
128
137
129
- func (a * App ) loadSession () {
130
- _ = a .session .Load ()
131
- a .session .CleanWindowSize (a .ctx )
132
- a .Chain = a .session .LastChain
133
- }
138
+ go a .Refresh ()
134
139
135
- func ( a * App ) Logger ( msg string ) {
136
- logger . Info ( msg )
137
- }
140
+ go a . freshenController . Run ()
141
+ go a . scraperController . Run ( )
142
+ go a . ipfsController . Run ()
138
143
139
- var isTesting bool
144
+ logger .Info ("Fininished loading..." )
145
+ }
140
146
141
- func init () {
142
- isTesting = os .Getenv ("TB_TEST_MODE" ) == "true"
147
+ // Shutdown is called by Wails when the app is closed
148
+ func (a * App ) Shutdown (ctx context.Context ) {
149
+ a .saveSession ()
143
150
}
0 commit comments