Skip to content

Commit 550f073

Browse files
committed
feat: open router and fix other minor issues and refactor action handler :(
1 parent 73e4a65 commit 550f073

File tree

21 files changed

+375
-62
lines changed

21 files changed

+375
-62
lines changed

frontend/src/components/DeepSeekLoginCard.vue

Whitespace-only changes.

frontend/src/lib/providers/deepseek.ts

Whitespace-only changes.

service/logic/open.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ var ServerPort = -1
1717

1818
var sessionActive = make(map[string]chan<- struct{})
1919

20-
func OpenUI(params url.Values, auth bool) (<-chan struct{}, func(), error) {
20+
func OpenAction(actionType string, params url.Values) (<-chan struct{}, func(), error) {
21+
return OpenUI("/action/"+actionType, params, true)
22+
}
23+
24+
func OpenUI(path string, params url.Values, auth bool) (<-chan struct{}, func(), error) {
2125
if auth {
2226
allUsers, err := store.Users.List()
2327
if err != nil {
@@ -43,7 +47,7 @@ func OpenUI(params url.Values, auth bool) (<-chan struct{}, func(), error) {
4347
params.Set("session", sessionId)
4448
params.Set("port", strconv.Itoa(ServerPort))
4549

46-
openBrowser.OpenBrowser(constants.UserName, constants.AppBaseUrl+"?"+params.Encode())
50+
openBrowser.OpenBrowser(constants.UserName, constants.AppBaseUrl+path+"?"+params.Encode())
4751

4852
channel := make(chan struct{})
4953
sessionActive[sessionId] = channel

service/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func main() {
9696

9797
if len(os.Args) < 2 {
9898
handleSetup()
99-
logic.OpenUI(url.Values{}, false)
99+
logic.OpenUI("/", url.Values{}, false)
100100
return
101101
}
102102

service/server/action.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package server
22

33
import (
44
"net/http"
5-
"net/url"
65

76
"github.com/gin-gonic/gin"
87

@@ -12,7 +11,6 @@ import (
1211

1312
func SetupActionAPI(router *gin.Engine) {
1413
router.GET("/", handleCheck)
15-
router.GET("/ui/open", handleOpenUI)
1614
router.POST("/ui/active", handleUIActive)
1715
}
1816

@@ -23,18 +21,6 @@ func handleCheck(c *gin.Context) {
2321
})
2422
}
2523

26-
func handleOpenUI(c *gin.Context) {
27-
_, cleanup, err := logic.OpenUI(url.Values{}, true)
28-
if cleanup != nil {
29-
cleanup()
30-
}
31-
32-
if err != nil {
33-
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to open UI"})
34-
return
35-
}
36-
}
37-
3824
func handleUIActive(c *gin.Context) {
3925
var req struct {
4026
Session string `json:"session"`

service/server/app.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,11 @@ func handleAppRegister(c *gin.Context) {
101101
defer delete(waitForGrant, uid)
102102

103103
params := url.Values{
104-
"action": {"register"},
105104
"appId": {uid},
106105
"appName": {req.Name},
107106
"appDescription": {req.Description},
108107
}
109-
uiActive, cleanup, err := logic.OpenUI(params, true)
108+
uiActive, cleanup, err := logic.OpenAction("register", params)
110109
if cleanup != nil {
111110
defer cleanup()
112111
}

service/server/auth.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,21 +141,24 @@ func RequireUserLogin() gin.HandlerFunc {
141141
return func(c *gin.Context) {
142142
authHeader := c.GetHeader("Authorization")
143143
if authHeader == "" {
144-
c.JSON(http.StatusUnauthorized, gin.H{"__uni_token": true})
144+
c.Header("X-Uni-Token-Error", "missing_authorization_header")
145+
c.Status(http.StatusUnauthorized)
145146
c.Abort()
146147
return
147148
}
148149

149150
tokenParts := strings.Split(authHeader, " ")
150151
if len(tokenParts) != 2 || tokenParts[0] != "Bearer" {
151-
c.JSON(http.StatusUnauthorized, gin.H{"__uni_token": true})
152+
c.Header("X-Uni-Token-Error", "missing_authorization_header")
153+
c.Status(http.StatusUnauthorized)
152154
c.Abort()
153155
return
154156
}
155157

156158
claims, err := logic.ValidateJWT(tokenParts[1])
157159
if err != nil {
158-
c.JSON(http.StatusUnauthorized, gin.H{"__uni_token": true})
160+
c.Header("X-Uni-Token-Error", "invalid_token")
161+
c.Status(http.StatusUnauthorized)
159162
c.Abort()
160163
return
161164
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package openrouter
2+
3+
import (
4+
"encoding/json"
5+
"io"
6+
"net/http"
7+
"time"
8+
9+
"uni-token-service/store"
10+
11+
"github.com/gin-gonic/gin"
12+
)
13+
14+
type session struct {
15+
Key string `json:"key"`
16+
UserId string `json:"userId"`
17+
}
18+
19+
func loadSession() (session, error) {
20+
var s session
21+
data, err := store.Providers.Get("openRouter")
22+
if err != nil {
23+
return session{}, err
24+
}
25+
json.Unmarshal(data, &s)
26+
return s, nil
27+
}
28+
29+
func saveSession(s session) error {
30+
jsonData, err := json.Marshal(s)
31+
if err != nil {
32+
return err
33+
}
34+
store.Providers.Put("openRouter", jsonData)
35+
return nil
36+
}
37+
38+
func SetupAPI(routes gin.IRoutes) {
39+
routes.POST("/authed", handleAuthed)
40+
routes.GET("/status", handleGetStatus)
41+
routes.GET("/key", handleGetKey)
42+
routes.POST("/logout", handleLogout)
43+
}
44+
45+
func handleAuthed(c *gin.Context) {
46+
var req struct {
47+
Key string `json:"key"`
48+
UserId string `json:"userId"`
49+
}
50+
if err := c.BindJSON(&req); err != nil {
51+
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
52+
return
53+
}
54+
err := saveSession(session{
55+
Key: req.Key,
56+
UserId: req.UserId,
57+
})
58+
if err != nil {
59+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save session"})
60+
return
61+
}
62+
c.Status(http.StatusOK)
63+
}
64+
65+
func handleGetStatus(c *gin.Context) {
66+
s, err := loadSession()
67+
if err != nil {
68+
c.JSON(http.StatusOK, gin.H{
69+
"authed": false,
70+
})
71+
return
72+
}
73+
74+
req, err := http.NewRequest("GET", "https://openrouter.ai/api/v1/credits", nil)
75+
if err != nil {
76+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create request"})
77+
return
78+
}
79+
req.Header.Set("Authorization", "Bearer "+s.Key)
80+
client := &http.Client{Timeout: 10 * time.Second}
81+
resp, err := client.Do(req)
82+
if err != nil {
83+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch credits"})
84+
return
85+
}
86+
defer resp.Body.Close()
87+
body, err := io.ReadAll(resp.Body)
88+
if err != nil {
89+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read response"})
90+
return
91+
}
92+
if resp.StatusCode != http.StatusOK {
93+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch credits"})
94+
return
95+
}
96+
var creditsResp struct {
97+
Data struct {
98+
TotalCredits float64 `json:"total_credits"`
99+
TotalUsage float64 `json:"total_usage"`
100+
} `json:"data"`
101+
}
102+
if err := json.Unmarshal(body, &creditsResp); err != nil {
103+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to parse credits"})
104+
return
105+
}
106+
c.JSON(http.StatusOK, gin.H{
107+
"userId": s.UserId,
108+
"credits": creditsResp.Data.TotalCredits,
109+
"usage": creditsResp.Data.TotalUsage,
110+
})
111+
}
112+
113+
func handleGetKey(c *gin.Context) {
114+
s, err := loadSession()
115+
if err != nil {
116+
c.Status(http.StatusUnauthorized)
117+
return
118+
}
119+
c.JSON(http.StatusOK, gin.H{"key": s.Key})
120+
}
121+
122+
// handleLogout handles user logout request
123+
func handleLogout(c *gin.Context) {
124+
// Remove the stored session
125+
err := store.Providers.Delete("openRouter")
126+
if err != nil {
127+
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to clear session"})
128+
return
129+
}
130+
c.Status(http.StatusOK)
131+
}

service/server/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"uni-token-service/logic"
1010
deepSeek "uni-token-service/server/deep-seek"
1111
siliconFlow "uni-token-service/server/silicon-flow"
12+
openRouter "uni-token-service/server/open-router"
1213

1314
"github.com/gin-contrib/cors"
1415
"github.com/gin-gonic/gin"
@@ -52,6 +53,7 @@ func setupRoutes(router *gin.Engine) {
5253

5354
siliconFlow.SetupAPI(router.Group("/siliconflow").Use(RequireUserLogin()))
5455
deepSeek.SetupAPI(router.Group("/deepseek").Use(RequireUserLogin()))
56+
openRouter.SetupAPI(router.Group("/openrouter").Use(RequireUserLogin()))
5557
}
5658

5759
func isPortAvailable(port int) bool {

ui/src/App.vue

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import ThemeToggle from '@/components/ThemeToggle.vue'
1111
import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'
1212
import { Toaster } from '@/components/ui/sonner'
1313
import { useThemeStore } from '@/stores/theme'
14-
import ActionHandler from '@/views/ActionHandler.vue'
1514
import { useAuthStore, useServiceStore } from './stores'
1615
import 'vue-sonner/style.css'
1716
@@ -104,8 +103,6 @@ onUIOpened()
104103
<RouterView />
105104
</SidebarInset>
106105
</SidebarProvider>
107-
108-
<ActionHandler />
109106
</div>
110107
</template>
111108

0 commit comments

Comments
 (0)