Blame view
payload.go
9.34 KB
ea858b8a7 refactoring |
1 |
package webutility |
64041a2ea first commit |
2 3 |
import ( |
79071a5d4 Using database/sq... |
4 |
"database/sql" |
8dbe745c3 merged tables uti... |
5 |
"encoding/json" |
f84e7607d added dictionary;... |
6 |
"errors" |
66478e04f payload now retur... |
7 |
"fmt" |
8dbe745c3 merged tables uti... |
8 |
"io" |
d2ddf82ef started on new rbac |
9 |
"net/http" |
68e590a60 load metadata fro... |
10 |
"strings" |
17a4d0447 mutex lock for pa... |
11 |
"sync" |
2ea67927f added support for... |
12 |
"time" |
64041a2ea first commit |
13 |
) |
2ea67927f added support for... |
14 |
var ( |
3fffcb954 removed old http API |
15 16 |
mu = &sync.Mutex{} metadata = make(map[string]Payload) |
67337ffa8 payload editing |
17 |
updateQue = make(map[string][]byte) |
2ea67927f added support for... |
18 |
|
79071a5d4 Using database/sq... |
19 |
metadataDB *sql.DB |
2ea67927f added support for... |
20 |
activeProject string |
18fcd6d6b merged with util ... |
21 22 |
inited bool metaDriver string |
2ea67927f added support for... |
23 |
) |
8dbe745c3 merged tables uti... |
24 |
|
707782344 lint; vet |
25 |
// LangMap ... |
64041a2ea first commit |
26 |
type LangMap map[string]map[string]string |
707782344 lint; vet |
27 |
// Field ... |
64041a2ea first commit |
28 |
type Field struct { |
d2ddf82ef started on new rbac |
29 30 31 32 |
Parameter string `json:"param"` Type string `json:"type"` Visible bool `json:"visible"` Editable bool `json:"editable"` |
64041a2ea first commit |
33 |
} |
707782344 lint; vet |
34 |
// CorrelationField ... |
8dbe745c3 merged tables uti... |
35 36 37 38 39 |
type CorrelationField struct { Result string `json:"result"` Elements []string `json:"elements"` Type string `json:"type"` } |
707782344 lint; vet |
40 |
// Translation ... |
8dbe745c3 merged tables uti... |
41 |
type Translation struct { |
ecec68b18 updated todo list |
42 |
Language string `json:"language"` |
8dbe745c3 merged tables uti... |
43 |
FieldsLabels map[string]string `json:"fieldsLabels"` |
64041a2ea first commit |
44 |
} |
707782344 lint; vet |
45 |
// PaginationLinks ... |
31a4e1302 started work on p... |
46 47 48 49 50 51 |
type PaginationLinks struct { Base string `json:"base"` Next string `json:"next"` Prev string `json:"prev"` Self string `json:"self"` } |
707782344 lint; vet |
52 |
// PaginationParameters ... |
31a4e1302 started work on p... |
53 |
type PaginationParameters struct { |
368c7f87b pagination work |
54 |
URL string `json:"-"` |
31a4e1302 started work on p... |
55 56 57 58 59 |
Offset int64 `json:"offset"` Limit int64 `json:"limit"` SortBy string `json:"sortBy"` Order string `json:"order"` } |
707782344 lint; vet |
60 |
// GetPaginationParameters ... |
368c7f87b pagination work |
61 62 63 64 65 66 67 68 69 |
// TODO(marko) func GetPaginationParameters(req *http.Request) (p PaginationParameters) { return p } // TODO(marko) func (p *PaginationParameters) paginationLinks() (links PaginationLinks) { return links } |
707782344 lint; vet |
70 |
// Payload ... |
4a51e54d7 simplified |
71 |
type Payload struct { |
d2ddf82ef started on new rbac |
72 73 74 75 |
Method string `json:"method"` Params map[string]string `json:"params"` Lang []Translation `json:"lang"` Fields []Field `json:"fields"` |
4a51e54d7 simplified |
76 |
Correlations []CorrelationField `json:"correlationFields"` |
707782344 lint; vet |
77 |
IDField string `json:"idField"` |
e1fbb41f9 added comments |
78 |
|
31a4e1302 started work on p... |
79 |
// Pagination |
368c7f87b pagination work |
80 81 82 |
Count int64 `json:"count"` Total int64 `json:"total"` Links PaginationLinks `json:"_links"` |
31a4e1302 started work on p... |
83 84 |
// Data holds JSON payload. It can't be used for itteration. |
d2ddf82ef started on new rbac |
85 |
Data interface{} `json:"data"` |
4a51e54d7 simplified |
86 |
} |
8a070abe2 improved |
87 88 89 90 91 92 93 |
func (p *Payload) addLang(code string, labels map[string]string) { t := Translation{ Language: code, FieldsLabels: labels, } p.Lang = append(p.Lang, t) } |
707782344 lint; vet |
94 |
// SetData ... |
ad8e9dd2a added middleware ... |
95 96 97 |
func (p *Payload) SetData(data interface{}) { p.Data = data } |
707782344 lint; vet |
98 |
// SetPaginationInfo ... |
368c7f87b pagination work |
99 |
func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) { |
31a4e1302 started work on p... |
100 101 |
p.Count = count p.Total = total |
368c7f87b pagination work |
102 |
p.Links = params.paginationLinks() |
31a4e1302 started work on p... |
103 |
} |
368c7f87b pagination work |
104 105 106 107 108 |
// NewPayload returs a payload sceleton for entity described with key. func NewPayload(r *http.Request, key string) Payload { p := metadata[key] p.Method = r.Method + " " + r.RequestURI return p |
79071a5d4 Using database/sq... |
109 110 111 112 113 114 115 |
} // DecodeJSON decodes JSON data from r to v. // Returns an error if it fails. func DecodeJSON(r io.Reader, v interface{}) error { return json.NewDecoder(r).Decode(v) } |
f84e7607d added dictionary;... |
116 117 |
// InitPayloadsMetadata loads all payloads' information into 'metadata' variable. func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { |
1b7dfab73 Payload changed t... |
118 |
var err error |
f84e7607d added dictionary;... |
119 |
if drv != "ora" && drv != "mysql" { |
1b7dfab73 Payload changed t... |
120 121 |
err = errors.New("driver not supported") return err |
f84e7607d added dictionary;... |
122 |
} |
1b7dfab73 Payload changed t... |
123 |
|
18fcd6d6b merged with util ... |
124 |
metaDriver = drv |
2ea67927f added support for... |
125 126 |
metadataDB = db activeProject = project |
62a69beda Init/Reload Table... |
127 |
|
2ea67927f added support for... |
128 129 |
mu.Lock() defer mu.Unlock() |
1b7dfab73 Payload changed t... |
130 |
err = initMetadata(project) |
d66628295 cleaned up |
131 132 133 |
if err != nil { return err } |
2ea67927f added support for... |
134 135 136 137 |
inited = true return nil } |
707782344 lint; vet |
138 |
// EnableHotloading ... |
61efd58cd Put hotload enabl... |
139 140 141 142 143 |
func EnableHotloading(interval int) { if interval > 0 { go hotload(interval) } } |
707782344 lint; vet |
144 |
// GetMetadataForAllEntities ... |
67337ffa8 payload editing |
145 146 147 |
func GetMetadataForAllEntities() map[string]Payload { return metadata } |
707782344 lint; vet |
148 |
// GetMetadataForEntity ... |
67337ffa8 payload editing |
149 150 151 152 |
func GetMetadataForEntity(t string) (Payload, bool) { p, ok := metadata[t] return p, ok } |
707782344 lint; vet |
153 |
// QueEntityModelUpdate ... |
67337ffa8 payload editing |
154 155 156 |
func QueEntityModelUpdate(entityType string, v interface{}) { updateQue[entityType], _ = json.Marshal(v) } |
707782344 lint; vet |
157 |
// UpdateEntityModels ... |
63b2ae620 renamed files |
158 159 160 161 162 163 |
func UpdateEntityModels(command string) (total, upd, add int, err error) { if command != "force" && command != "missing" { return total, 0, 0, errors.New("webutility: unknown command: " + command) } if !inited { |
707782344 lint; vet |
164 |
return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried") |
63b2ae620 renamed files |
165 166 167 168 169 170 |
} total = len(updateQue) toUpdate := make([]string, 0) toAdd := make([]string, 0) |
707782344 lint; vet |
171 |
for k := range updateQue { |
63b2ae620 renamed files |
172 173 174 175 176 177 178 179 180 181 |
if _, exists := metadata[k]; exists { if command == "force" { toUpdate = append(toUpdate, k) } } else { toAdd = append(toAdd, k) } } var uStmt *sql.Stmt |
18fcd6d6b merged with util ... |
182 |
if metaDriver == "ora" { |
63b2ae620 renamed files |
183 184 185 186 |
uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") if err != nil { return } |
18fcd6d6b merged with util ... |
187 |
} else if metaDriver == "mysql" { |
63b2ae620 renamed files |
188 189 190 191 192 193 |
uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") if err != nil { return } } for _, k := range toUpdate { |
63b2ae620 renamed files |
194 195 |
_, err = uStmt.Exec(string(updateQue[k]), k) if err != nil { |
63b2ae620 renamed files |
196 197 198 199 200 201 202 |
return } upd++ } blankPayload, _ := json.Marshal(Payload{}) var iStmt *sql.Stmt |
18fcd6d6b merged with util ... |
203 |
if metaDriver == "ora" { |
63b2ae620 renamed files |
204 205 206 207 |
iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") if err != nil { return } |
18fcd6d6b merged with util ... |
208 |
} else if metaDriver == "mysql" { |
63b2ae620 renamed files |
209 210 211 212 213 214 215 216 |
iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") if err != nil { return } } for _, k := range toAdd { _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) if err != nil { |
63b2ae620 renamed files |
217 218 219 220 221 222 223 224 |
return } metadata[k] = Payload{} add++ } return total, upd, add, nil } |
79071a5d4 Using database/sq... |
225 226 227 228 229 230 231 232 233 234 |
func initMetadata(project string) error { rows, err := metadataDB.Query(`select entity_type, metadata from entities where projekat = ` + fmt.Sprintf("'%s'", project)) if err != nil { return err } defer rows.Close() |
79071a5d4 Using database/sq... |
235 236 237 238 239 240 241 242 243 244 245 |
if len(metadata) > 0 { metadata = nil } metadata = make(map[string]Payload) for rows.Next() { var name, load string rows.Scan(&name, &load) p := Payload{} err := json.Unmarshal([]byte(load), &p) if err != nil { |
b3f1275cd refactored middle... |
246 247 248 |
fmt.Printf("webutility: couldn't init: '%s' metadata: %s: %s ", name, err.Error(), load) |
79071a5d4 Using database/sq... |
249 |
} else { |
79071a5d4 Using database/sq... |
250 251 |
metadata[name] = p } |
79071a5d4 Using database/sq... |
252 |
} |
79071a5d4 Using database/sq... |
253 254 255 |
return nil } |
707782344 lint; vet |
256 |
// LoadMetadataFromFile expects file in format: |
8a070abe2 improved |
257 258 |
// // [ payload A identifier ] |
d9855ed8c : -> = |
259 260 |
// key1 = value1 // key2 = value2 |
8a070abe2 improved |
261 262 |
// ... // [ payload B identifier ] |
d9855ed8c : -> = |
263 264 |
// key1 = value1 // key2 = value2 |
8a070abe2 improved |
265 |
// ... |
707782344 lint; vet |
266 267 |
// // TODO(marko): Currently supports only one hardcoded language... |
68e590a60 load metadata fro... |
268 |
func LoadMetadataFromFile(path string) error { |
18fcd6d6b merged with util ... |
269 |
lines, err := ReadFileLines(path) |
68e590a60 load metadata fro... |
270 271 272 |
if err != nil { return err } |
68e590a60 load metadata fro... |
273 274 275 |
metadata = make(map[string]Payload) var name string |
3ad172fb6 refactored and ma... |
276 |
for i, l := range lines { |
8a070abe2 improved |
277 |
// skip empty lines |
f74a6c349 refactored |
278 |
if l = strings.TrimSpace(l); len(l) == 0 { |
3ad172fb6 refactored and ma... |
279 280 |
continue } |
18fcd6d6b merged with util ... |
281 |
if IsWrappedWith(l, "[", "]") { |
68e590a60 load metadata fro... |
282 |
name = strings.Trim(l, "[]") |
8a070abe2 improved |
283 284 285 |
p := Payload{} p.addLang("sr", make(map[string]string)) metadata[name] = p |
68e590a60 load metadata fro... |
286 287 |
continue } |
3ad172fb6 refactored and ma... |
288 |
if name == "" { |
707782344 lint; vet |
289 |
return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]", i+1, l) |
3ad172fb6 refactored and ma... |
290 |
} |
d9855ed8c : -> = |
291 |
parts := strings.Split(l, "=") |
8a070abe2 improved |
292 |
if len(parts) != 2 { |
707782344 lint; vet |
293 |
return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]", i+1, l) |
3ad172fb6 refactored and ma... |
294 |
} |
f74a6c349 refactored |
295 296 |
k := strings.TrimSpace(parts[0]) v := strings.TrimSpace(parts[1]) |
3ad172fb6 refactored and ma... |
297 298 |
if v != "-" { metadata[name].Lang[0].FieldsLabels[k] = v |
68e590a60 load metadata fro... |
299 300 301 302 303 |
} } return nil } |
79071a5d4 Using database/sq... |
304 305 306 307 308 309 310 311 312 313 |
func hotload(n int) { entityScan := make(map[string]int64) firstCheck := true for { time.Sleep(time.Duration(n) * time.Second) rows, err := metadataDB.Query(`select ora_rowscn, entity_type from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) if err != nil { |
b3f1275cd refactored middle... |
314 315 |
fmt.Printf("webutility: hotload failed: %v ", err) |
79071a5d4 Using database/sq... |
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
time.Sleep(time.Duration(n) * time.Second) continue } var toRefresh []string for rows.Next() { var scanID int64 var entity string rows.Scan(&scanID, &entity) oldID, ok := entityScan[entity] if !ok || oldID != scanID { entityScan[entity] = scanID toRefresh = append(toRefresh, entity) } } rows.Close() if rows.Err() != nil { |
b3f1275cd refactored middle... |
334 335 |
fmt.Printf("webutility: hotload rset error: %v ", rows.Err()) |
79071a5d4 Using database/sq... |
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
time.Sleep(time.Duration(n) * time.Second) continue } if len(toRefresh) > 0 && !firstCheck { mu.Lock() refreshMetadata(toRefresh) mu.Unlock() } if firstCheck { firstCheck = false } } } func refreshMetadata(entities []string) { for _, e := range entities { fmt.Printf("refreshing %s ", e) rows, err := metadataDB.Query(`select metadata from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject) + ` and entity_type = ` + fmt.Sprintf("'%s'", e)) if err != nil { |
b3f1275cd refactored middle... |
362 363 |
fmt.Printf("webutility: refresh: prep: %v ", err) |
79071a5d4 Using database/sq... |
364 365 366 367 368 369 370 371 372 373 |
rows.Close() continue } for rows.Next() { var load string rows.Scan(&load) p := Payload{} err := json.Unmarshal([]byte(load), &p) if err != nil { |
b3f1275cd refactored middle... |
374 375 376 |
fmt.Printf("webutility: couldn't refresh: '%s' metadata: %s %s ", e, err.Error(), load) |
79071a5d4 Using database/sq... |
377 378 379 380 381 382 383 |
} else { metadata[e] = p } } rows.Close() } } |
f84e7607d added dictionary;... |
384 |
/* |
67337ffa8 payload editing |
385 386 |
func ModifyMetadataForEntity(entityType string, p *Payload) error { md, err := json.Marshal(*p) |
2ea67927f added support for... |
387 388 389 |
if err != nil { return err } |
67337ffa8 payload editing |
390 |
|
d66628295 cleaned up |
391 392 |
mu.Lock() defer mu.Unlock() |
2ea67927f added support for... |
393 394 395 396 397 398 399 400 401 |
_, err = metadataDB.PrepAndExe(`update entities set metadata = :1 where projekat = :2 and entity_type = :3`, string(md), activeProject, entityType) if err != nil { return err |
d66628295 cleaned up |
402 403 404 |
} return nil } |
67337ffa8 payload editing |
405 406 407 408 409 410 411 412 |
func DeleteEntityModel(entityType string) error { _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) if err == nil { mu.Lock() delete(metadata, entityType) mu.Unlock() } return err |
d66628295 cleaned up |
413 |
} |
79071a5d4 Using database/sq... |
414 |
*/ |