Skip to content

Commit 5d21637

Browse files
committed
🍍 api: improve abstractions
1 parent 3c874fd commit 5d21637

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

api/internal/restapi/restapi.go

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

33
import (
44
"encoding/json"
5+
"io"
56
"net/http"
67
)
78

@@ -11,15 +12,29 @@ type HandlerFunc func(w http.ResponseWriter, r *http.Request) (status int, err e
1112
// EncodeResponse sets the Content-Type header field to application/json, and writes
1213
// to the response writer with the given status code and data encoded as JSON.
1314
//
14-
// If data is nil, the status code is written and no data is encoded.
15+
// If data is nil, only the status code is written and no data is encoded.
16+
//
17+
// If data is of type [io.Reader] or []byte, it is assumed to be encoded JSON
18+
// and is written directly to the response writer.
1519
func EncodeResponse(w http.ResponseWriter, status int, data any) (int, error) {
1620
if data == nil {
1721
w.WriteHeader(status)
1822
return status, nil
1923
}
2024
w.Header()["Content-Type"] = []string{"application/json"}
2125
w.WriteHeader(status)
22-
return status, json.NewEncoder(w).Encode(data)
26+
var err error
27+
switch v := data.(type) {
28+
case io.Reader:
29+
_, err = io.Copy(w, v)
30+
case *[]byte:
31+
_, err = w.Write(*v)
32+
case []byte:
33+
_, err = w.Write(v)
34+
default:
35+
err = json.NewEncoder(w).Encode(v)
36+
}
37+
return status, err
2338
}
2439

2540
// DecodeRequest decodes the request body as JSON into the provided value.

api/ssm/ssm.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,21 @@ func (sm *ServerManager) requireServerStats(h func(http.ResponseWriter, *http.Re
6464
name := r.PathValue("server")
6565
server, ok := sm.serverByName[name]
6666
if !ok {
67-
return restapi.EncodeResponse(w, http.StatusNotFound, StandardError{Message: "server not found"})
67+
return restapi.EncodeResponse(w, http.StatusNotFound, &serverNotFoundJSON)
6868
}
6969
return h(w, r, server.StatsCollector)
7070
}
7171
}
7272

73-
var serverInfoJSON = []byte(`{"server":"shadowsocks-go ` + shadowsocks.Version + `","apiVersion":"v1"}`)
73+
var (
74+
serverInfoJSON = []byte(`{"server":"shadowsocks-go ` + shadowsocks.Version + `","apiVersion":"v1"}`)
75+
serverNotFoundJSON = []byte(`{"error":"server not found"}`)
76+
serverNoCredentialManagerJSON = []byte(`{"error":"The server does not support user management."}`)
77+
userNotFoundJSON = []byte(`{"error":"user not found"}`)
78+
)
7479

7580
func handleGetServerInfo(w http.ResponseWriter, _ *http.Request, _ stats.Collector) (int, error) {
76-
w.Header()["Content-Type"] = []string{"application/json"}
77-
_, err := w.Write(serverInfoJSON)
78-
return http.StatusOK, err
81+
return restapi.EncodeResponse(w, http.StatusOK, &serverInfoJSON)
7982
}
8083

8184
func handleGetStats(w http.ResponseWriter, r *http.Request, sc stats.Collector) (int, error) {
@@ -93,10 +96,10 @@ func (sm *ServerManager) requireServerUsers(h func(http.ResponseWriter, *http.Re
9396
name := r.PathValue("server")
9497
server, ok := sm.serverByName[name]
9598
if !ok {
96-
return restapi.EncodeResponse(w, http.StatusNotFound, StandardError{Message: "server not found"})
99+
return restapi.EncodeResponse(w, http.StatusNotFound, &serverNotFoundJSON)
97100
}
98101
if server.CredentialManager == nil {
99-
return restapi.EncodeResponse(w, http.StatusNotFound, StandardError{Message: "The server does not support user management."})
102+
return restapi.EncodeResponse(w, http.StatusNotFound, &serverNoCredentialManagerJSON)
100103
}
101104
return h(w, r, server)
102105
}
@@ -131,7 +134,7 @@ func handleGetUser(w http.ResponseWriter, r *http.Request, ms Server) (int, erro
131134
username := r.PathValue("username")
132135
userCred, ok := ms.CredentialManager.GetCredential(username)
133136
if !ok {
134-
return restapi.EncodeResponse(w, http.StatusNotFound, StandardError{Message: "user not found"})
137+
return restapi.EncodeResponse(w, http.StatusNotFound, &userNotFoundJSON)
135138
}
136139

137140
return restapi.EncodeResponse(w, http.StatusOK, response{userCred, ms.StatsCollector.Snapshot().Traffic})

0 commit comments

Comments
 (0)