Skip to content

Commit 2325140

Browse files
committed
glue, manage api 2.0
1 parent 053298a commit 2325140

File tree

18 files changed

+546
-350
lines changed

18 files changed

+546
-350
lines changed

README.md

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ Specify target host and timeout for forwarding requests
5252
3) prefix or proxying - `/my/*`
5353
4) mixed `/my/{parameter}/path/*`
5454

55-
And need to define rules for our route: each rule heve `type` and options related to this kind of rule,
55+
And need to define rules for our route: each rule heve `kind` and options related to this kind of rule,
5656

5757
```json
5858
{
5959
// ...
6060
"rules": {
6161
"/posts/{id}": [ // route
6262
{
63-
"type": "cache", // rule type "cache" - simple cache strategy
63+
"kind": "cache", // rule kind "cache" - simple cache strategy
6464
"ttl": "10s", // cache ttl
6565
"key": "post-{id}", // cache key template, can contain url parameter from route
6666
"storage": "main_ha" // storage name from "storages" section that will be used for this rule
@@ -73,12 +73,12 @@ Specify target host and timeout for forwarding requests
7373
```
7474
That is, you can run `circa` and it will cache requests to GET /posts/{id} for 10 seconds and proxy all other requests
7575

76-
There are a list of rules types and parameters for each:
76+
There are a list of rules kinds and parameters for each:
7777

