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