Skip to content

Commit b35b002

Browse files
committed
exporting methods
1 parent e3e257e commit b35b002

22 files changed

+696
-595
lines changed

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@
55
To create distributed systems in a simple, elegant and safe way.
66
</p>
77
</div>
8-
9-
[//]: # (<a href="https://github.com/syntax-framework/syntax"><img width="160" src="./docs/logo-syntax.png" /></a>)
10-
11-
[//]: # ()
12-
[//]: # (**chain** is part of the [Syntax Framework]&#40;https://github.com/syntax-framework/syntax&#41;)
13-
148
---
159

1610
Chain is a core library that tries to provide all the necessary machinery to create distributed systems in a simple,

context.go

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package chain
33
import (
44
"context"
55
"net/http"
6-
"strings"
76
)
87

98
type chainContextKey struct{}
@@ -32,19 +31,17 @@ type Context struct {
3231
data map[any]any
3332
handler Handle
3433
router *Router
35-
MatchedRoutePath string
34+
Route *RouteInfo
3635
Writer http.ResponseWriter
3736
Request *http.Request
3837
Crypto *cryptoImpl
39-
root *Context
38+
parent *Context
39+
index int
4040
children []*Context
4141
}
4242

4343
// Set define um valor compartilhado no contexto de execução da requisição
4444
func (ctx *Context) Set(key any, value any) {
45-
if ctx.root != nil {
46-
ctx.root.Set(key, value)
47-
}
4845
if ctx.data == nil {
4946
ctx.data = make(map[any]any)
5047
}
@@ -53,46 +50,86 @@ func (ctx *Context) Set(key any, value any) {
5350

5451
// Get obtém um valor compartilhado no contexto de execução da requisição
5552
func (ctx *Context) Get(key any) (any, bool) {
56-
if ctx.root != nil {
57-
return ctx.root.Get(key)
53+
if ctx.data != nil {
54+
value, exists := ctx.data[key]
55+
if exists {
56+
return value, exists
57+
}
5858
}
5959

60-
if ctx.data == nil {
61-
return nil, false
60+
if ctx.parent != nil {
61+
return ctx.parent.Get(key)
6262
}
63-
value, exists := ctx.data[key]
64-
return value, exists
63+
return nil, false
6564
}
6665

67-
func (ctx *Context) WithParams(names []string, values []string) *Context {
66+
func (ctx *Context) Destroy() {
67+
if ctx.parent == nil {
68+
// root context, will be removed automaticaly
69+
return
70+
}
71+
if ctx.parent.children != nil {
72+
ctx.parent.children[ctx.index] = nil
73+
}
74+
ctx.parent = nil
75+
ctx.children = nil
76+
77+
if ctx.router != nil {
78+
ctx.router.poolPutContext(ctx)
79+
}
80+
}
81+
82+
func (ctx *Context) Child() *Context {
6883
var child *Context
6984
if ctx.router != nil {
70-
child = ctx.router.GetContext(ctx.Request, ctx.Writer, "")
85+
child = ctx.router.poolGetContext(ctx.Request, ctx.Writer, "")
7186
} else {
7287
child = &Context{
73-
Writer: ctx.Writer,
74-
Request: ctx.Request,
75-
handler: ctx.handler,
76-
paramCount: len(names),
77-
paramNames: ctx.paramNames,
78-
paramValues: ctx.paramValues,
88+
path: ctx.path,
89+
Crypto: crypt,
90+
Writer: ctx.Writer,
91+
Request: ctx.Request,
92+
handler: ctx.handler,
7993
}
8094
}
81-
for i := 0; i < len(names); i++ {
82-
child.paramNames[i] = names[i]
83-
child.paramValues[i] = values[i]
95+
96+
child.paramCount = ctx.paramCount
97+
child.paramNames = ctx.paramNames
98+
child.paramValues = ctx.paramValues
99+
child.pathSegments = ctx.pathSegments
100+
child.pathSegmentsCount = ctx.pathSegmentsCount
101+
child.Route = ctx.Route
102+
103+
child.parent = ctx
104+
105+
if ctx.children == nil {
106+
ctx.children = make([]*Context, 0)
84107
}
108+
child.index = len(ctx.children)
109+
ctx.children = append(ctx.children, child)
85110

86-
if ctx.root == nil {
87-
child.root = ctx
88-
} else {
89-
child.root = ctx.root
111+
return child
112+
}
113+
114+
// func (ctx *Context) With(key any, value any) *Context {
115+
116+
// }
117+
118+
func (ctx *Context) WithParams(names []string, values []string) *Context {
119+
child := ctx.Child()
120+
child.paramCount = len(names)
121+
child.paramNames = [32]string{}
122+
child.paramValues = [32]string{}
123+
124+
for i, name := range ctx.paramNames {
125+
child.paramNames[i] = name
126+
child.paramValues[i] = ctx.paramValues[i]
90127
}
91128

92-
if child.root.children == nil {
93-
child.root.children = make([]*Context, 0)
129+
for i := 0; i < len(names); i++ {
130+
child.paramNames[i] = names[i]
131+
child.paramValues[i] = values[i]
94132
}
95-
child.root.children = append(child.root.children, child)
96133

97134
return child
98135
}
@@ -145,30 +182,5 @@ func (ctx *Context) addParameter(name string, value string) {
145182
}
146183

147184
func (ctx *Context) parsePathSegments() {
148-
var (
149-
segmentStart = 0
150-
segmentSize int
151-
path = ctx.path
152-
)
153-
if len(path) > 0 {
154-
path = path[1:]
155-
}
156-
157-
ctx.pathSegments[0] = 0
158-
ctx.pathSegmentsCount = 1
159-
160-
for {
161-
segmentSize = strings.IndexByte(path, separator)
162-
if segmentSize == -1 {
163-
segmentSize = len(path)
164-
}
165-
ctx.pathSegments[ctx.pathSegmentsCount] = segmentStart + 1 + segmentSize
166-
167-
if segmentSize == len(path) {
168-
break
169-
}
170-
ctx.pathSegmentsCount++
171-
path = path[segmentSize+1:]
172-
segmentStart = segmentStart + 1 + segmentSize
173-
}
185+
ctx.pathSegmentsCount = parsePathSegments(ctx.path, &ctx.pathSegments)
174186
}

context_response.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ func (ctx *Context) Write(data []byte) (int, error) {
100100
return ctx.Writer.Write(data)
101101
}
102102

103+
func (ctx *Context) GetStatus() int {
104+
return ctx.Writer.(*ResponseWriterSpy).Status()
105+
}
106+
103107
// Header returns the header map that will be sent by
104108
// WriteHeader. The Header map also is the mechanism with which
105109
// Handlers can set HTTP trailers.

docs/logo-syntax.png

-12.9 KB
Binary file not shown.

middlewares/session/manager.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import (
1414
var globalManagers = map[*chain.Router]*Manager{}
1515

1616
var (
17-
sessionKey = "syntax.chain.session." // Session on chain.Context
18-
managerKey = "syntax.chain.session-manager." // Manager on chain.Context
17+
sessionKey = "chain.session." // Session on chain.Context
18+
managerKey = "chain.session-manager." // Manager on chain.Context
1919
ErrCannotFetch = errors.New("cannot fetch session, check if there is a session.Manager configured")
2020
)
2121

middlewares/session/store_cookie.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,14 @@
1414
// router := chain.New()
1515
// router.Use(session.Manager{
1616
// Store: session.Cookie{
17-
// Key: "_my_app_session",
18-
// Log: "debug"
17+
// Key: "_my_app_session"
1918
// }
2019
// })
2120

2221
package session
2322

2423
import (
2524
"log/slog"
26-
"strings"
2725

2826
"github.com/nidorx/chain"
2927
"github.com/nidorx/chain/crypto"
@@ -39,7 +37,6 @@ var (
3937
// https://edgeapi.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html
4038
// https://funcptr.net/2013/08/25/user-sessions,-what-data-should-be-stored-where-/
4139
type Cookie struct {
42-
Log string // Log level to use when the cookie cannot be decoded. Defaults to `debug`, can be set to false to disable it.
4340
Serializer chain.Serializer // cookie serializer module that defines `Encode(any)` and `Decode(any)`. Defaults to `json`.
4441
SigningKeyring *crypto.Keyring // a crypto.Keyring used with for signing/verifying a cookie.
4542
EncryptionKeyring *crypto.Keyring // a crypto.Keyring used for encrypting/decrypting a cookie.
@@ -54,10 +51,6 @@ func (c *Cookie) Init(config Config, router *chain.Router) (err error) {
5451
c.SigningKeyring = defaultSigningKeyring
5552
}
5653

57-
if strings.TrimSpace(c.Log) == "" {
58-
c.Log = "debug"
59-
}
60-
6154
if c.Serializer == nil {
6255
c.Serializer = defaultSerializer
6356
}

pubsub/pubsub.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var (
1717
selfId = ksuid.New()
1818
selfIdBytes = selfId.Bytes() // 20 bytes
1919
selfIdString = selfId.String()
20-
directTopic = "stx:direct:" + selfIdString
20+
directTopic = "direct:" + selfIdString
2121
ErrNoAdapter = errors.New("no adapter matches topic to broadcast the message")
2222
)
2323

@@ -129,7 +129,7 @@ func Broadcast(topic string, message []byte, options ...*Option) (err error) {
129129
var compressed []byte
130130
if compressed, err = compressPayload(msgToSend); err != nil {
131131
slog.Warn(
132-
"[chain] Failed to compress payload",
132+
"[chain.pubsub] failed to compress payload",
133133
slog.Any("error", err),
134134
)
135135
} else if len(compressed) < len(msgToSend) {
@@ -178,7 +178,7 @@ func DirectBroadcast(nodeId string, topic string, message []byte, options ...*Op
178178
buf.WriteString(topic)
179179
buf.Write(message)
180180

181-
return broadcastMessage(messageTypeDirectBroadcast, "stx:direct:"+nodeId, buf.Bytes(), options...)
181+
return broadcastMessage(messageTypeDirectBroadcast, "direct:"+nodeId, buf.Bytes(), options...)
182182
}
183183

184184
// Broadcast broadcasts message on given topic across the whole cluster.
@@ -214,7 +214,7 @@ func broadcastMessage(msgType messageType, topic string, message []byte, options
214214
var compressed []byte
215215
if compressed, err = compressPayload(msgToSend); err != nil {
216216
slog.Warn(
217-
"[chain] Failed to compress payload",
217+
"[chain.pubsub] failed to compress payload",
218218
slog.Any("error", err),
219219
)
220220
} else if len(compressed) < len(msgToSend) {

registry.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ func (r *Registry) addHandle(path string, handle Handle) {
5050
r.routes = []*Route{}
5151
}
5252

53-
details := ParsePathDetails(path)
53+
details := ParseRouteInfo(path)
5454

5555
// avoid conflicts
5656
for _, route := range r.routes {
57-
if details.conflictsWith(route.Path) {
58-
slog.Error("[chain] wildcard conflicts", slog.String("new", details.path), slog.String("existing", route.Path.path))
57+
if details.conflictsWith(route.Info) {
58+
slog.Error("[chain] wildcard conflicts", slog.String("new", details.path), slog.String("existing", route.Info.path))
5959
panic("[chain] wildcard conflicts")
6060
}
6161
}
@@ -77,17 +77,17 @@ func (r *Registry) addHandle(path string, handle Handle) {
7777
r.storage.add(r.createRoute(handle, details))
7878
}
7979

80-
func (r *Registry) createRoute(handle Handle, pathDetails *PathDetails) *Route {
80+
func (r *Registry) createRoute(handle Handle, info *RouteInfo) *Route {
8181
route := &Route{
8282
Handle: handle,
83-
Path: pathDetails,
83+
Info: info,
8484
middlewaresAdded: map[*Middleware]bool{},
8585
}
8686

8787
r.routes = append(r.routes, route)
8888

8989
for _, middleware := range r.middlewares {
90-
if route.middlewaresAdded[middleware] != true && middleware.Path.MaybeMatches(route.Path) {
90+
if route.middlewaresAdded[middleware] != true && middleware.Path.Matches(route.Info) {
9191
route.middlewaresAdded[middleware] = true
9292
route.Middlewares = append(route.Middlewares, middleware)
9393
}
@@ -103,15 +103,15 @@ func (r *Registry) addMiddleware(path string, middlewares []func(ctx *Context, n
103103

104104
for _, middleware := range middlewares {
105105
info := &Middleware{
106-
Path: ParsePathDetails(path),
106+
Path: ParseRouteInfo(path),
107107
Handle: middleware,
108108
}
109109

110110
r.middlewares = append(r.middlewares, info)
111111

112112
// add this MiddlewareFunc to all compatible routes
113113
for _, route := range r.routes {
114-
if route.middlewaresAdded[info] != true && info.Path.MaybeMatches(route.Path) {
114+
if route.middlewaresAdded[info] != true && info.Path.Matches(route.Info) {
115115
route.middlewaresAdded[info] = true
116116
route.Middlewares = append(route.Middlewares, info)
117117
}

response_writer.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,29 @@ var ErrAlreadySent = errors.New("the response was already sent")
1111

1212
type ResponseWriterSpy struct {
1313
http.ResponseWriter
14+
status int // status code passed to WriteHeader
1415
writeStarted bool
1516
writeCalled bool
1617
writeHeaderCalled bool
1718
beforeWriteHeaderHooks []func()
1819
afterWriteHooks []func()
1920
}
2021

22+
func (w *ResponseWriterSpy) Status() int {
23+
return w.status
24+
}
25+
2126
func (w *ResponseWriterSpy) WriteHeader(status int) {
27+
w.status = status
2228
w.writeHeaderCalled = true
2329
w.execBeforeWriteHeaderHooks()
2430
w.ResponseWriter.WriteHeader(status)
2531
}
2632

2733
func (w *ResponseWriterSpy) Write(b []byte) (int, error) {
34+
if w.status == 0 {
35+
w.status = http.StatusOK
36+
}
2837
w.writeCalled = true
2938
if !w.writeStarted {
3039
w.execBeforeWriteHeaderHooks()

0 commit comments

Comments
 (0)