feat(mcp): session id store
This commit is contained in:
40
internal/mcp/session.go
Normal file
40
internal/mcp/session.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package mcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SessionStore struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
m map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSessionStore() *SessionStore {
|
||||||
|
return &SessionStore{m: make(map[string]struct{})}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionStore) Issue() string {
|
||||||
|
b := make([]byte, 16)
|
||||||
|
_, _ = rand.Read(b)
|
||||||
|
id := hex.EncodeToString(b)
|
||||||
|
|
||||||
|
s.mu.Lock()
|
||||||
|
s.m[id] = struct{}{}
|
||||||
|
s.mu.Unlock()
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionStore) Valid(id string) bool {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
_, ok := s.m[id]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionStore) Drop(id string) {
|
||||||
|
s.mu.Lock()
|
||||||
|
delete(s.m, id)
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
22
internal/mcp/session_test.go
Normal file
22
internal/mcp/session_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package mcp_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.d-ma.be/mathias/gitea-mcp/internal/mcp"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSessionStoreIssueAndCheck(t *testing.T) {
|
||||||
|
s := mcp.NewSessionStore()
|
||||||
|
|
||||||
|
id := s.Issue()
|
||||||
|
assert.NotEmpty(t, id)
|
||||||
|
assert.Len(t, id, 32)
|
||||||
|
|
||||||
|
assert.True(t, s.Valid(id))
|
||||||
|
assert.False(t, s.Valid("bogus"))
|
||||||
|
|
||||||
|
s.Drop(id)
|
||||||
|
assert.False(t, s.Valid(id))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user