7878
1. Cache with ttl
7979
```json
8080
{
81-
"type": "cache", // by default
81+
"kind": "cache", // by default
8282
"ttl": "10m50s", // cache time to live Valid time units are “ns”, “us” (or “µs”), “ms”, “s”, “m”, “h”.
8383
"key": "....."
8484
}
@@ -87,7 +87,7 @@ Specify target host and timeout for forwarding requests
8787
2. Cache with early expiration -
8888
```json
8989
{
90-
"type": "early",
90+
"kind": "early",
9191
"ttl": "10h", // cache time to live
9292
"early_ttl": "1h", // time for pre invalidation
9393
"key": "....."
@@ -97,7 +97,7 @@ Specify target host and timeout for forwarding requests
9797
3. Cache with hit expiration -
9898
```json
9999
{
100-
"type": "hit",
100+
"kind": "hit",
101101
"ttl": "10h", // cache time to live
102102
"hits": 100, // number of hits before cache will be invalidated
103103
"update_after": 10, // optional; number of hits for pre invalidation
@@ -108,7 +108,7 @@ Specify target host and timeout for forwarding requests
108108
4. Failover cache -
109109
```json
110110
{
111-
"type": "fail",
111+
"kind": "fail",
112112
"ttl": "10h", // cache time to live
113113
"key": "....."
114114
}
@@ -117,7 +117,7 @@ Specify target host and timeout for forwarding requests
117117
5. Rate limit -
118118
```json
119119
{
120-
"type": "rate-limit",
120+
"kind": "rate-limit",
121121
"ttl": "10m", // limit period
122122
"hits": 100, // number of hits ( read as 100 request per 10 min)
123123
"key": "....."
@@ -127,7 +127,7 @@ Specify target host and timeout for forwarding requests
127127
6. Retry -
128128
```json
129129
{
130-
"type": "retry",
130+
"kind": "retry",
131131
"methods": ["GET", "HEAD"],
132132
"backoff": "5s",
133133
"count": 5 // retry attempts
@@ -138,7 +138,7 @@ Specify target host and timeout for forwarding requests
138138
7. request_id - `skip_return` - check that backend return response with tha same request ID
139139
```json
140140
{
141-
"type": "request_id",
141+
"kind": "request_id",
142142
"methods": ["GET", "POST", "DELETE", "PUT", "PATCH"],
143143
"skip_return": false // by default
144144
}
@@ -147,7 +147,7 @@ Specify target host and timeout for forwarding requests
147147
8. idempotency
148148
```json
149149
{
150-
"type": "idempotency",
150+
"kind": "idempotency",
151151
"ttl": "1m"
152152
// "key": "{R:body|hash}",
153153
}
@@ -156,7 +156,7 @@ Specify target host and timeout for forwarding requests
156156
9. invalidate
157157
```json
158158
{
159-
"type": "invalidate",
159+
"kind": "invalidate",
160160
"methods": ["POST", "DELETE", "PUT", "PATCH"],
161161
"key": "posts-{id}:key" // the key template that will be deleted after success request
162162
}
@@ -165,14 +165,14 @@ Specify target host and timeout for forwarding requests
165165
10. skip - will skip all rules see "Routing"
166166
```json
167167
{
168-
"type": "skip"
168+
"kind": "skip"
169169
}
170170
```
171171

172172
11. proxy - rule to change method or target host for proxing
173173
```json
174174
{
175-
"type": "proxy",
175+
"kind": "proxy",
176176
"methods": ["GET"],
177177
"path": "/posts/", // optional
178178
"method": "POST", // optional
@@ -184,20 +184,29 @@ Will proxy all get methods as post request to the https://google.com/posts/
184184
12. Glue
185185
```json
186186
{
187-
"type": "json",
188-
"paths": ["/posts", "/articles"]
187+
"kind": "glue",
188+
"model": "single", // "list"
189+
"calls": {
190+
"user_info": "/users/{id}/info",
191+
"user_meta": "/users/{id}/meta",
192+
"posts": "/posts/?user={id}"
193+
},
194+
"mapping": {
195+
"posts": "posts"
196+
} // {..info, ..meta, "posts": posts}
189197
}
190198

191199
TODO:
192-
- unix socket as target
193-
- proxy fast with no rules
194-
- glue
200+
- proxy fast with no rules [x] - with /* rule - fast tpp
201+
- cache resolve
202+
- glue[partly]
203+
- proxy header - like request-id just get and return back
204+
- cache condition - header, time, query
195205
- proxy filebody
206+
- proxy Location - bug
207+
- manage api
196208
- circuit-breaker []
197209
- rate-limit with a sliding window
198210
- hot cache ?
199-
- hot reload with config change
200211
- config flush
201-
202-
ConfigRepo (store a config) -> Config (control a rules storages and sync configRepo) -> Runner
203-
Request -> Resolver (route -> rules) -> Rule -> Handler -> Requester -> Response
212+
- unix socket as targe

config.json

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,34 @@
66
"rules": {
77
"/posts/{id}": [
88
{
9-
"kind": "idempotency",
10-
"key": "post-ide-{R:body|hash}",
11-
"ttl": "10s",
12-
"methods": ["POST"]
9+
"kind": "glue",
10+
"model": "object",
11+
"calls": {
12+
"post_main": "/posts/{id}",
13+
"post_meta": "/post_meta/{id}"
14+
}
1315
},
1416
{
15-
"key": "posts-{id}:key",
16-
"kind": "early",
17-
"storage": "mem",
18-
"early_ttl": "1m",
19-
"ttl": "10m"
17+
"kind": "invalidate",
18+
"methods": ["DELETE", "PUT", "PATCH"],
19+
"key": "posts-{id}:key"
2020
},
2121
{
2222
"kind": "invalidate",
23-
"methods": ["POST", "DELETE", "PUT", "PATCH"],
24-
"key": "posts-{id}:key"
23+
"methods": ["DELETE", "PUT", "PATCH"],
24+
"key": "posts:key"
25+
}
26+
],
27+
"/posts/": [
28+
{
29+
"key": "posts:key:{R:query}",
30+
"ttl": "10m"
31+
},
32+
{
33+
"kind": "idempotency",
34+
"key": "post-ide-{R:body|hash}",
35+
"ttl": "10s",
36+
"methods": ["POST"]
2537
}
2638
],
2739
"/posts/3": [
@@ -49,24 +61,11 @@
4961
"ttl": "1m",
5062
"key": "{R:full_path}"
5163
}
52-
],
53-
"/*": [
54-
{
55-
"kind": "request_id",
56-
"methods": ["GET", "POST", "DELETE", "PUT", "PATCH"],
57-
"skip_return": true
58-
},
59-
{
60-
"kind": "retry",
61-
"methods": ["GET", "PATCH"],
62-
"backoff": "1s",
63-
"count": 2
64-
}
65-
6664
]
6765
},
6866
"options": {
69-
"host": "http://localhost:8000",
70-
"timeout": "1m30s"
67+
"target": "http://localhost:8888",
68+
"timeout": "1m30s",
69+
"default_storage": "main"
7170
}
7271
}

config/config.go

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,54 @@ type Config struct {
4444
lock *sync.RWMutex
4545
}
4646

47+
func (c *Config) Init() error {
48+
rules, err := c.getRules()
49+
if err != nil {
50+
return err
51+
}
52+
for _, rule := range rules {
53+
c.resolver.Add(rule)
54+
}
55+
return nil
56+
}
57+
58+
func (c *Config) getRules() ([]*rules.Rule, error) {
59+
routes, err := c.repository.GetRoutes()
60+
if err != nil {
61+
return nil, err
62+
}
63+
var storage storages.Storage
64+
var ok bool
65+
defaultStorageName, err := c.repository.GetDefaultStorage()
66+
if err != nil {
67+
return nil, err
68+
}
69+
defaultStorage, ok := c.storages[defaultStorageName]
70+
if !ok {
71+
return nil, errors.New("wrong default Storage setup")
72+
}
73+
returnRules := []*rules.Rule{}
74+
75+
for _, route := range routes {
76+
rules, err := c.repository.GetRules(route)
77+
if err != nil {
78+
return nil, err
79+
}
80+
for _, ruleOptions := range rules {
81+
storage, ok = c.storages[ruleOptions.Storage]
82+
if !ok {
83+
storage = defaultStorage
84+
}
85+
rule, err := getRuleFromOptions(ruleOptions, storage, route)
86+
if err != nil {
87+
return nil, err
88+
}
89+
returnRules = append(returnRules, rule)
90+
}
91+
}
92+
return returnRules, nil
93+
}
94+
4795
func (c *Config) Resolve(path string) (rules []*rules.Rule, params map[string]string, err error) {
4896
return c.resolver.Resolve(path)
4997
}
@@ -83,6 +131,14 @@ func (c *Config) GetTimeout() (time.Duration, error) {
83131
return timeout, nil
84132
}
85133

134+
func (c *Config) GetStorages() (map[string]string, error) {
135+
return c.repository.GetStorages()
136+
}
137+
138+
func (c *Config) GetRoutes() ([]*rules.Rule, error) {
139+
return c.getRules()
140+
}
141+
86142
func NewConfigFromDSN(dsn string, resolver *resolver.Resolver) (*Config, error) {
87143
repo, err := newFileConfig(dsn)
88144
if err != nil {
@@ -101,45 +157,11 @@ func NewConfigFromDSN(dsn string, resolver *resolver.Resolver) (*Config, error)
101157
}
102158
log.Info().Msgf("Configured storage '%v' with dns '%v'", name, DSN)
103159
}
104-
105-
// defRequest := &message.Request{Host: c.Options.Target, Timeout: timeout} // Move to runner
106-
routes, err := repo.GetRoutes()
107-
if err != nil {
108-
return nil, err
109-
}
110-
var storage storages.Storage
111-
var ok bool
112-
defaultStorageName, err := repo.GetDefaultStorage()
113-
if err != nil {
114-
return nil, err
115-
}
116-
defaultStorage, ok := storagesMap[defaultStorageName]
117-
if !ok {
118-
return nil, errors.New("wrong default Storage setup")
119-
}
120-
121-
for _, route := range routes {
122-
rules, err := repo.GetRules(route)
123-
if err != nil {
124-
return nil, err
125-
}
126-
for _, ruleOptions := range rules {
127-
storage, ok = storagesMap[ruleOptions.Storage]
128-
if !ok {
129-
storage = defaultStorage
130-
}
131-
rule, err := getRuleFromOptions(ruleOptions, storage, route)
132-
if err != nil {
133-
return nil, err
134-
}
135-
136-
resolver.Add(route, rule)
137-
}
138-
}
139-
return &Config{
160+
c := Config{
140161
repository: repo,
141162
resolver: resolver,
142163
storages: storagesMap,
143164
lock: &sync.RWMutex{},
144-
}, nil
165+
}
166+
return &c, c.Init()
145167
}

config/rules.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ func getRuleProcessorFromOptions(rule Rule) (rules.RuleProcessor, error) {
5555
return convertToEarlyCacheRule(rule)
5656
case "cache":
5757
return convertToCacheRule(rule)
58+
case "glue":
59+
return convertToGlueRule(rule)
5860
case "":
5961
return convertToCacheRule(rule)
6062
}
@@ -124,6 +126,10 @@ func convertToHitRule(rule Rule) (*rules.HitRule, error) {
124126
return &rules.HitRule{TTL: ttl, Hits: rule.Hits, UpdateAfterHits: rule.UpdateAfterHits}, err
125127
}
126128

129+
func convertToGlueRule(rule Rule) (*rules.GlueRule, error) {
130+
return &rules.GlueRule{Calls: rule.Calls}, nil
131+
}
132+
127133
func timeFromString(in string) (time.Duration, error) {
128134
if in == "" {
129135
return time.Second, nil

0 commit comments

Comments
 (0)