mirror of
https://github.com/m1k1o/neko-rooms.git
synced 2026-11-03 07:01:35 -06:00
296 lines
7.1 KiB
Go
296 lines
7.1 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/m1k1o/neko-rooms/internal/room"
|
|
"github.com/m1k1o/neko-rooms/internal/types"
|
|
)
|
|
|
|
func (manager *ApiManagerCtx) roomsList(w http.ResponseWriter, r *http.Request) {
|
|
labelsMap := map[string]string{}
|
|
for key, value := range r.URL.Query() {
|
|
key = strings.ToLower(key)
|
|
|
|
if !room.CheckLabelKey(key) {
|
|
http.Error(w, "invalid label name, allowed characters: [a-z0-9.-]", 400)
|
|
return
|
|
}
|
|
|
|
labelsMap[key] = value[0]
|
|
}
|
|
|
|
response, err := manager.rooms.List(r.Context(), labelsMap)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomCreate(w http.ResponseWriter, r *http.Request) {
|
|
var start = true // default value
|
|
if s := r.URL.Query().Get("start"); s != "" {
|
|
var err error
|
|
start, err = strconv.ParseBool(s)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 400)
|
|
return
|
|
}
|
|
}
|
|
|
|
// Default values
|
|
request := types.RoomSettings{
|
|
MaxConnections: 10,
|
|
Resources: types.RoomResources{
|
|
ShmSize: 2 * 1e9,
|
|
},
|
|
}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
|
http.Error(w, err.Error(), 400)
|
|
return
|
|
}
|
|
|
|
ID, err := manager.rooms.Create(r.Context(), request)
|
|
if err != nil {
|
|
manager.logger.Error().Err(err).Msg("create: failed to create room")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
if start {
|
|
if err := manager.rooms.Start(r.Context(), ID); err != nil {
|
|
manager.logger.Error().Err(err).Msg("create: failed to start room")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
}
|
|
|
|
response, err := manager.rooms.GetEntry(r.Context(), ID)
|
|
if err != nil {
|
|
manager.logger.Error().Err(err).Msg("create: failed to get room entry")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomRecreate(w http.ResponseWriter, r *http.Request) {
|
|
roomId := chi.URLParam(r, "roomId")
|
|
|
|
var start bool
|
|
if s := r.URL.Query().Get("start"); s != "" {
|
|
var err error
|
|
start, err = strconv.ParseBool(s)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 400)
|
|
return
|
|
}
|
|
} else {
|
|
entry, err := manager.rooms.GetEntry(r.Context(), roomId)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
manager.logger.Error().Err(err).Msg("recreate: failed to get room entry")
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
start = entry.Running
|
|
}
|
|
|
|
settings, err := manager.rooms.GetSettings(r.Context(), roomId)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
manager.logger.Error().Err(err).Msg("recreate: failed to get room settings")
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
// optional settings payload
|
|
if err := json.NewDecoder(r.Body).Decode(&settings); err != nil && !errors.Is(err, io.EOF) {
|
|
http.Error(w, err.Error(), 400)
|
|
return
|
|
}
|
|
|
|
if err := manager.rooms.Remove(r.Context(), roomId); err != nil {
|
|
manager.logger.Error().Err(err).Msg("recreate: failed to remove room")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
ID, err := manager.rooms.Create(r.Context(), *settings)
|
|
if err != nil {
|
|
manager.logger.Error().Err(err).Msg("recreate: failed to create room")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
if start {
|
|
if err := manager.rooms.Start(r.Context(), ID); err != nil {
|
|
manager.logger.Error().Err(err).Msg("recreate: failed to start room")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
}
|
|
|
|
response, err := manager.rooms.GetEntry(r.Context(), ID)
|
|
if err != nil {
|
|
manager.logger.Error().Err(err).Msg("recreate: failed to get room entry")
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomGetEntry(w http.ResponseWriter, r *http.Request) {
|
|
roomId := chi.URLParam(r, "roomId")
|
|
|
|
response, err := manager.rooms.GetEntry(r.Context(), roomId)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomGetEntryByName(w http.ResponseWriter, r *http.Request) {
|
|
// roomId is actually room name here
|
|
roomName := chi.URLParam(r, "roomId")
|
|
|
|
response, err := manager.rooms.GetEntryByName(r.Context(), roomName)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomGetSettings(w http.ResponseWriter, r *http.Request) {
|
|
roomId := chi.URLParam(r, "roomId")
|
|
|
|
response, err := manager.rooms.GetSettings(r.Context(), roomId)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomGetStats(w http.ResponseWriter, r *http.Request) {
|
|
roomId := chi.URLParam(r, "roomId")
|
|
|
|
response, err := manager.rooms.GetStats(r.Context(), roomId)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) roomGenericAction(action func(ctx context.Context, id string) error) func(http.ResponseWriter, *http.Request) {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
roomId := chi.URLParam(r, "roomId")
|
|
|
|
err := action(r.Context(), roomId)
|
|
if err != nil {
|
|
if errors.Is(err, types.ErrRoomNotFound) {
|
|
http.Error(w, err.Error(), 404)
|
|
} else {
|
|
http.Error(w, err.Error(), 500)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) events(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "text/event-stream")
|
|
w.Header().Set("Cache-Control", "no-cache")
|
|
w.Header().Set("Connection", "keep-alive")
|
|
|
|
flusher, ok := w.(http.Flusher)
|
|
if !ok {
|
|
http.Error(w, "Connection does not support streaming", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
events, errs := manager.rooms.Events(r.Context())
|
|
for {
|
|
select {
|
|
case _, ok := <-errs:
|
|
if !ok {
|
|
manager.logger.Debug().Msg("sse channel closed")
|
|
}
|
|
return
|
|
case e := <-events:
|
|
jsonData, err := json.Marshal(e)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
fmt.Fprintf(w, "data: %s\n\n", jsonData)
|
|
flusher.Flush()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (manager *ApiManagerCtx) dockerCompose(w http.ResponseWriter, r *http.Request) {
|
|
response, err := manager.rooms.ExportAsDockerCompose(r.Context())
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 500)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/yaml")
|
|
w.Write(response)
|
|
}
|