Commit 1257b237add893d84a7fb973eab6506de75fb161
1 parent
f38e87cf4c
Exists in
master
todo
Showing
1 changed file
with
1 additions
and
0 deletions
Show diff stats
payload.go
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 | "os" | 10 | "os" |
11 | "strings" | 11 | "strings" |
12 | "sync" | 12 | "sync" |
13 | "time" | 13 | "time" |
14 | 14 | ||
15 | "git.to-net.rs/marko.tikvic/gologger" | 15 | "git.to-net.rs/marko.tikvic/gologger" |
16 | ) | 16 | ) |
17 | 17 | ||
18 | var ( | 18 | var ( |
19 | mu = &sync.Mutex{} | 19 | mu = &sync.Mutex{} |
20 | metadata = make(map[string]Payload) | 20 | metadata = make(map[string]Payload) |
21 | 21 | ||
22 | updateQue = make(map[string][]byte) | 22 | updateQue = make(map[string][]byte) |
23 | 23 | ||
24 | metadataDB *sql.DB | 24 | metadataDB *sql.DB |
25 | activeProject string | 25 | activeProject string |
26 | 26 | ||
27 | inited bool | 27 | inited bool |
28 | driver string | 28 | driver string |
29 | logger *gologger.Logger | 29 | logger *gologger.Logger |
30 | ) | 30 | ) |
31 | 31 | ||
32 | type LangMap map[string]map[string]string | 32 | type LangMap map[string]map[string]string |
33 | 33 | ||
34 | type Field struct { | 34 | type Field struct { |
35 | Parameter string `json:"param"` | 35 | Parameter string `json:"param"` |
36 | Type string `json:"type"` | 36 | Type string `json:"type"` |
37 | Visible bool `json:"visible"` | 37 | Visible bool `json:"visible"` |
38 | Editable bool `json:"editable"` | 38 | Editable bool `json:"editable"` |
39 | } | 39 | } |
40 | 40 | ||
41 | type CorrelationField struct { | 41 | type CorrelationField struct { |
42 | Result string `json:"result"` | 42 | Result string `json:"result"` |
43 | Elements []string `json:"elements"` | 43 | Elements []string `json:"elements"` |
44 | Type string `json:"type"` | 44 | Type string `json:"type"` |
45 | } | 45 | } |
46 | 46 | ||
47 | type Translation struct { | 47 | type Translation struct { |
48 | Language string `json:"language"` | 48 | Language string `json:"language"` |
49 | FieldsLabels map[string]string `json:"fieldsLabels"` | 49 | FieldsLabels map[string]string `json:"fieldsLabels"` |
50 | } | 50 | } |
51 | 51 | ||
52 | // output | 52 | // output |
53 | type PaginationLinks struct { | 53 | type PaginationLinks struct { |
54 | Base string `json:"base"` | 54 | Base string `json:"base"` |
55 | Next string `json:"next"` | 55 | Next string `json:"next"` |
56 | Prev string `json:"prev"` | 56 | Prev string `json:"prev"` |
57 | Self string `json:"self"` | 57 | Self string `json:"self"` |
58 | } | 58 | } |
59 | 59 | ||
60 | // input | 60 | // input |
61 | type PaginationParameters struct { | 61 | type PaginationParameters struct { |
62 | URL string `json:"-"` | 62 | URL string `json:"-"` |
63 | Offset int64 `json:"offset"` | 63 | Offset int64 `json:"offset"` |
64 | Limit int64 `json:"limit"` | 64 | Limit int64 `json:"limit"` |
65 | SortBy string `json:"sortBy"` | 65 | SortBy string `json:"sortBy"` |
66 | Order string `json:"order"` | 66 | Order string `json:"order"` |
67 | } | 67 | } |
68 | 68 | ||
69 | // TODO(marko) | 69 | // TODO(marko) |
70 | func GetPaginationParameters(req *http.Request) (p PaginationParameters) { | 70 | func GetPaginationParameters(req *http.Request) (p PaginationParameters) { |
71 | return p | 71 | return p |
72 | } | 72 | } |
73 | 73 | ||
74 | // TODO(marko) | 74 | // TODO(marko) |
75 | func (p *PaginationParameters) paginationLinks() (links PaginationLinks) { | 75 | func (p *PaginationParameters) paginationLinks() (links PaginationLinks) { |
76 | return links | 76 | return links |
77 | } | 77 | } |
78 | 78 | ||
79 | type Payload struct { | 79 | type Payload struct { |
80 | Method string `json:"method"` | 80 | Method string `json:"method"` |
81 | Params map[string]string `json:"params"` | 81 | Params map[string]string `json:"params"` |
82 | Lang []Translation `json:"lang"` | 82 | Lang []Translation `json:"lang"` |
83 | Fields []Field `json:"fields"` | 83 | Fields []Field `json:"fields"` |
84 | Correlations []CorrelationField `json:"correlationFields"` | 84 | Correlations []CorrelationField `json:"correlationFields"` |
85 | IdField string `json:"idField"` | 85 | IdField string `json:"idField"` |
86 | 86 | ||
87 | // Pagination | 87 | // Pagination |
88 | Count int64 `json:"count"` | 88 | Count int64 `json:"count"` |
89 | Total int64 `json:"total"` | 89 | Total int64 `json:"total"` |
90 | Links PaginationLinks `json:"_links"` | 90 | Links PaginationLinks `json:"_links"` |
91 | 91 | ||
92 | // Data holds JSON payload. It can't be used for itteration. | 92 | // Data holds JSON payload. It can't be used for itteration. |
93 | Data interface{} `json:"data"` | 93 | Data interface{} `json:"data"` |
94 | } | 94 | } |
95 | 95 | ||
96 | func (p *Payload) addLang(code string, labels map[string]string) { | 96 | func (p *Payload) addLang(code string, labels map[string]string) { |
97 | t := Translation{ | 97 | t := Translation{ |
98 | Language: code, | 98 | Language: code, |
99 | FieldsLabels: labels, | 99 | FieldsLabels: labels, |
100 | } | 100 | } |
101 | p.Lang = append(p.Lang, t) | 101 | p.Lang = append(p.Lang, t) |
102 | } | 102 | } |
103 | 103 | ||
104 | func (p *Payload) SetData(data interface{}) { | 104 | func (p *Payload) SetData(data interface{}) { |
105 | p.Data = data | 105 | p.Data = data |
106 | } | 106 | } |
107 | 107 | ||
108 | func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) { | 108 | func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) { |
109 | p.Count = count | 109 | p.Count = count |
110 | p.Total = total | 110 | p.Total = total |
111 | p.Links = params.paginationLinks() | 111 | p.Links = params.paginationLinks() |
112 | } | 112 | } |
113 | 113 | ||
114 | // NewPayload returs a payload sceleton for entity described with key. | 114 | // NewPayload returs a payload sceleton for entity described with key. |
115 | func NewPayload(r *http.Request, key string) Payload { | 115 | func NewPayload(r *http.Request, key string) Payload { |
116 | p := metadata[key] | 116 | p := metadata[key] |
117 | p.Method = r.Method + " " + r.RequestURI | 117 | p.Method = r.Method + " " + r.RequestURI |
118 | return p | 118 | return p |
119 | } | 119 | } |
120 | 120 | ||
121 | // DecodeJSON decodes JSON data from r to v. | 121 | // DecodeJSON decodes JSON data from r to v. |
122 | // Returns an error if it fails. | 122 | // Returns an error if it fails. |
123 | func DecodeJSON(r io.Reader, v interface{}) error { | 123 | func DecodeJSON(r io.Reader, v interface{}) error { |
124 | return json.NewDecoder(r).Decode(v) | 124 | return json.NewDecoder(r).Decode(v) |
125 | } | 125 | } |
126 | 126 | ||
127 | // InitPayloadsMetadata loads all payloads' information into 'metadata' variable. | 127 | // InitPayloadsMetadata loads all payloads' information into 'metadata' variable. |
128 | func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { | 128 | func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { |
129 | var err error | 129 | var err error |
130 | if drv != "ora" && drv != "mysql" { | 130 | if drv != "ora" && drv != "mysql" { |
131 | err = errors.New("driver not supported") | 131 | err = errors.New("driver not supported") |
132 | return err | 132 | return err |
133 | } | 133 | } |
134 | 134 | ||
135 | driver = drv | 135 | driver = drv |
136 | metadataDB = db | 136 | metadataDB = db |
137 | activeProject = project | 137 | activeProject = project |
138 | 138 | ||
139 | logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) | 139 | logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) |
140 | if err != nil { | 140 | if err != nil { |
141 | fmt.Printf("webutility: %s\n", err.Error()) | 141 | fmt.Printf("webutility: %s\n", err.Error()) |
142 | } | 142 | } |
143 | 143 | ||
144 | mu.Lock() | 144 | mu.Lock() |
145 | defer mu.Unlock() | 145 | defer mu.Unlock() |
146 | err = initMetadata(project) | 146 | err = initMetadata(project) |
147 | if err != nil { | 147 | if err != nil { |
148 | return err | 148 | return err |
149 | } | 149 | } |
150 | inited = true | 150 | inited = true |
151 | 151 | ||
152 | return nil | 152 | return nil |
153 | } | 153 | } |
154 | 154 | ||
155 | func EnableHotloading(interval int) { | 155 | func EnableHotloading(interval int) { |
156 | if interval > 0 { | 156 | if interval > 0 { |
157 | go hotload(interval) | 157 | go hotload(interval) |
158 | } | 158 | } |
159 | } | 159 | } |
160 | 160 | ||
161 | func GetMetadataForAllEntities() map[string]Payload { | 161 | func GetMetadataForAllEntities() map[string]Payload { |
162 | return metadata | 162 | return metadata |
163 | } | 163 | } |
164 | 164 | ||
165 | func GetMetadataForEntity(t string) (Payload, bool) { | 165 | func GetMetadataForEntity(t string) (Payload, bool) { |
166 | p, ok := metadata[t] | 166 | p, ok := metadata[t] |
167 | return p, ok | 167 | return p, ok |
168 | } | 168 | } |
169 | 169 | ||
170 | func QueEntityModelUpdate(entityType string, v interface{}) { | 170 | func QueEntityModelUpdate(entityType string, v interface{}) { |
171 | updateQue[entityType], _ = json.Marshal(v) | 171 | updateQue[entityType], _ = json.Marshal(v) |
172 | } | 172 | } |
173 | 173 | ||
174 | func UpdateEntityModels(command string) (total, upd, add int, err error) { | 174 | func UpdateEntityModels(command string) (total, upd, add int, err error) { |
175 | if command != "force" && command != "missing" { | 175 | if command != "force" && command != "missing" { |
176 | return total, 0, 0, errors.New("webutility: unknown command: " + command) | 176 | return total, 0, 0, errors.New("webutility: unknown command: " + command) |
177 | } | 177 | } |
178 | 178 | ||
179 | if !inited { | 179 | if !inited { |
180 | return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.") | 180 | return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.") |
181 | } | 181 | } |
182 | 182 | ||
183 | total = len(updateQue) | 183 | total = len(updateQue) |
184 | 184 | ||
185 | toUpdate := make([]string, 0) | 185 | toUpdate := make([]string, 0) |
186 | toAdd := make([]string, 0) | 186 | toAdd := make([]string, 0) |
187 | 187 | ||
188 | for k, _ := range updateQue { | 188 | for k, _ := range updateQue { |
189 | if _, exists := metadata[k]; exists { | 189 | if _, exists := metadata[k]; exists { |
190 | if command == "force" { | 190 | if command == "force" { |
191 | toUpdate = append(toUpdate, k) | 191 | toUpdate = append(toUpdate, k) |
192 | } | 192 | } |
193 | } else { | 193 | } else { |
194 | toAdd = append(toAdd, k) | 194 | toAdd = append(toAdd, k) |
195 | } | 195 | } |
196 | } | 196 | } |
197 | 197 | ||
198 | var uStmt *sql.Stmt | 198 | var uStmt *sql.Stmt |
199 | if driver == "ora" { | 199 | if driver == "ora" { |
200 | uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") | 200 | uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") |
201 | if err != nil { | 201 | if err != nil { |
202 | logger.Trace(err.Error()) | 202 | logger.Trace(err.Error()) |
203 | return | 203 | return |
204 | } | 204 | } |
205 | } else if driver == "mysql" { | 205 | } else if driver == "mysql" { |
206 | uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") | 206 | uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") |
207 | if err != nil { | 207 | if err != nil { |
208 | logger.Trace(err.Error()) | 208 | logger.Trace(err.Error()) |
209 | return | 209 | return |
210 | } | 210 | } |
211 | } | 211 | } |
212 | for _, k := range toUpdate { | 212 | for _, k := range toUpdate { |
213 | _, err = uStmt.Exec(string(updateQue[k]), k) | 213 | _, err = uStmt.Exec(string(updateQue[k]), k) |
214 | if err != nil { | 214 | if err != nil { |
215 | logger.Trace(err.Error()) | 215 | logger.Trace(err.Error()) |
216 | return | 216 | return |
217 | } | 217 | } |
218 | upd++ | 218 | upd++ |
219 | } | 219 | } |
220 | 220 | ||
221 | blankPayload, _ := json.Marshal(Payload{}) | 221 | blankPayload, _ := json.Marshal(Payload{}) |
222 | var iStmt *sql.Stmt | 222 | var iStmt *sql.Stmt |
223 | if driver == "ora" { | 223 | if driver == "ora" { |
224 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") | 224 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") |
225 | if err != nil { | 225 | if err != nil { |
226 | logger.Trace(err.Error()) | 226 | logger.Trace(err.Error()) |
227 | return | 227 | return |
228 | } | 228 | } |
229 | } else if driver == "mysql" { | 229 | } else if driver == "mysql" { |
230 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") | 230 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") |
231 | if err != nil { | 231 | if err != nil { |
232 | logger.Trace(err.Error()) | 232 | logger.Trace(err.Error()) |
233 | return | 233 | return |
234 | } | 234 | } |
235 | } | 235 | } |
236 | for _, k := range toAdd { | 236 | for _, k := range toAdd { |
237 | _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) | 237 | _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) |
238 | if err != nil { | 238 | if err != nil { |
239 | logger.Trace(err.Error()) | 239 | logger.Trace(err.Error()) |
240 | return | 240 | return |
241 | } | 241 | } |
242 | metadata[k] = Payload{} | 242 | metadata[k] = Payload{} |
243 | add++ | 243 | add++ |
244 | } | 244 | } |
245 | 245 | ||
246 | return total, upd, add, nil | 246 | return total, upd, add, nil |
247 | } | 247 | } |
248 | 248 | ||
249 | func initMetadata(project string) error { | 249 | func initMetadata(project string) error { |
250 | rows, err := metadataDB.Query(`select | 250 | rows, err := metadataDB.Query(`select |
251 | entity_type, | 251 | entity_type, |
252 | metadata | 252 | metadata |
253 | from entities | 253 | from entities |
254 | where projekat = ` + fmt.Sprintf("'%s'", project)) | 254 | where projekat = ` + fmt.Sprintf("'%s'", project)) |
255 | if err != nil { | 255 | if err != nil { |
256 | return err | 256 | return err |
257 | } | 257 | } |
258 | defer rows.Close() | 258 | defer rows.Close() |
259 | 259 | ||
260 | if len(metadata) > 0 { | 260 | if len(metadata) > 0 { |
261 | metadata = nil | 261 | metadata = nil |
262 | } | 262 | } |
263 | metadata = make(map[string]Payload) | 263 | metadata = make(map[string]Payload) |
264 | for rows.Next() { | 264 | for rows.Next() { |
265 | var name, load string | 265 | var name, load string |
266 | rows.Scan(&name, &load) | 266 | rows.Scan(&name, &load) |
267 | 267 | ||
268 | p := Payload{} | 268 | p := Payload{} |
269 | err := json.Unmarshal([]byte(load), &p) | 269 | err := json.Unmarshal([]byte(load), &p) |
270 | if err != nil { | 270 | if err != nil { |
271 | logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load) | 271 | logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load) |
272 | } else { | 272 | } else { |
273 | metadata[name] = p | 273 | metadata[name] = p |
274 | } | 274 | } |
275 | } | 275 | } |
276 | 276 | ||
277 | return nil | 277 | return nil |
278 | } | 278 | } |
279 | 279 | ||
280 | // TODO(marko): | 280 | // TODO(marko): |
281 | // | 281 | // |
282 | // Currently supports only one hardcoded language... | 282 | // Currently supports only one hardcoded language... |
283 | // | 283 | // |
284 | // | 284 | // |
285 | // | 285 | // |
286 | // | 286 | // |
287 | // | 287 | // |
288 | // Metadata file ecpected format: | 288 | // Metadata file ecpected format: |
289 | // | 289 | // |
290 | // [ payload A identifier ] | 290 | // [ payload A identifier ] |
291 | // key1 : value1 | 291 | // key1 : value1 |
292 | // key2 : value2 | 292 | // key2 : value2 |
293 | // ... | 293 | // ... |
294 | // [ payload B identifier ] | 294 | // [ payload B identifier ] |
295 | // key1 : value1 | 295 | // key1 : value1 |
296 | // key2 : value2 | 296 | // key2 : value2 |
297 | // ... | 297 | // ... |
298 | func LoadMetadataFromFile(path string) error { | 298 | func LoadMetadataFromFile(path string) error { |
299 | lines, err := ReadFileLines(path) | 299 | lines, err := ReadFileLines(path) |
300 | if err != nil { | 300 | if err != nil { |
301 | return err | 301 | return err |
302 | } | 302 | } |
303 | 303 | ||
304 | metadata = make(map[string]Payload) | 304 | metadata = make(map[string]Payload) |
305 | 305 | ||
306 | var name string | 306 | var name string |
307 | for i, l := range lines { | 307 | for i, l := range lines { |
308 | // skip empty lines | 308 | // skip empty lines |
309 | if l = trimSpaces(l); len(l) == 0 { | 309 | if l = trimSpaces(l); len(l) == 0 { |
310 | continue | 310 | continue |
311 | } | 311 | } |
312 | 312 | ||
313 | if isWrappedWith(l, "[", "]") { | 313 | if isWrappedWith(l, "[", "]") { |
314 | name = strings.Trim(l, "[]") | 314 | name = strings.Trim(l, "[]") |
315 | p := Payload{} | 315 | p := Payload{} |
316 | p.addLang("sr", make(map[string]string)) | 316 | p.addLang("sr", make(map[string]string)) |
317 | metadata[name] = p | 317 | metadata[name] = p |
318 | continue | 318 | continue |
319 | } | 319 | } |
320 | 320 | ||
321 | if name == "" { | 321 | if name == "" { |
322 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]\n", i+1, l) | 322 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]\n", i+1, l) |
323 | } | 323 | } |
324 | 324 | ||
325 | parts := strings.Split(l, ":") | 325 | parts := strings.Split(l, ":") |
326 | if len(parts) != 2 { | 326 | if len(parts) != 2 { |
327 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]\n", i+1, l) | 327 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]\n", i+1, l) |
328 | } | 328 | } |
329 | 329 | ||
330 | k := trimSpaces(parts[0]) | 330 | k := trimSpaces(parts[0]) |
331 | v := trimSpaces(parts[1]) | 331 | v := trimSpaces(parts[1]) |
332 | if v != "-" { | 332 | if v != "-" { |
333 | metadata[name].Lang[0].FieldsLabels[k] = v | 333 | metadata[name].Lang[0].FieldsLabels[k] = v |
334 | } | 334 | } |
335 | } | 335 | } |
336 | 336 | ||
337 | return nil | 337 | return nil |
338 | } | 338 | } |
339 | 339 | ||
340 | func isWrappedWith(src, begin, end string) bool { | 340 | func isWrappedWith(src, begin, end string) bool { |
341 | return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end) | 341 | return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end) |
342 | } | 342 | } |
343 | 343 | ||
344 | func trimSpaces(s string) string { | 344 | func trimSpaces(s string) string { |
345 | return strings.TrimSpace(s) | 345 | return strings.TrimSpace(s) |
346 | } | 346 | } |
347 | 347 | ||
348 | // TODO(marko): Move to separate package | ||
348 | func ReadFileLines(path string) ([]string, error) { | 349 | func ReadFileLines(path string) ([]string, error) { |
349 | f, err := os.Open(path) | 350 | f, err := os.Open(path) |
350 | if err != nil { | 351 | if err != nil { |
351 | return nil, err | 352 | return nil, err |
352 | } | 353 | } |
353 | defer f.Close() | 354 | defer f.Close() |
354 | 355 | ||
355 | var s strings.Builder | 356 | var s strings.Builder |
356 | 357 | ||
357 | if _, err = io.Copy(&s, f); err != nil { | 358 | if _, err = io.Copy(&s, f); err != nil { |
358 | return nil, err | 359 | return nil, err |
359 | } | 360 | } |
360 | 361 | ||
361 | lines := strings.Split(s.String(), "\n") | 362 | lines := strings.Split(s.String(), "\n") |
362 | 363 | ||
363 | return lines, nil | 364 | return lines, nil |
364 | } | 365 | } |
365 | 366 | ||
366 | func hotload(n int) { | 367 | func hotload(n int) { |
367 | entityScan := make(map[string]int64) | 368 | entityScan := make(map[string]int64) |
368 | firstCheck := true | 369 | firstCheck := true |
369 | for { | 370 | for { |
370 | time.Sleep(time.Duration(n) * time.Second) | 371 | time.Sleep(time.Duration(n) * time.Second) |
371 | rows, err := metadataDB.Query(`select | 372 | rows, err := metadataDB.Query(`select |
372 | ora_rowscn, | 373 | ora_rowscn, |
373 | entity_type | 374 | entity_type |
374 | from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) | 375 | from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) |
375 | if err != nil { | 376 | if err != nil { |
376 | logger.Log("webutility: hotload failed: %v\n", err) | 377 | logger.Log("webutility: hotload failed: %v\n", err) |
377 | time.Sleep(time.Duration(n) * time.Second) | 378 | time.Sleep(time.Duration(n) * time.Second) |
378 | continue | 379 | continue |
379 | } | 380 | } |
380 | 381 | ||
381 | var toRefresh []string | 382 | var toRefresh []string |
382 | for rows.Next() { | 383 | for rows.Next() { |
383 | var scanID int64 | 384 | var scanID int64 |
384 | var entity string | 385 | var entity string |
385 | rows.Scan(&scanID, &entity) | 386 | rows.Scan(&scanID, &entity) |
386 | oldID, ok := entityScan[entity] | 387 | oldID, ok := entityScan[entity] |
387 | if !ok || oldID != scanID { | 388 | if !ok || oldID != scanID { |
388 | entityScan[entity] = scanID | 389 | entityScan[entity] = scanID |
389 | toRefresh = append(toRefresh, entity) | 390 | toRefresh = append(toRefresh, entity) |
390 | } | 391 | } |
391 | } | 392 | } |
392 | rows.Close() | 393 | rows.Close() |
393 | 394 | ||
394 | if rows.Err() != nil { | 395 | if rows.Err() != nil { |
395 | logger.Log("webutility: hotload rset error: %v\n", rows.Err()) | 396 | logger.Log("webutility: hotload rset error: %v\n", rows.Err()) |
396 | time.Sleep(time.Duration(n) * time.Second) | 397 | time.Sleep(time.Duration(n) * time.Second) |
397 | continue | 398 | continue |
398 | } | 399 | } |
399 | 400 | ||
400 | if len(toRefresh) > 0 && !firstCheck { | 401 | if len(toRefresh) > 0 && !firstCheck { |
401 | mu.Lock() | 402 | mu.Lock() |
402 | refreshMetadata(toRefresh) | 403 | refreshMetadata(toRefresh) |
403 | mu.Unlock() | 404 | mu.Unlock() |
404 | } | 405 | } |
405 | if firstCheck { | 406 | if firstCheck { |
406 | firstCheck = false | 407 | firstCheck = false |
407 | } | 408 | } |
408 | } | 409 | } |
409 | } | 410 | } |
410 | 411 | ||
411 | func refreshMetadata(entities []string) { | 412 | func refreshMetadata(entities []string) { |
412 | for _, e := range entities { | 413 | for _, e := range entities { |
413 | fmt.Printf("refreshing %s\n", e) | 414 | fmt.Printf("refreshing %s\n", e) |
414 | rows, err := metadataDB.Query(`select | 415 | rows, err := metadataDB.Query(`select |
415 | metadata | 416 | metadata |
416 | from entities | 417 | from entities |
417 | where projekat = ` + fmt.Sprintf("'%s'", activeProject) + | 418 | where projekat = ` + fmt.Sprintf("'%s'", activeProject) + |
418 | ` and entity_type = ` + fmt.Sprintf("'%s'", e)) | 419 | ` and entity_type = ` + fmt.Sprintf("'%s'", e)) |
419 | 420 | ||
420 | if err != nil { | 421 | if err != nil { |
421 | logger.Log("webutility: refresh: prep: %v\n", err) | 422 | logger.Log("webutility: refresh: prep: %v\n", err) |
422 | rows.Close() | 423 | rows.Close() |
423 | continue | 424 | continue |
424 | } | 425 | } |
425 | 426 | ||
426 | for rows.Next() { | 427 | for rows.Next() { |
427 | var load string | 428 | var load string |
428 | rows.Scan(&load) | 429 | rows.Scan(&load) |
429 | p := Payload{} | 430 | p := Payload{} |
430 | err := json.Unmarshal([]byte(load), &p) | 431 | err := json.Unmarshal([]byte(load), &p) |
431 | if err != nil { | 432 | if err != nil { |
432 | logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) | 433 | logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) |
433 | } else { | 434 | } else { |
434 | metadata[e] = p | 435 | metadata[e] = p |
435 | } | 436 | } |
436 | } | 437 | } |
437 | rows.Close() | 438 | rows.Close() |
438 | } | 439 | } |
439 | } | 440 | } |
440 | 441 | ||
441 | /* | 442 | /* |
442 | func ModifyMetadataForEntity(entityType string, p *Payload) error { | 443 | func ModifyMetadataForEntity(entityType string, p *Payload) error { |
443 | md, err := json.Marshal(*p) | 444 | md, err := json.Marshal(*p) |
444 | if err != nil { | 445 | if err != nil { |
445 | return err | 446 | return err |
446 | } | 447 | } |
447 | 448 | ||
448 | mu.Lock() | 449 | mu.Lock() |
449 | defer mu.Unlock() | 450 | defer mu.Unlock() |
450 | _, err = metadataDB.PrepAndExe(`update entities set | 451 | _, err = metadataDB.PrepAndExe(`update entities set |
451 | metadata = :1 | 452 | metadata = :1 |
452 | where projekat = :2 | 453 | where projekat = :2 |
453 | and entity_type = :3`, | 454 | and entity_type = :3`, |
454 | string(md), | 455 | string(md), |
455 | activeProject, | 456 | activeProject, |
456 | entityType) | 457 | entityType) |
457 | if err != nil { | 458 | if err != nil { |
458 | return err | 459 | return err |
459 | } | 460 | } |
460 | return nil | 461 | return nil |
461 | } | 462 | } |
462 | 463 | ||
463 | func DeleteEntityModel(entityType string) error { | 464 | func DeleteEntityModel(entityType string) error { |
464 | _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) | 465 | _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) |
465 | if err == nil { | 466 | if err == nil { |
466 | mu.Lock() | 467 | mu.Lock() |
467 | delete(metadata, entityType) | 468 | delete(metadata, entityType) |
468 | mu.Unlock() | 469 | mu.Unlock() |
469 | } | 470 | } |
470 | return err | 471 | return err |
471 | } | 472 | } |
472 | */ | 473 | */ |
473 | 474 |