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