renames some api endpoints: e.g. /servers to /client-conns, /servers/xxx/peers to /client-conns/xxx/routes

This commit is contained in:
hyung-hwan 2024-11-30 00:19:39 +09:00
parent 9667a9b2e2
commit 4625ed3328
2 changed files with 249 additions and 62 deletions

View File

@ -16,6 +16,8 @@ import "strconv"
* GET list all peers
* PUT create/replace
* PATCH partial update
* /servers/1112123/peers/1231344
* GET get info
*/
type json_errmsg struct {
@ -26,32 +28,37 @@ type json_in_peer_addrs struct {
PeerAddrs []string `json:"peer-addrs"`
}
type json_out_server struct {
type json_out_client_conn struct {
Id uint32 `json:"id"`
ServerAddr string `json:"server-addr"`
PeerAddrs []json_out_server_peer `json:"peer-addrs"`
Routes []json_out_client_route `json:"routes"`
}
type json_out_server_peer struct {
type json_out_client_route struct {
Id uint32 `json:"id"`
ClientPeerAddr string `json:"peer-addr"`
ClientPeerAddr string `json:"client-peer-addr"`
ServerPeerListenAddr string `json:"server-peer-listen-addr"`
}
// ------------------------------------
type client_ctl_servers struct {
type client_ctl_client_conns struct {
c *Client
}
type client_ctl_servers_id struct {
type client_ctl_client_conns_id struct {
c *Client
}
type client_ctl_servers_id_peers struct {
type client_ctl_client_conns_id_routes struct {
c *Client
}
type client_ctl_client_conns_id_routes_id struct {
c *Client
}
type client_ctl_clients struct {
c *Client
}
@ -62,40 +69,41 @@ type client_ctl_clients_id struct {
// ------------------------------------
func (ctl *client_ctl_servers) ServeHTTP(w http.ResponseWriter, req *http.Request) {
func (ctl *client_ctl_client_conns) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var c *Client
var status_code int
var err error
var je *json.Encoder
c = ctl.c
je = json.NewEncoder(w)
switch req.Method {
case http.MethodGet:
var je *json.Encoder
var cts *ClientConn
var js []json_out_server
status_code = http.StatusOK; w.WriteHeader(status_code)
je = json.NewEncoder(w)
var js []json_out_client_conn
js = make([]json_out_client_conn, 0)
c.cts_mtx.Lock()
for _, cts = range c.cts_map_by_id {
var r *ClientRoute
var jsp []json_out_server_peer
var jsp []json_out_client_route
jsp = make([]json_out_client_route, 0)
cts.route_mtx.Lock()
for _, r = range cts.route_map {
jsp = append(jsp, json_out_server_peer{
jsp = append(jsp, json_out_client_route{
Id: r.id,
ClientPeerAddr: r.peer_addr.String(),
ServerPeerListenAddr: r.server_peer_listen_addr.String(),
})
}
js = append(js, json_out_server{Id: cts.id, ServerAddr: cts.saddr.String(), PeerAddrs: jsp})
js = append(js, json_out_client_conn{Id: cts.id, ServerAddr: cts.saddr.String(), Routes: jsp})
cts.route_mtx.Unlock()
}
c.cts_mtx.Unlock()
status_code = http.StatusOK; w.WriteHeader(status_code)
if err = je.Encode(js); err != nil { goto oops }
case http.MethodPost:
@ -106,22 +114,17 @@ func (ctl *client_ctl_servers) ServeHTTP(w http.ResponseWriter, req *http.Reques
err = json.NewDecoder(req.Body).Decode(&s)
if err != nil {
status_code = http.StatusBadRequest
w.WriteHeader(status_code)
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
goto done
}
cc.ServerAddr = s.ServerAddr
cc.PeerAddrs = s.PeerAddrs
cts, err = c.start_service(&cc) // TODO: this can be blocking. do we have to resolve addresses before calling this? also not good because resolution succeed or fail at each attempt. however ok as ServeHTTP itself is in a goroutine?
if err != nil {
var je *json.Encoder
status_code = http.StatusInternalServerError; w.WriteHeader(status_code)
je = json.NewEncoder(w)
if err = je.Encode(json_errmsg{Text: err.Error()}); err != nil { goto oops }
} else {
var je *json.Encoder
status_code = http.StatusCreated; w.WriteHeader(status_code)
je = json.NewEncoder(w)
if err = je.Encode(cts.cfg); err != nil { goto oops }
}
@ -131,7 +134,7 @@ func (ctl *client_ctl_servers) ServeHTTP(w http.ResponseWriter, req *http.Reques
c.cts_mtx.Lock()
for _, cts = range c.cts_map { cts.ReqStop() }
c.cts_mtx.Unlock()
w.WriteHeader(http.StatusNoContent)
status_code = http.StatusNoContent; w.WriteHeader(status_code)
default:
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
@ -149,43 +152,136 @@ oops:
// ------------------------------------
// servers/{id}
func (ctl *client_ctl_servers_id) ServeHTTP(w http.ResponseWriter, req *http.Request) {
//req.PathValue("id")
switch req.Method {
case http.MethodGet:
case http.MethodPost:
case http.MethodPut: // update
goto bad_request
case http.MethodDelete:
}
return
bad_request:
w.WriteHeader(http.StatusBadRequest)
return
}
func (ctl *client_ctl_servers_id_peers) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// client-conns/{conn_id}
func (ctl *client_ctl_client_conns_id) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var c *Client
var status_code int
var err error
var id string
var conn_id string
var conn_nid uint64
var je *json.Encoder
c = ctl.c
je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id")
conn_nid, err = strconv.ParseUint(conn_id, 10, 32)
if err != nil {
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops }
goto done
}
id = req.PathValue("id")
switch req.Method {
case http.MethodGet:
var r *ClientRoute
var jsp []json_out_client_route
var js *json_out_client_conn
var cts *ClientConn
cts = c.FindClientConnById(uint32(conn_nid))
if cts == nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "non-existent connection id - " + conn_id}); err != nil { goto oops }
goto done
}
jsp = make([]json_out_client_route, 0)
cts.route_mtx.Lock()
for _, r = range cts.route_map {
jsp = append(jsp, json_out_client_route{
Id: r.id,
ClientPeerAddr: r.peer_addr.String(),
ServerPeerListenAddr: r.server_peer_listen_addr.String(),
})
}
js = &json_out_client_conn{Id: cts.id, ServerAddr: cts.saddr.String(), Routes: jsp}
cts.route_mtx.Unlock()
status_code = http.StatusOK; w.WriteHeader(status_code)
if err = je.Encode(js); err != nil { goto oops }
case http.MethodDelete:
/*
err = c.RemoveClientConnById(uint32(conn_nid))
if err != nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: err.Error()}); err != nil { goto oops }
} else {
status_code = http.StatusNoContent; w.WriteHeader(status_code)
}
*/
default:
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
}
return
done:
// TODO: need to handle x-forwarded-for and other stuff? this is not a real web service, though
c.log.Write("", LOG_DEBUG, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) // TODO: time taken
return
oops:
c.log.Write("", LOG_ERROR, "[%s] %s %s - %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error())
return
}
func (ctl *client_ctl_client_conns_id_routes) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var c *Client
var status_code int
var err error
var conn_id string
var conn_nid uint64
var je *json.Encoder
var cts *ClientConn
c = ctl.c
je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id")
conn_nid, err = strconv.ParseUint(conn_id, 10, 32)
if err != nil {
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops }
goto done
}
cts = c.FindClientConnById(uint32(conn_nid))
if cts == nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "non-existent connection id - " + conn_id}); err != nil { goto oops }
goto done
}
switch req.Method {
case http.MethodGet:
var r *ClientRoute
var jsp []json_out_client_route
jsp = make([]json_out_client_route, 0)
cts.route_mtx.Lock()
for _, r = range cts.route_map {
jsp = append(jsp, json_out_client_route{
Id: r.id,
ClientPeerAddr: r.peer_addr.String(),
ServerPeerListenAddr: r.server_peer_listen_addr.String(),
})
}
cts.route_mtx.Unlock()
status_code = http.StatusOK; w.WriteHeader(status_code)
if err = je.Encode(jsp); err != nil { goto oops }
case http.MethodPost:
var pa json_in_peer_addrs
var cts *ClientConn
var nid uint64
err = json.NewDecoder(req.Body).Decode(&pa)
if err != nil {
@ -193,21 +289,14 @@ func (ctl *client_ctl_servers_id_peers) ServeHTTP(w http.ResponseWriter, req *ht
goto done
}
nid, err = strconv.ParseUint(id, 10, 32)
if err != nil {
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
goto done
}
cts = c.FindClientConnById(uint32(nid))
cts = c.FindClientConnById(uint32(conn_nid))
if cts == nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops }
} else {
err = cts.AddClientRoutes(pa.PeerAddrs)
if err != nil {
var je *json.Encoder
status_code = http.StatusInternalServerError; w.WriteHeader(status_code)
je = json.NewEncoder(w)
if err = je.Encode(json_errmsg{Text: err.Error()}); err != nil { goto oops }
} else {
status_code = http.StatusCreated; w.WriteHeader(status_code)
@ -228,6 +317,86 @@ oops:
return
}
// ------------------------------------
func (ctl *client_ctl_client_conns_id_routes_id) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var c *Client
var status_code int
var err error
var conn_id string
var route_id string
var conn_nid uint64
var route_nid uint64
var je *json.Encoder
var cts *ClientConn
c = ctl.c
je = json.NewEncoder(w)
conn_id = req.PathValue("conn_id")
route_id = req.PathValue("route_id")
conn_nid, err = strconv.ParseUint(conn_id, 10, 32)
if err != nil {
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "wrong connection id - " + conn_id}); err != nil { goto oops }
goto done
}
route_nid, err = strconv.ParseUint(route_id, 10, 32)
if err != nil {
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "wrong route id - " + route_id}); err != nil { goto oops }
goto done
}
cts = c.FindClientConnById(uint32(conn_nid))
if cts == nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "non-existent connection id - " + conn_id}); err != nil { goto oops }
goto done
}
switch req.Method {
case http.MethodGet:
var r *ClientRoute
r = cts.FindClientRouteById(uint32(route_nid))
if r == nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: "non-existent route id - " + conn_id}); err != nil { goto oops }
goto done
}
err = je.Encode(json_out_client_route{
Id: r.id,
ClientPeerAddr: r.peer_addr.String(),
ServerPeerListenAddr: r.server_peer_listen_addr.String(),
})
if err != nil { goto oops }
case http.MethodDelete:
err = cts.RemoveClientRouteById(uint32(route_nid))
if err != nil {
status_code = http.StatusNotFound; w.WriteHeader(status_code)
if err = je.Encode(json_errmsg{Text: err.Error()}); err != nil { goto oops }
} else {
status_code = http.StatusNoContent; w.WriteHeader(status_code)
}
default:
status_code = http.StatusBadRequest; w.WriteHeader(status_code)
}
done:
// TODO: need to handle x-forwarded-for and other stuff? this is not a real web service, though
c.log.Write("", LOG_DEBUG, "[%s] %s %s %d", req.RemoteAddr, req.Method, req.URL.String(), status_code) // TODO: time taken
return
oops:
c.log.Write("", LOG_ERROR, "[%s] %s %s - %s", req.RemoteAddr, req.Method, req.URL.String(), err.Error())
return
}
// ------------------------------------
func (ctl *client_ctl_clients) ServeHTTP(w http.ResponseWriter, req *http.Request) {

View File

@ -39,6 +39,7 @@ type Client struct {
ctx context.Context
ctx_cancel context.CancelFunc
tlscfg *tls.Config
api_prefix string
ext_svcs []Service
ctl *http.Server // control server
@ -451,6 +452,21 @@ func (cts *ClientConn) RemoveClientRouteById(route_id uint32) error {
return nil
}
func (cts *ClientConn) FindClientRouteById(route_id uint32) *ClientRoute {
var r *ClientRoute
var ok bool
cts.route_mtx.Lock()
r, ok = cts.route_map[route_id]
if !ok {
cts.route_mtx.Unlock()
return nil
}
cts.route_mtx.Unlock()
return r
}
func (cts *ClientConn) AddClientRoutes(peer_addrs []string) error {
var v string
var addr *net.TCPAddr
@ -755,13 +771,15 @@ func NewClient(ctx context.Context, listen_on string, logger Logger, tlscfg *tls
c.stop_req.Store(false)
c.stop_chan = make(chan bool, 8)
c.log = logger
c.api_prefix = "" // TODO:
c.mux = http.NewServeMux()
c.mux.Handle("/servers", &client_ctl_servers{c: &c})
c.mux.Handle("/servers/{id}", &client_ctl_servers_id{c: &c})
c.mux.Handle("/servers/{id}/peers", &client_ctl_servers_id_peers{c: &c})
c.mux.Handle("/clients", &client_ctl_clients{c: &c})
c.mux.Handle("/clients/{id}", &client_ctl_clients_id{c: &c})
c.mux.Handle(c.api_prefix + "/client-conns", &client_ctl_client_conns{c: &c})
c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}", &client_ctl_client_conns_id{c: &c})
c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}/routes", &client_ctl_client_conns_id_routes{c: &c})
c.mux.Handle(c.api_prefix + "/client-conns/{conn_id}/routes/{route_id}", &client_ctl_client_conns_id_routes_id{c: &c})
c.mux.Handle(c.api_prefix + "/server-conns", &client_ctl_clients{c: &c})
c.mux.Handle(c.api_prefix + "/server-conns/{id}", &client_ctl_clients_id{c: &c})
c.ctl = &http.Server{
Addr: listen_on,