/
types.go
273 lines (238 loc) · 7.03 KB
/
types.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
package discord
import (
"errors"
"fmt"
"sync"
"github.com/status-im/status-go/images"
"github.com/status-im/status-go/protocol/protobuf"
)
type ErrorCodeType uint
const (
NoErrorType ErrorCodeType = iota + 1
WarningType
ErrorType
)
const MaxTaskErrorItemsCount = 3
const MaxImportFileSizeBytes = 52428800
var (
ErrNoChannelData = errors.New("No channels to import messages from")
ErrNoMessageData = errors.New("No messages to import")
ErrMarshalMessage = errors.New("Couldn't marshal discord message")
ErrImportFileTooBig = fmt.Errorf("File is too big (max. %d MB)", MaxImportFileSizeBytes/1024/1024)
)
type MessageType string
const (
MessageTypeDefault MessageType = "Default"
MessageTypeReply MessageType = "Reply"
MessageTypeChannelPinned MessageType = "ChannelPinnedMessage"
)
type ImportTask uint
const (
CommunityCreationTask ImportTask = iota + 1
ChannelsCreationTask
ImportMessagesTask
DownloadAssetsTask
InitCommunityTask
)
func (t ImportTask) String() string {
switch t {
case CommunityCreationTask:
return "import.communityCreation"
case ChannelsCreationTask:
return "import.channelsCreation"
case ImportMessagesTask:
return "import.importMessages"
case DownloadAssetsTask:
return "import.downloadAssets"
case InitCommunityTask:
return "import.initializeCommunity"
}
return "unknown"
}
type ImportTaskState uint
const (
TaskStateInitialized ImportTaskState = iota
TaskStateSaving
)
func (t ImportTaskState) String() string {
switch t {
case TaskStateInitialized:
return "import.taskState.initialized"
case TaskStateSaving:
return "import.taskState.saving"
}
return "import.taskState.unknown"
}
type Channel struct {
ID string `json:"id"`
CategoryName string `json:"category"`
CategoryID string `json:"categoryId"`
Name string `json:"name"`
Description string `json:"topic"`
FilePath string `json:"filePath"`
}
type Category struct {
ID string `json:"id"`
Name string `json:"name"`
}
type ExportedData struct {
Channel Channel `json:"channel"`
Messages []*protobuf.DiscordMessage `json:"messages"`
MessageCount int `json:"messageCount"`
}
type ExtractedData struct {
Categories map[string]*Category
ExportedData []*ExportedData
OldestMessageTimestamp int
MessageCount int
}
type ImportError struct {
// This code is used to distinguish between errors
// that are considered "criticial" and those that are not.
//
// Critical errors are the ones that prevent the imported community
// from functioning properly. For example, if the creation of the community
// or its categories and channels fails, this is a critical error.
//
// Non-critical errors are the ones that would not prevent the imported
// community from functioning. For example, if the channel data to be imported
// has no messages, or is not parsable.
Code ErrorCodeType `json:"code"`
Message string `json:"message"`
TaskInfo string `json:"taskInfo"`
}
func (d ImportError) Error() string {
return fmt.Sprintf("%d: %s", d.Code, d.Message)
}
func Error(message string) *ImportError {
return &ImportError{
Message: message,
Code: ErrorType,
}
}
func Warning(message string) *ImportError {
return &ImportError{
Message: message,
Code: WarningType,
}
}
type ImportTaskProgress struct {
Type string `json:"type"`
Progress float32 `json:"progress"`
Errors []*ImportError `json:"errors"`
Stopped bool `json:"stopped"`
ErrorsCount uint `json:"errorsCount"`
WarningsCount uint `json:"warningsCount"`
State string `json:"state"`
}
type ImportTasks map[ImportTask]*ImportTaskProgress
type ImportProgress struct {
CommunityID string `json:"communityId,omitempty"`
CommunityName string `json:"communityName"`
CommunityImages map[string]images.IdentityImage `json:"communityImages"`
Tasks []*ImportTaskProgress `json:"tasks"`
Progress float32 `json:"progress"`
ErrorsCount uint `json:"errorsCount"`
WarningsCount uint `json:"warningsCount"`
Stopped bool `json:"stopped"`
TotalChunkCount int `json:"totalChunksCount,omitempty"`
CurrentChunk int `json:"currentChunk,omitempty"`
m sync.Mutex
}
func (progress *ImportProgress) Init(totalChunkCount int, tasks []ImportTask) {
progress.Progress = 0
progress.Tasks = make([]*ImportTaskProgress, 0)
for _, task := range tasks {
progress.Tasks = append(progress.Tasks, &ImportTaskProgress{
Type: task.String(),
Progress: 0,
Errors: []*ImportError{},
Stopped: false,
ErrorsCount: 0,
WarningsCount: 0,
State: TaskStateInitialized.String(),
})
}
progress.ErrorsCount = 0
progress.WarningsCount = 0
progress.Stopped = false
progress.TotalChunkCount = totalChunkCount
progress.CurrentChunk = 0
}
func (progress *ImportProgress) Stop() {
progress.Stopped = true
}
func (progress *ImportProgress) AddTaskError(task ImportTask, err *ImportError) {
progress.m.Lock()
defer progress.m.Unlock()
for i, t := range progress.Tasks {
if t.Type == task.String() {
errorsAndWarningsCount := progress.Tasks[i].ErrorsCount + progress.Tasks[i].WarningsCount
if (errorsAndWarningsCount < MaxTaskErrorItemsCount) || err.Code > WarningType {
errors := progress.Tasks[i].Errors
progress.Tasks[i].Errors = append(errors, err)
}
if err.Code > WarningType {
progress.Tasks[i].ErrorsCount++
}
if err.Code > NoErrorType {
progress.Tasks[i].WarningsCount++
}
}
}
if err.Code > WarningType {
progress.ErrorsCount++
return
}
if err.Code > NoErrorType {
progress.WarningsCount++
}
}
func (progress *ImportProgress) StopTask(task ImportTask) {
progress.m.Lock()
defer progress.m.Unlock()
for i, t := range progress.Tasks {
if t.Type == task.String() {
progress.Tasks[i].Stopped = true
}
}
progress.Stop()
}
func (progress *ImportProgress) UpdateTaskProgress(task ImportTask, value float32) {
progress.m.Lock()
defer progress.m.Unlock()
for i, t := range progress.Tasks {
if t.Type == task.String() {
progress.Tasks[i].Progress = value
}
}
sum := float32(0)
for _, t := range progress.Tasks {
sum = sum + t.Progress
}
// Update total progress now that sub progress has changed
progress.Progress = sum / float32(len(progress.Tasks))
}
func (progress *ImportProgress) UpdateTaskState(task ImportTask, state ImportTaskState) {
progress.m.Lock()
defer progress.m.Unlock()
for i, t := range progress.Tasks {
if t.Type == task.String() {
progress.Tasks[i].State = state.String()
}
}
}
type AssetCounter struct {
m sync.RWMutex
v uint64
}
func (c *AssetCounter) Value() uint64 {
c.m.RLock()
defer c.m.RUnlock()
return c.v
}
func (c *AssetCounter) Increase() {
c.m.Lock()
c.v++
c.m.Unlock()
}