/
dapp.go
155 lines (133 loc) · 3.45 KB
/
dapp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package dapp
import (
"encoding/hex"
"errors"
"fmt"
"time"
module "github.com/Bit-Nation/panthalassa/dapp/module"
cbModule "github.com/Bit-Nation/panthalassa/dapp/module/callbacks"
dbModule "github.com/Bit-Nation/panthalassa/dapp/module/db"
dAppRenderer "github.com/Bit-Nation/panthalassa/dapp/module/renderer/dapp"
msgRenderer "github.com/Bit-Nation/panthalassa/dapp/module/renderer/message"
storm "github.com/asdine/storm"
log "github.com/ipfs/go-log"
logger "github.com/op/go-logging"
otto "github.com/robertkrimen/otto"
)
var sysLog = log.Logger("dapp")
type DApp struct {
vm *otto.Otto
logger *logger.Logger
app *Data
// will be called when the app shut down
closeChan chan<- *Data
dAppRenderer *dAppRenderer.Module
msgRenderer *msgRenderer.Module
cbMod *cbModule.Module
dbMod *dbModule.BoltStorage
vmModules []module.Module
}
// close DApp
func (d *DApp) Close() {
d.vm.Interrupt <- func() {
d.logger.Info(fmt.Sprintf("shutting down: %s (%s)", hex.EncodeToString(d.app.UsedSigningKey), d.app.Name))
for _, mod := range d.vmModules {
if err := mod.Close(); err != nil {
sysLog.Error(err)
}
}
d.closeChan <- d.app
}
}
func (d *DApp) ID() string {
return hex.EncodeToString(d.app.UsedSigningKey)
}
func (d *DApp) OpenDApp(context string) error {
return d.dAppRenderer.OpenDApp(context)
}
func (d *DApp) RenderMessage(payload string) (string, error) {
return d.msgRenderer.RenderMessage(payload)
}
func (d *DApp) CallFunction(id uint, args string) error {
return d.cbMod.CallFunction(id, args)
}
// will start a DApp based on the given config file
func New(l *logger.Logger, app *Data, vmModules []module.Module, closer chan<- *Data, timeOut time.Duration, db *storm.DB) (*DApp, error) {
// check if app is valid
valid, err := app.VerifySignature()
if err != nil {
return nil, err
}
if !valid {
return nil, InvalidSignature
}
// create VM
vm := otto.New()
vm.Interrupt = make(chan func(), 1)
// register all vm modules
for _, m := range vmModules {
if err := m.Register(vm); err != nil {
return nil, err
}
}
// register DApp renderer
dr := dAppRenderer.New(l)
vmModules = append(vmModules, dr)
if err := dr.Register(vm); err != nil {
return nil, err
}
// register message renderer
mr := msgRenderer.New(l)
vmModules = append(vmModules, mr)
if err := mr.Register(vm); err != nil {
return nil, err
}
// register callbacks module
cbm := cbModule.New(l)
vmModules = append(vmModules, cbm)
if err := cbm.Register(vm); err != nil {
return nil, err
}
// register database (the one used by the dapp)
dAppDBStorage, err := dbModule.NewBoltStorage(db, app.UsedSigningKey)
if err != nil {
return nil, err
}
dbm := dbModule.New(dAppDBStorage, l)
vmModules = append(vmModules, dbm)
if err := dbm.Register(vm); err != nil {
return nil, err
}
dApp := &DApp{
vm: vm,
logger: l,
app: app,
closeChan: closer,
dAppRenderer: dr,
msgRenderer: mr,
cbMod: cbm,
dbMod: dAppDBStorage,
vmModules: vmModules,
}
wait := make(chan error, 1)
// start the DApp async
go func() {
_, err := vm.Run(app.Code)
if err != nil {
l.Errorf(err.Error())
}
wait <- err
}()
// wait for the DApp with given timeout
select {
case err := <-wait:
if err != nil {
return nil, err
}
return dApp, nil
case <-time.After(timeOut):
vm.Interrupt <- func() {}
closer <- app
return nil, errors.New("timeout - failed to start DApp")
}
}