Commit 685dd6223d0c84c78e702a9e437417be64d2c170

Authored by Marko Tikvić
1 parent 3f8e3c4374
Exists in master and in 1 other branch v2

added error logging everywhere

Showing 1 changed file with 6 additions and 0 deletions   Show diff stats
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "encoding/json" 5 "encoding/json"
6 "errors" 6 "errors"
7 "fmt" 7 "fmt"
8 "io" 8 "io"
9 "net/http" 9 "net/http"
10 "sync" 10 "sync"
11 "time" 11 "time"
12 12
13 "git.to-net.rs/marko.tikvic/gologger" 13 "git.to-net.rs/marko.tikvic/gologger"
14 ) 14 )
15 15
16 var ( 16 var (
17 mu = &sync.Mutex{} 17 mu = &sync.Mutex{}
18 metadata = make(map[string]Payload) 18 metadata = make(map[string]Payload)
19 19
20 updateQue = make(map[string][]byte) 20 updateQue = make(map[string][]byte)
21 21
22 metadataDB *sql.DB 22 metadataDB *sql.DB
23 activeProject string 23 activeProject string
24 24
25 inited bool 25 inited bool
26 driver string 26 driver string
27 logger *gologger.Logger 27 logger *gologger.Logger
28 ) 28 )
29 29
30 type LangMap map[string]map[string]string 30 type LangMap map[string]map[string]string
31 31
32 type Field struct { 32 type Field struct {
33 Parameter string `json:"param"` 33 Parameter string `json:"param"`
34 Type string `json:"type"` 34 Type string `json:"type"`
35 Visible bool `json:"visible"` 35 Visible bool `json:"visible"`
36 Editable bool `json:"editable"` 36 Editable bool `json:"editable"`
37 } 37 }
38 38
39 type CorrelationField struct { 39 type CorrelationField struct {
40 Result string `json:"result"` 40 Result string `json:"result"`
41 Elements []string `json:"elements"` 41 Elements []string `json:"elements"`
42 Type string `json:"type"` 42 Type string `json:"type"`
43 } 43 }
44 44
45 type Translation struct { 45 type Translation struct {
46 Language string `json:"language"` 46 Language string `json:"language"`
47 FieldsLabels map[string]string `json:"fieldsLabels"` 47 FieldsLabels map[string]string `json:"fieldsLabels"`
48 } 48 }
49 49
50 type Payload struct { 50 type Payload struct {
51 Method string `json:"method"` 51 Method string `json:"method"`
52 Params map[string]string `json:"params"` 52 Params map[string]string `json:"params"`
53 Lang []Translation `json:"lang"` 53 Lang []Translation `json:"lang"`
54 Fields []Field `json:"fields"` 54 Fields []Field `json:"fields"`
55 Correlations []CorrelationField `json:"correlationFields"` 55 Correlations []CorrelationField `json:"correlationFields"`
56 IdField string `json:"idField"` 56 IdField string `json:"idField"`
57 57
58 // Data holds JSON payload. 58 // Data holds JSON payload.
59 // It can't be used for itteration. 59 // It can't be used for itteration.
60 Data interface{} `json:"data"` 60 Data interface{} `json:"data"`
61 } 61 }
62 62
63 func (p *Payload) SetData(data interface{}) { 63 func (p *Payload) SetData(data interface{}) {
64 p.Data = data 64 p.Data = data
65 } 65 }
66 66
67 // NewPayload returs a payload sceleton for entity described with etype. 67 // NewPayload returs a payload sceleton for entity described with etype.
68 func NewPayload(r *http.Request, etype string) Payload { 68 func NewPayload(r *http.Request, etype string) Payload {
69 pload := metadata[etype] 69 pload := metadata[etype]
70 pload.Method = r.Method + " " + r.RequestURI 70 pload.Method = r.Method + " " + r.RequestURI
71 return pload 71 return pload
72 } 72 }
73 73
74 // DecodeJSON decodes JSON data from r to v. 74 // DecodeJSON decodes JSON data from r to v.
75 // Returns an error if it fails. 75 // Returns an error if it fails.
76 func DecodeJSON(r io.Reader, v interface{}) error { 76 func DecodeJSON(r io.Reader, v interface{}) error {
77 return json.NewDecoder(r).Decode(v) 77 return json.NewDecoder(r).Decode(v)
78 } 78 }
79 79
80 // InitPayloadsMetadata loads all payloads' information into 'metadata' variable. 80 // InitPayloadsMetadata loads all payloads' information into 'metadata' variable.
81 func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { 81 func InitPayloadsMetadata(drv string, db *sql.DB, project string) error {
82 var err error 82 var err error
83 if drv != "ora" && drv != "mysql" { 83 if drv != "ora" && drv != "mysql" {
84 err = errors.New("driver not supported") 84 err = errors.New("driver not supported")
85 return err 85 return err
86 } 86 }
87 87
88 driver = drv 88 driver = drv
89 metadataDB = db 89 metadataDB = db
90 activeProject = project 90 activeProject = project
91 91
92 logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) 92 logger, err = gologger.New("metadata", gologger.MaxLogSize100KB)
93 if err != nil { 93 if err != nil {
94 fmt.Printf("webutility: %s\n", err.Error()) 94 fmt.Printf("webutility: %s\n", err.Error())
95 } 95 }
96 96
97 mu.Lock() 97 mu.Lock()
98 defer mu.Unlock() 98 defer mu.Unlock()
99 err = initMetadata(project) 99 err = initMetadata(project)
100 if err != nil { 100 if err != nil {
101 return err 101 return err
102 } 102 }
103 inited = true 103 inited = true
104 104
105 return nil 105 return nil
106 } 106 }
107 107
108 func EnableHotloading(interval int) { 108 func EnableHotloading(interval int) {
109 if interval > 0 { 109 if interval > 0 {
110 go hotload(interval) 110 go hotload(interval)
111 } 111 }
112 } 112 }
113 113
114 func GetMetadataForAllEntities() map[string]Payload { 114 func GetMetadataForAllEntities() map[string]Payload {
115 return metadata 115 return metadata
116 } 116 }
117 117
118 func GetMetadataForEntity(t string) (Payload, bool) { 118 func GetMetadataForEntity(t string) (Payload, bool) {
119 p, ok := metadata[t] 119 p, ok := metadata[t]
120 return p, ok 120 return p, ok
121 } 121 }
122 122
123 func QueEntityModelUpdate(entityType string, v interface{}) { 123 func QueEntityModelUpdate(entityType string, v interface{}) {
124 updateQue[entityType], _ = json.Marshal(v) 124 updateQue[entityType], _ = json.Marshal(v)
125 } 125 }
126 126
127 func UpdateEntityModels(command string) (total, upd, add int, err error) { 127 func UpdateEntityModels(command string) (total, upd, add int, err error) {
128 if command != "force" && command != "missing" { 128 if command != "force" && command != "missing" {
129 return total, 0, 0, errors.New("webutility: unknown command: " + command) 129 return total, 0, 0, errors.New("webutility: unknown command: " + command)
130 } 130 }
131 131
132 if !inited { 132 if !inited {
133 return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.") 133 return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.")
134 } 134 }
135 135
136 total = len(updateQue) 136 total = len(updateQue)
137 137
138 toUpdate := make([]string, 0) 138 toUpdate := make([]string, 0)
139 toAdd := make([]string, 0) 139 toAdd := make([]string, 0)
140 140
141 for k, _ := range updateQue { 141 for k, _ := range updateQue {
142 if _, exists := metadata[k]; exists { 142 if _, exists := metadata[k]; exists {
143 if command == "force" { 143 if command == "force" {
144 toUpdate = append(toUpdate, k) 144 toUpdate = append(toUpdate, k)
145 } 145 }
146 } else { 146 } else {
147 toAdd = append(toAdd, k) 147 toAdd = append(toAdd, k)
148 } 148 }
149 } 149 }
150 150
151 var uStmt *sql.Stmt 151 var uStmt *sql.Stmt
152 if driver == "ora" { 152 if driver == "ora" {
153 uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") 153 uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2")
154 if err != nil { 154 if err != nil {
155 logger.Trace(err.Error())
155 return 156 return
156 } 157 }
157 } else if driver == "mysql" { 158 } else if driver == "mysql" {
158 uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") 159 uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?")
159 if err != nil { 160 if err != nil {
161 logger.Trace(err.Error())
160 return 162 return
161 } 163 }
162 } 164 }
163 for _, k := range toUpdate { 165 for _, k := range toUpdate {
164 _, err = uStmt.Exec(string(updateQue[k]), k) 166 _, err = uStmt.Exec(string(updateQue[k]), k)
165 if err != nil { 167 if err != nil {
168 logger.Trace(err.Error())
166 return 169 return
167 } 170 }
168 upd++ 171 upd++
169 } 172 }
170 173
171 blankPayload, _ := json.Marshal(Payload{}) 174 blankPayload, _ := json.Marshal(Payload{})
172 var iStmt *sql.Stmt 175 var iStmt *sql.Stmt
173 if driver == "ora" { 176 if driver == "ora" {
174 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") 177 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)")
175 if err != nil { 178 if err != nil {
179 logger.Trace(err.Error())
176 return 180 return
177 } 181 }
178 } else if driver == "mysql" { 182 } else if driver == "mysql" {
179 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") 183 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)")
180 if err != nil { 184 if err != nil {
185 logger.Trace(err.Error())
181 return 186 return
182 } 187 }
183 } 188 }
184 for _, k := range toAdd { 189 for _, k := range toAdd {
185 _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) 190 _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k]))
186 if err != nil { 191 if err != nil {
192 logger.Trace(err.Error())
187 return 193 return
188 } 194 }
189 metadata[k] = Payload{} 195 metadata[k] = Payload{}
190 add++ 196 add++
191 } 197 }
192 198
193 return total, upd, add, nil 199 return total, upd, add, nil
194 } 200 }
195 201
196 func initMetadata(project string) error { 202 func initMetadata(project string) error {
197 rows, err := metadataDB.Query(`select 203 rows, err := metadataDB.Query(`select
198 entity_type, 204 entity_type,
199 metadata 205 metadata
200 from entities 206 from entities
201 where projekat = ` + fmt.Sprintf("'%s'", project)) 207 where projekat = ` + fmt.Sprintf("'%s'", project))
202 if err != nil { 208 if err != nil {
203 return err 209 return err
204 } 210 }
205 defer rows.Close() 211 defer rows.Close()
206 212
207 if len(metadata) > 0 { 213 if len(metadata) > 0 {
208 metadata = nil 214 metadata = nil
209 } 215 }
210 metadata = make(map[string]Payload) 216 metadata = make(map[string]Payload)
211 for rows.Next() { 217 for rows.Next() {
212 var name, load string 218 var name, load string
213 rows.Scan(&name, &load) 219 rows.Scan(&name, &load)
214 220
215 p := Payload{} 221 p := Payload{}
216 err := json.Unmarshal([]byte(load), &p) 222 err := json.Unmarshal([]byte(load), &p)
217 if err != nil { 223 if err != nil {
218 logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load) 224 logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load)
219 } else { 225 } else {
220 metadata[name] = p 226 metadata[name] = p
221 } 227 }
222 } 228 }
223 229
224 return nil 230 return nil
225 } 231 }
226 232
227 func hotload(n int) { 233 func hotload(n int) {
228 entityScan := make(map[string]int64) 234 entityScan := make(map[string]int64)
229 firstCheck := true 235 firstCheck := true
230 for { 236 for {
231 time.Sleep(time.Duration(n) * time.Second) 237 time.Sleep(time.Duration(n) * time.Second)
232 rows, err := metadataDB.Query(`select 238 rows, err := metadataDB.Query(`select
233 ora_rowscn, 239 ora_rowscn,
234 entity_type 240 entity_type
235 from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) 241 from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject))
236 if err != nil { 242 if err != nil {
237 logger.Log("webutility: hotload failed: %v\n", err) 243 logger.Log("webutility: hotload failed: %v\n", err)
238 time.Sleep(time.Duration(n) * time.Second) 244 time.Sleep(time.Duration(n) * time.Second)
239 continue 245 continue
240 } 246 }
241 247
242 var toRefresh []string 248 var toRefresh []string
243 for rows.Next() { 249 for rows.Next() {
244 var scanID int64 250 var scanID int64
245 var entity string 251 var entity string
246 rows.Scan(&scanID, &entity) 252 rows.Scan(&scanID, &entity)
247 oldID, ok := entityScan[entity] 253 oldID, ok := entityScan[entity]
248 if !ok || oldID != scanID { 254 if !ok || oldID != scanID {
249 entityScan[entity] = scanID 255 entityScan[entity] = scanID
250 toRefresh = append(toRefresh, entity) 256 toRefresh = append(toRefresh, entity)
251 } 257 }
252 } 258 }
253 rows.Close() 259 rows.Close()
254 260
255 if rows.Err() != nil { 261 if rows.Err() != nil {
256 logger.Log("webutility: hotload rset error: %v\n", rows.Err()) 262 logger.Log("webutility: hotload rset error: %v\n", rows.Err())
257 time.Sleep(time.Duration(n) * time.Second) 263 time.Sleep(time.Duration(n) * time.Second)
258 continue 264 continue
259 } 265 }
260 266
261 if len(toRefresh) > 0 && !firstCheck { 267 if len(toRefresh) > 0 && !firstCheck {
262 mu.Lock() 268 mu.Lock()
263 refreshMetadata(toRefresh) 269 refreshMetadata(toRefresh)
264 mu.Unlock() 270 mu.Unlock()
265 } 271 }
266 if firstCheck { 272 if firstCheck {
267 firstCheck = false 273 firstCheck = false
268 } 274 }
269 } 275 }
270 } 276 }
271 277
272 func refreshMetadata(entities []string) { 278 func refreshMetadata(entities []string) {
273 for _, e := range entities { 279 for _, e := range entities {
274 fmt.Printf("refreshing %s\n", e) 280 fmt.Printf("refreshing %s\n", e)
275 rows, err := metadataDB.Query(`select 281 rows, err := metadataDB.Query(`select
276 metadata 282 metadata
277 from entities 283 from entities
278 where projekat = ` + fmt.Sprintf("'%s'", activeProject) + 284 where projekat = ` + fmt.Sprintf("'%s'", activeProject) +
279 ` and entity_type = ` + fmt.Sprintf("'%s'", e)) 285 ` and entity_type = ` + fmt.Sprintf("'%s'", e))
280 286
281 if err != nil { 287 if err != nil {
282 logger.Log("webutility: refresh: prep: %v\n", err) 288 logger.Log("webutility: refresh: prep: %v\n", err)
283 rows.Close() 289 rows.Close()
284 continue 290 continue
285 } 291 }
286 292
287 for rows.Next() { 293 for rows.Next() {
288 var load string 294 var load string
289 rows.Scan(&load) 295 rows.Scan(&load)
290 p := Payload{} 296 p := Payload{}
291 err := json.Unmarshal([]byte(load), &p) 297 err := json.Unmarshal([]byte(load), &p)
292 if err != nil { 298 if err != nil {
293 logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) 299 logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load)
294 } else { 300 } else {
295 metadata[e] = p 301 metadata[e] = p
296 } 302 }
297 } 303 }
298 rows.Close() 304 rows.Close()
299 } 305 }
300 } 306 }
301 307
302 /* 308 /*
303 func ModifyMetadataForEntity(entityType string, p *Payload) error { 309 func ModifyMetadataForEntity(entityType string, p *Payload) error {
304 md, err := json.Marshal(*p) 310 md, err := json.Marshal(*p)
305 if err != nil { 311 if err != nil {
306 return err 312 return err
307 } 313 }
308 314
309 mu.Lock() 315 mu.Lock()
310 defer mu.Unlock() 316 defer mu.Unlock()
311 _, err = metadataDB.PrepAndExe(`update entities set 317 _, err = metadataDB.PrepAndExe(`update entities set
312 metadata = :1 318 metadata = :1
313 where projekat = :2 319 where projekat = :2
314 and entity_type = :3`, 320 and entity_type = :3`,
315 string(md), 321 string(md),
316 activeProject, 322 activeProject,
317 entityType) 323 entityType)
318 if err != nil { 324 if err != nil {
319 return err 325 return err
320 } 326 }
321 return nil 327 return nil
322 } 328 }
323 329
324 func DeleteEntityModel(entityType string) error { 330 func DeleteEntityModel(entityType string) error {
325 _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) 331 _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType)
326 if err == nil { 332 if err == nil {
327 mu.Lock() 333 mu.Lock()
328 delete(metadata, entityType) 334 delete(metadata, entityType)
329 mu.Unlock() 335 mu.Unlock()
330 } 336 }
331 return err 337 return err
332 } 338 }
333 */ 339 */
334 340