mirror of
https://github.com/m1k1o/neko-rooms.git
synced 2026-11-02 22:51:34 -06:00
add labels filter support to API.
This commit is contained in:
+15
-1
@@ -3,14 +3,28 @@ package api
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"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) {
|
||||
response, err := manager.rooms.List()
|
||||
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(labelsMap)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
|
||||
@@ -28,6 +28,7 @@ func (manager *RoomManagerCtx) containerToEntry(container dockerTypes.Container)
|
||||
Running: container.State == "running",
|
||||
Status: container.Status,
|
||||
Created: time.Unix(container.Created, 0),
|
||||
Labels: labels.UserDefined,
|
||||
}
|
||||
|
||||
if labels.Mux {
|
||||
@@ -37,35 +38,23 @@ func (manager *RoomManagerCtx) containerToEntry(container dockerTypes.Container)
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
func (manager *RoomManagerCtx) listContainers() ([]dockerTypes.Container, error) {
|
||||
func (manager *RoomManagerCtx) listContainers(labels map[string]string) ([]dockerTypes.Container, error) {
|
||||
args := filters.NewArgs(
|
||||
filters.Arg("label", "m1k1o.neko_rooms.instance"),
|
||||
filters.Arg("label", fmt.Sprintf("m1k1o.neko_rooms.instance=%s", manager.config.InstanceName)),
|
||||
)
|
||||
|
||||
containers, err := manager.client.ContainerList(context.Background(), dockerTypes.ContainerListOptions{
|
||||
for key, val := range labels {
|
||||
args.Add("label", fmt.Sprintf("m1k1o.neko_rooms.x-%s=%s", key, val))
|
||||
}
|
||||
|
||||
return manager.client.ContainerList(context.Background(), dockerTypes.ContainerListOptions{
|
||||
All: true,
|
||||
Filters: args,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []dockerTypes.Container{}
|
||||
for _, container := range containers {
|
||||
val, ok := container.Labels["m1k1o.neko_rooms.instance"]
|
||||
if !ok || val != manager.config.InstanceName {
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, container)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (manager *RoomManagerCtx) containerFilter(args filters.Args) (*dockerTypes.Container, error) {
|
||||
args.Add("label", "m1k1o.neko_rooms.instance")
|
||||
args.Add("label", fmt.Sprintf("m1k1o.neko_rooms.instance=%s", manager.config.InstanceName))
|
||||
|
||||
containers, err := manager.client.ContainerList(context.Background(), dockerTypes.ContainerListOptions{
|
||||
All: true,
|
||||
@@ -81,12 +70,6 @@ func (manager *RoomManagerCtx) containerFilter(args filters.Args) (*dockerTypes.
|
||||
}
|
||||
|
||||
container := containers[0]
|
||||
|
||||
val, ok := container.Labels["m1k1o.neko_rooms.instance"]
|
||||
if !ok || val != manager.config.InstanceName {
|
||||
return nil, fmt.Errorf("this container does not belong to neko_rooms")
|
||||
}
|
||||
|
||||
return &container, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,15 @@ package room
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/m1k1o/neko-rooms/internal/types"
|
||||
)
|
||||
|
||||
var labelRegex = regexp.MustCompile(`^[a-z0-9.-]+$`)
|
||||
|
||||
type RoomLabels struct {
|
||||
Name string
|
||||
URL string
|
||||
@@ -15,6 +19,7 @@ type RoomLabels struct {
|
||||
NekoImage string
|
||||
|
||||
BrowserPolicy *BrowserPolicyLabels
|
||||
UserDefined map[string]string
|
||||
}
|
||||
|
||||
type BrowserPolicyLabels struct {
|
||||
@@ -101,6 +106,14 @@ func (manager *RoomManagerCtx) extractLabels(labels map[string]string) (*RoomLab
|
||||
}
|
||||
}
|
||||
|
||||
// extract user defined labels
|
||||
userDefined := map[string]string{}
|
||||
for key, val := range labels {
|
||||
if strings.HasPrefix(key, "m1k1o.neko_rooms.x-") {
|
||||
userDefined[strings.TrimPrefix(key, "m1k1o.neko_rooms.x-")] = val
|
||||
}
|
||||
}
|
||||
|
||||
return &RoomLabels{
|
||||
Name: name,
|
||||
URL: url,
|
||||
@@ -109,6 +122,7 @@ func (manager *RoomManagerCtx) extractLabels(labels map[string]string) (*RoomLab
|
||||
Epr: epr,
|
||||
|
||||
BrowserPolicy: browserPolicy,
|
||||
UserDefined: userDefined,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -133,5 +147,16 @@ func (manager *RoomManagerCtx) serializeLabels(labels RoomLabels) map[string]str
|
||||
labelsMap["m1k1o.neko_rooms.browser_policy.path"] = labels.BrowserPolicy.Path
|
||||
}
|
||||
|
||||
for key, val := range labels.UserDefined {
|
||||
// to lowercase
|
||||
key = strings.ToLower(key)
|
||||
|
||||
labelsMap[fmt.Sprintf("m1k1o.neko_rooms.x-%s", key)] = val
|
||||
}
|
||||
|
||||
return labelsMap
|
||||
}
|
||||
|
||||
func CheckLabelKey(name string) bool {
|
||||
return labelRegex.MatchString(name)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -62,13 +63,13 @@ func (manager *RoomManagerCtx) Config() types.RoomsConfig {
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *RoomManagerCtx) List() ([]types.RoomEntry, error) {
|
||||
containers, err := manager.listContainers()
|
||||
func (manager *RoomManagerCtx) List(labels map[string]string) ([]types.RoomEntry, error) {
|
||||
containers, err := manager.listContainers(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []types.RoomEntry{}
|
||||
result := make([]types.RoomEntry, 0, len(containers))
|
||||
for _, container := range containers {
|
||||
entry, err := manager.containerToEntry(container)
|
||||
if err != nil {
|
||||
@@ -174,6 +175,7 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro
|
||||
NekoImage: settings.NekoImage,
|
||||
|
||||
BrowserPolicy: browserPolicyLabels,
|
||||
UserDefined: settings.Labels,
|
||||
})
|
||||
|
||||
//
|
||||
@@ -652,9 +654,10 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro
|
||||
Name: labels.Name,
|
||||
NekoImage: labels.NekoImage,
|
||||
MaxConnections: labels.Epr.Max - labels.Epr.Min + 1,
|
||||
Labels: labels.UserDefined,
|
||||
Mounts: mounts,
|
||||
BrowserPolicy: browserPolicy,
|
||||
Resources: roomResources,
|
||||
BrowserPolicy: browserPolicy,
|
||||
}
|
||||
|
||||
if labels.Mux {
|
||||
@@ -678,7 +681,7 @@ func (manager *RoomManagerCtx) GetStats(id string) (*types.RoomStats, error) {
|
||||
}
|
||||
|
||||
output, err := manager.containerExec(id, []string{
|
||||
"wget", "-q", "-O-", "http://127.0.0.1:8080/stats?pwd=" + settings.AdminPass,
|
||||
"wget", "-q", "-O-", "http://127.0.0.1:8080/stats?pwd=" + url.QueryEscape(settings.AdminPass),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -44,7 +44,7 @@ func (manager *RoomManagerCtx) allocatePorts(sum uint16) (EprPorts, error) {
|
||||
}
|
||||
|
||||
func (manager *RoomManagerCtx) getUsedPorts() ([]EprPorts, error) {
|
||||
containers, err := manager.listContainers()
|
||||
containers, err := manager.listContainers(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+12
-10
@@ -35,15 +35,16 @@ type RoomsConfig struct {
|
||||
}
|
||||
|
||||
type RoomEntry struct {
|
||||
ID string `json:"id"`
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
NekoImage string `json:"neko_image"`
|
||||
IsOutdated bool `json:"is_outdated"`
|
||||
MaxConnections uint16 `json:"max_connections"` // 0 when using mux
|
||||
Running bool `json:"running"`
|
||||
Status string `json:"status"`
|
||||
Created time.Time `json:"created"`
|
||||
ID string `json:"id"`
|
||||
URL string `json:"url"`
|
||||
Name string `json:"name"`
|
||||
NekoImage string `json:"neko_image"`
|
||||
IsOutdated bool `json:"is_outdated"`
|
||||
MaxConnections uint16 `json:"max_connections"` // 0 when using mux
|
||||
Running bool `json:"running"`
|
||||
Status string `json:"status"`
|
||||
Created time.Time `json:"created"`
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
type MountType string
|
||||
@@ -94,6 +95,7 @@ type RoomSettings struct {
|
||||
BroadcastPipeline string `json:"broadcast_pipeline,omitempty"`
|
||||
|
||||
Envs map[string]string `json:"envs"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Mounts []RoomMount `json:"mounts"`
|
||||
Resources RoomResources `json:"resources"`
|
||||
|
||||
@@ -280,7 +282,7 @@ type RoomMember struct {
|
||||
|
||||
type RoomManager interface {
|
||||
Config() RoomsConfig
|
||||
List() ([]RoomEntry, error)
|
||||
List(labels map[string]string) ([]RoomEntry, error)
|
||||
FindByName(name string) (*RoomEntry, error)
|
||||
|
||||
Create(settings RoomSettings) (string, error)
|
||||
|
||||
Reference in New Issue
Block a user