Skip to content

Commit e705ac6

Browse files
authored
Add logout (#13796)
### What problem does this PR solve? Add command: logout ### Type of change - [x] New Feature (non-breaking change which adds functionality) Signed-off-by: Jin Hai <haijin.chn@gmail.com>
1 parent ebf3695 commit e705ac6

File tree

8 files changed

+96
-30
lines changed

8 files changed

+96
-30
lines changed

internal/admin/router.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@ func (r *Router) Setup(engine *gin.Engine) {
4343
// Public routes
4444
admin.GET("/ping", r.handler.Ping)
4545
admin.POST("/login", r.handler.Login)
46-
admin.GET("/logout", r.handler.Logout)
4746

4847
admin.POST("/reports", r.handler.Reports)
4948

5049
// Protected routes
5150
protected := admin.Group("")
5251
protected.Use(r.handler.AuthMiddleware())
5352
{
53+
54+
protected.GET("/logout", r.handler.Logout)
5455
// Auth
5556
protected.GET("/auth", r.handler.AuthCheck)
5657

internal/cli/admin_parser.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ func (p *Parser) parseAdminLoginUser() (*Command, error) {
2727
return cmd, nil
2828
}
2929

30+
func (p *Parser) parseAdminLogout() (*Command, error) {
31+
cmd := NewCommand("logout")
32+
p.nextToken()
33+
// Semicolon is optional for UNSET TOKEN
34+
if p.curToken.Type == TokenSemicolon {
35+
p.nextToken()
36+
}
37+
return cmd, nil
38+
}
39+
3040
func (p *Parser) parseAdminPingServer() (*Command, error) {
3141
cmd := NewCommand("ping")
3242
p.nextToken()

internal/cli/cli.go

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -110,60 +110,65 @@ func parseHostPort(hostPort string) (string, int, error) {
110110
func ParseConnectionArgs(args []string) (*ConnectionArgs, error) {
111111
// First, scan args to check for help, config file, and admin mode
112112
var configFilePath string
113-
113+
var adminMode bool = false
114114
for i := 0; i < len(args); i++ {
115115
arg := args[i]
116116
if arg == "--help" || arg == "-help" {
117117
return &ConnectionArgs{ShowHelp: true}, nil
118118
} else if (arg == "-f" || arg == "--config") && i+1 < len(args) {
119119
configFilePath = args[i+1]
120120
i++
121+
} else if arg == "--admin" {
122+
adminMode = true
121123
}
122124
}
123125

124126
// Load config file with priority: -f > rf.yml > none
125127
var config *ConfigFile
126128
var err error
127129

128-
if configFilePath != "" {
129-
// User specified config file via -f
130-
config, err = LoadConfigFileFromPath(configFilePath)
131-
if err != nil {
132-
return nil, err
133-
}
134-
} else {
135-
// Try default rf.yml
136-
config, err = LoadDefaultConfigFile()
137-
if err != nil {
138-
return nil, err
139-
}
140-
}
141-
142130
// Parse arguments manually to support both short and long forms
143131
// and to handle priority: command line > config file > defaults
144132

145133
// Build result from config file first (if exists), then override with command line flags
146134
result := &ConnectionArgs{}
147135

148-
// Get non-flag arguments (command to execute)
149-
var nonFlagArgs []string
150-
151-
// Apply config file values first (lower priority)
152-
if config != nil {
153-
// Parse host:port from config file
154-
if config.Host != "" {
155-
h, port, err := parseHostPort(config.Host)
136+
if !adminMode {
137+
// Only user mode read config file
138+
if configFilePath != "" {
139+
// User specified config file via -f
140+
config, err = LoadConfigFileFromPath(configFilePath)
141+
if err != nil {
142+
return nil, err
143+
}
144+
} else {
145+
// Try default rf.yml
146+
config, err = LoadDefaultConfigFile()
156147
if err != nil {
157-
return nil, fmt.Errorf("invalid host in config file: %v", err)
148+
return nil, err
149+
}
150+
}
151+
152+
// Apply config file values first (lower priority)
153+
if config != nil {
154+
// Parse host:port from config file
155+
if config.Host != "" {
156+
h, port, err := parseHostPort(config.Host)
157+
if err != nil {
158+
return nil, fmt.Errorf("invalid host in config file: %v", err)
159+
}
160+
result.Host = h
161+
result.Port = port
158162
}
159-
result.Host = h
160-
result.Port = port
163+
result.UserName = config.UserName
164+
result.Password = config.Password
165+
result.APIToken = config.APIToken
161166
}
162-
result.UserName = config.UserName
163-
result.Password = config.Password
164-
result.APIToken = config.APIToken
165167
}
166168

169+
// Get non-flag arguments (command to execute)
170+
var nonFlagArgs []string
171+
167172
// Override with command line flags (higher priority)
168173
// Handle both short and long forms manually
169174
for i := 0; i < len(args); i++ {

internal/cli/client.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,35 @@ func (c *RAGFlowClient) loginUser(email, password string) (string, error) {
234234
return token, nil
235235
}
236236

237+
func (c *RAGFlowClient) Logout() (ResponseIf, error) {
238+
if c.HTTPClient.LoginToken == "" {
239+
return nil, fmt.Errorf("not logged in")
240+
}
241+
242+
var path string
243+
if c.ServerType == "admin" {
244+
path = "/admin/logout"
245+
} else {
246+
path = "/user/logout"
247+
}
248+
249+
resp, err := c.HTTPClient.Request("GET", path, c.ServerType == "admin", "web", nil, nil)
250+
if err != nil {
251+
return nil, err
252+
}
253+
254+
var result SimpleResponse
255+
if err = json.Unmarshal(resp.Body, &result); err != nil {
256+
return nil, fmt.Errorf("login failed: invalid JSON (%w)", err)
257+
}
258+
259+
if result.Code != 0 {
260+
return nil, fmt.Errorf("login failed: %s", result.Message)
261+
}
262+
263+
return &result, nil
264+
}
265+
237266
// readPassword reads password from terminal without echoing
238267
func readPassword() (string, error) {
239268
// Check if stdin is a terminal by trying to get terminal size
@@ -301,6 +330,8 @@ func (c *RAGFlowClient) ExecuteAdminCommand(cmd *Command) (ResponseIf, error) {
301330
switch cmd.Type {
302331
case "login_user":
303332
return nil, c.LoginUser(cmd)
333+
case "logout":
334+
return c.Logout()
304335
case "ping":
305336
return c.PingAdmin(cmd)
306337
case "benchmark":
@@ -350,6 +381,8 @@ func (c *RAGFlowClient) ExecuteUserCommand(cmd *Command) (ResponseIf, error) {
350381
return c.RegisterUser(cmd)
351382
case "login_user":
352383
return nil, c.LoginUser(cmd)
384+
case "logout":
385+
return c.Logout()
353386
case "ping":
354387
return c.PingServer(cmd)
355388
case "benchmark":

internal/cli/lexer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ func (l *Lexer) lookupIdent(ident string) Token {
149149
switch upper {
150150
case "LOGIN":
151151
return Token{Type: TokenLogin, Value: ident}
152+
case "LOGOUT":
153+
return Token{Type: TokenLogout, Value: ident}
152154
case "REGISTER":
153155
return Token{Type: TokenRegister, Value: ident}
154156
case "LIST":

internal/cli/parser.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ func (p *Parser) parseAdminCommand() (*Command, error) {
8181
switch p.curToken.Type {
8282
case TokenLogin:
8383
return p.parseAdminLoginUser()
84+
case TokenLogout:
85+
return p.parseAdminLogout()
8486
case TokenPing:
8587
return p.parseAdminPingServer()
8688
case TokenList:
@@ -131,6 +133,8 @@ func (p *Parser) parseUserCommand() (*Command, error) {
131133
switch p.curToken.Type {
132134
case TokenLogin:
133135
return p.parseLoginUser()
136+
case TokenLogout:
137+
return p.parseLogout()
134138
case TokenPing:
135139
return p.parsePingServer()
136140
case TokenList:

internal/cli/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type Command struct {
2626
const (
2727
// Keywords
2828
TokenLogin = iota
29+
TokenLogout
2930
TokenRegister
3031
TokenList
3132
TokenServices

internal/cli/user_parser.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ package cli
33
import "fmt"
44

55
// Command parsers
6+
func (p *Parser) parseLogout() (*Command, error) {
7+
cmd := NewCommand("logout")
8+
p.nextToken()
9+
// Semicolon is optional for UNSET TOKEN
10+
if p.curToken.Type == TokenSemicolon {
11+
p.nextToken()
12+
}
13+
return cmd, nil
14+
}
15+
616
func (p *Parser) parseLoginUser() (*Command, error) {
717
cmd := NewCommand("login_user")
818

0 commit comments

Comments
 (0)