forked from Cliffbreak/tsviewer
		
	Compare commits
	
		
			59 commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 59bd3d7139 | |||
| a454dbc947 | |||
| 8416fcbdb4 | |||
| 
							 | 
						cf378679fb | ||
| d57986721d | |||
| b91c02e815 | |||
| bfba32968c | |||
| 53b246a6df | |||
| 1f523a6b7d | |||
| 1a9f7fd72e | |||
| 0121873d35 | |||
| c3fb6ce53b | |||
| fa24055a52 | |||
| 036d6f604c | |||
| 1f23290854 | |||
| c78afcdc24 | |||
| 4d4311c30c | |||
| 5527744c43 | |||
| 2089963e9e | |||
| 7ebfd7be08 | |||
| 0d575286fa | |||
| d6e1047ba2 | |||
| eddc32a157 | |||
| 8bd0e85e17 | |||
| 298435a4cb | |||
| cfde0fd79b | |||
| d1b9551889 | |||
| a308206256 | |||
| 96fd78fcd3 | |||
| 5a0da7fced | |||
| 126eb99d0f | |||
| e4556869fe | |||
| 50b56687eb | |||
| e152962fe7 | |||
| 6343577301 | |||
| 470370aebd | |||
| 5189cb63f6 | |||
| d7d3732fab | |||
| c0e8b1b8e1 | |||
| 66fc41cc7f | |||
| 2250abb484 | |||
| 5012872895 | |||
| 1441b942a9 | |||
| 5bb3e7781a | |||
| 8ed735698b | |||
| b2480324c3 | |||
| e64c0c78a6 | |||
| 1e03bba52b | |||
| 036219f445 | |||
| 9e2d7e9acc | |||
| 872dd200e1 | |||
| 58761d011e | |||
| 49129c845f | |||
| 119f9c4915 | |||
| edbf70eede | |||
| c534e4bf49 | |||
| 615f1969d7 | |||
| 8f613ed089 | |||
| 42a606b308 | 
					 31 changed files with 479 additions and 169 deletions
				
			
		
							
								
								
									
										0
									
								
								.dockerignore
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.dockerignore
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -13,4 +13,5 @@
 | 
				
			||||||
*.out
 | 
					*.out
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Custom Blacklist
 | 
					# Custom Blacklist
 | 
				
			||||||
config.json
 | 
					
 | 
				
			||||||
 | 
					#CM
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								Dockerfile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Dockerfile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					FROM golang:latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENV TS3_IP=127.0.0.1
 | 
				
			||||||
 | 
					ENV TS3_NAME=serveradmin
 | 
				
			||||||
 | 
					ENV TS3_PW=<changeMe>
 | 
				
			||||||
 | 
					ENV TS3_PORT=9987
 | 
				
			||||||
 | 
					ENV TS3_QUERY=10011
 | 
				
			||||||
 | 
					ENV WEB_PORT=8080
 | 
				
			||||||
 | 
					ENV BLACKLIST_USER=USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN mkdir /app 		
 | 
				
			||||||
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					RUN mkdir /app/go	    
 | 
				
			||||||
 | 
					RUN export GOPATH=/app/go
 | 
				
			||||||
 | 
					COPY main.go .
 | 
				
			||||||
 | 
					RUN go get; exit 0
 | 
				
			||||||
 | 
					WORKDIR $GOPATH/src/git.cliffbreak.de/Cliffbreak/tsviewer
 | 
				
			||||||
 | 
					COPY config.json .
 | 
				
			||||||
 | 
					RUN go build 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMD ["./tsviewer"]  
 | 
				
			||||||
							
								
								
									
										59
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -1,30 +1,59 @@
 | 
				
			||||||
# go-tsviewer **[WIP]**
 | 
					# tsviewer **[ALPHA 1.0.1]**
 | 
				
			||||||
## **WARNING** This API is not usable ATM
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
A REST API made for TS3 Viewer.
 | 
					A TS3 Viewer with REST API.
 | 
				
			||||||
 | 
					## DOCKER-Config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```bash
 | 
				
			||||||
 | 
					docker build -t name/cont:ver .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					docker run -e TS3_IP="<SERVER-IP>" -e TS3_PW="<SERVER-ADMIN_PW>" -e WEB_PORT="8080" -d -p 8080:8080 name/cont:ver
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					ENV:
 | 
				
			||||||
 | 
					```Docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENV TS3_IP=127.0.0.1
 | 
				
			||||||
 | 
					ENV TS3_NAME=serveradmin
 | 
				
			||||||
 | 
					ENV TS3_PW=<changeMe>
 | 
				
			||||||
 | 
					ENV TS3_PORT=9987
 | 
				
			||||||
 | 
					ENV TS3_QUERY=10011
 | 
				
			||||||
 | 
					ENV WEB_PORT=8080
 | 
				
			||||||
 | 
					ENV BLACKLIST_USER=USER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Features
 | 
					# Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Config
 | 
					## Config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The config file is generated automatically on first startup.
 | 
					The config file is generated automatically on first startup.
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    "ip": "127.0.0.1",              // Server IP
 | 
					 | 
				
			||||||
    "port": 10011,                  // Dataquery Port
 | 
					 | 
				
			||||||
    "user": {
 | 
					    "user": {
 | 
				
			||||||
        "name": "serveradmin",      // Username
 | 
					        "nickname": "serveradmin",
 | 
				
			||||||
        "password": ""              // Password
 | 
					        "name": "serveradmin",
 | 
				
			||||||
 | 
					        "password": ""
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "server": {
 | 
					    "serverTS": {
 | 
				
			||||||
        "port": 9987                // Port of the target server
 | 
					        "ip": "127.0.0.1",
 | 
				
			||||||
 | 
					        "portServer": 9987,
 | 
				
			||||||
 | 
					        "portQuery": 10011
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "serverWeb": {
 | 
				
			||||||
 | 
					        "port": 80
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## URL-Parameter
 | 
					## URL-Parameter
 | 
				
			||||||
| Name       | Type     | Description              |
 | 
					
 | 
				
			||||||
| ---------- | -------- | ------------------------ |
 | 
					| Name       | Type   | Description              |
 | 
				
			||||||
| `pretty`   | `bool`   | pretty-prints JSON       |
 | 
					| ---------- | ------ | ------------------------ |
 | 
				
			||||||
| `envelope` | `bool`   | wraps JSON in data array |
 | 
					| `pretty`   | `bool` | pretty-prints JSON       |
 | 
				
			||||||
 | 
					| `envelope` | `bool` | wraps JSON in data array |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Channels
 | 
					## Channels
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **`GET`** `/v1/channels/:id`
 | 
					- **`GET`** `/v1/channels/:id`
 | 
				
			||||||
- **`GET`** `/v1/channels`
 | 
					- **`GET`** `/v1/channels`
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
| 
						 | 
					@ -37,7 +66,9 @@ The config file is generated automatically on first startup.
 | 
				
			||||||
    "awayMessage": ""
 | 
					    "awayMessage": ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Clients
 | 
					## Clients
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **`GET`** `/v1/clients/:id`
 | 
					- **`GET`** `/v1/clients/:id`
 | 
				
			||||||
- **`GET`** `/v1/clients/`
 | 
					- **`GET`** `/v1/clients/`
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
| 
						 | 
					@ -51,7 +82,9 @@ The config file is generated automatically on first startup.
 | 
				
			||||||
    "neededSubscribePower": 0
 | 
					    "neededSubscribePower": 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Server
 | 
					## Server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **`GET`** `/v1/server/info`
 | 
					- **`GET`** `/v1/server/info`
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								config.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								config.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "user": {
 | 
				
			||||||
 | 
					        "nickname": "serveradmin",
 | 
				
			||||||
 | 
					        "name": "serveradmin",
 | 
				
			||||||
 | 
					        "password": "HNxkefVx"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "serverTS": {
 | 
				
			||||||
 | 
					        "ip": "127.0.0.1",
 | 
				
			||||||
 | 
					        "portServer": 9987,
 | 
				
			||||||
 | 
					        "portQuery": 10011
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "serverWeb": {
 | 
				
			||||||
 | 
					        "port": 80
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										117
									
								
								config/config.go
									
										
									
									
									
								
							
							
						
						
									
										117
									
								
								config/config.go
									
										
									
									
									
								
							| 
						 | 
					@ -1,69 +1,84 @@
 | 
				
			||||||
package config
 | 
					package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"io/ioutil"
 | 
					 | 
				
			||||||
	"log"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/spf13/viper"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	IP     string `json:"ip"`
 | 
						User struct {
 | 
				
			||||||
	Port   uint16 `json:"port"`
 | 
							Nickname string
 | 
				
			||||||
	User   User   `json:"user"`
 | 
							Name     string
 | 
				
			||||||
	Server Server `json:"server"`
 | 
							Password string
 | 
				
			||||||
}
 | 
						}
 | 
				
			||||||
 | 
						ServerTS struct {
 | 
				
			||||||
type User struct {
 | 
							IP         string
 | 
				
			||||||
	Name     string `json:"name"`
 | 
							PortServer uint16
 | 
				
			||||||
	Password string `json:"password"`
 | 
							PortQuery  uint16
 | 
				
			||||||
}
 | 
						}
 | 
				
			||||||
 | 
						ServerWeb struct {
 | 
				
			||||||
type Server struct {
 | 
							Port uint16
 | 
				
			||||||
	Port uint16 `json:"port"`
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const FileName = "config.json"
 | 
					const FileName = "config.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func New() (*Config, error) {
 | 
					func New() (*Config, error) {
 | 
				
			||||||
	config := defaults()
 | 
						viper.SetConfigName("config")
 | 
				
			||||||
 | 
						viper.SetConfigFile("yaml")
 | 
				
			||||||
	configFile, err := os.Open(FileName)
 | 
						viper.AddConfigPath(".")
 | 
				
			||||||
	if err != nil {
 | 
						if err := viper.ReadInConfig(); err != nil {
 | 
				
			||||||
		if err := config.createFile(); err != nil {
 | 
							return nil, err
 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		log.Println(config)
 | 
					 | 
				
			||||||
		return &config, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	defer configFile.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	jsonParser := json.NewDecoder(configFile)
 | 
					 | 
				
			||||||
	jsonParser.Decode(&config)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &config, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (config Config) createFile() error {
 | 
					 | 
				
			||||||
	configJSON, err := json.MarshalIndent(config, "", "    ")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ioutil.WriteFile(FileName, configJSON, 0644)
 | 
						setDefaults()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var config Config
 | 
				
			||||||
 | 
						err := viper.Unmarshal(&config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						config.overrideWithEnvironmentVars()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &config, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func defaults() Config {
 | 
					func setDefaults() {
 | 
				
			||||||
	return Config{
 | 
						viper.SetDefault("User.Nickname", "serveradmin")
 | 
				
			||||||
		IP:   "127.0.0.1",
 | 
						viper.SetDefault("User.Name", "serveradmin")
 | 
				
			||||||
		Port: 10011,
 | 
						viper.SetDefault("User.Password", "<changeMe>")
 | 
				
			||||||
		User: User{
 | 
						viper.SetDefault("ServerTS.IP", "127.0.0.1")
 | 
				
			||||||
			Name:     "serveradmin",
 | 
						viper.SetDefault("ServerTS.PortServer", "9987")
 | 
				
			||||||
			Password: "",
 | 
						viper.SetDefault("ServerTS.PortQuery", "10011")
 | 
				
			||||||
		},
 | 
						viper.SetDefault("ServerWeb.Port", "80")
 | 
				
			||||||
		Server: Server{
 | 
					}
 | 
				
			||||||
			Port: 9987,
 | 
					
 | 
				
			||||||
		},
 | 
					func (config *Config) overrideWithEnvironmentVars() {
 | 
				
			||||||
 | 
						if nickname := os.Getenv("TS3_NICKNAME"); nickname != "" {
 | 
				
			||||||
 | 
							config.User.Nickname = nickname
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if username := os.Getenv("TS3_NAME"); username != "" {
 | 
				
			||||||
 | 
							config.User.Name = username
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if password := os.Getenv("TS3_PW"); password != "" {
 | 
				
			||||||
 | 
							config.User.Password = password
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if tsIP := os.Getenv("TS3_IP"); tsIP != "" {
 | 
				
			||||||
 | 
							config.ServerTS.IP = tsIP
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if tsPort, err := strconv.Atoi(os.Getenv("TS3_PORT")); tsPort <= 65535 && tsPort >= 0 && err == nil {
 | 
				
			||||||
 | 
							config.ServerTS.PortServer = uint16(tsPort)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if tsQuery, err := strconv.Atoi(os.Getenv("TS3_QUERY")); tsQuery <= 65535 && tsQuery >= 0 && err == nil {
 | 
				
			||||||
 | 
							config.ServerTS.PortQuery = uint16(tsQuery)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if webPort, err := strconv.Atoi(os.Getenv("WEB_PORT")); webPort <= 65535 && webPort >= 0 && err == nil {
 | 
				
			||||||
 | 
							config.ServerWeb.Port = uint16(webPort)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,8 @@ type Service interface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Channel struct {
 | 
					type Channel struct {
 | 
				
			||||||
	ID                   int       `json:"id"`
 | 
						ID                   int       `json:"id"`
 | 
				
			||||||
	Subchannels          []Channel `json:"subchannels,omitempty"`
 | 
					 | 
				
			||||||
	Name                 string    `json:"name"`
 | 
						Name                 string    `json:"name"`
 | 
				
			||||||
 | 
						Subchannels          []Channel `json:"subchannels,omitempty"`
 | 
				
			||||||
	TotalClients         int       `json:"totalClients"`
 | 
						TotalClients         int       `json:"totalClients"`
 | 
				
			||||||
	NeededSubscribePower int       `json:"neededSubscribePower"`
 | 
						NeededSubscribePower int       `json:"neededSubscribePower"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -4,13 +4,13 @@ import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/response"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/response"
 | 
				
			||||||
	"github.com/go-chi/chi"
 | 
						"github.com/go-chi/chi"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ChannelAPIHandler(s Service) http.HandlerFunc {
 | 
					func ChannelAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		response.Handler(w, response.HandlerFunc(func() (int, error) {
 | 
							response.Handler(w, r, response.HandlerFunc(func() (int, error) {
 | 
				
			||||||
			id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64)
 | 
								id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return http.StatusBadRequest, err
 | 
									return http.StatusBadRequest, err
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ func ChannelAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ChannelsAPIHandler(s Service) http.HandlerFunc {
 | 
					func ChannelsAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		response.Handler(w, response.HandlerFunc(func() (int, error) {
 | 
							response.Handler(w, r, response.HandlerFunc(func() (int, error) {
 | 
				
			||||||
			cc, err := s.Channels()
 | 
								cc, err := s.Channels()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return http.StatusBadRequest, err
 | 
									return http.StatusBadRequest, err
 | 
				
			||||||
| 
						 | 
					@ -4,13 +4,13 @@ import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/response"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/response"
 | 
				
			||||||
	"github.com/go-chi/chi"
 | 
						"github.com/go-chi/chi"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ClientAPIHandler(s Service) http.HandlerFunc {
 | 
					func ClientAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		response.Handler(w, response.HandlerFunc(func() (int, error) {
 | 
							response.Handler(w, r, response.HandlerFunc(func() (int, error) {
 | 
				
			||||||
			id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64)
 | 
								id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return http.StatusBadRequest, err
 | 
									return http.StatusBadRequest, err
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ func ClientAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ClientsAPIHandler(s Service) http.HandlerFunc {
 | 
					func ClientsAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		response.Handler(w, response.HandlerFunc(func() (int, error) {
 | 
							response.Handler(w, r, response.HandlerFunc(func() (int, error) {
 | 
				
			||||||
			cc, err := s.Clients()
 | 
								cc, err := s.Clients()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return http.StatusBadRequest, err
 | 
									return http.StatusBadRequest, err
 | 
				
			||||||
| 
						 | 
					@ -3,13 +3,13 @@ package server
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/response"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/response"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func InfoAPIHandler(s Service) http.HandlerFunc {
 | 
					func InfoAPIHandler(s Service) http.HandlerFunc {
 | 
				
			||||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		response.Handler(w, response.HandlerFunc(func() (int, error) {
 | 
							response.Handler(w, r, response.HandlerFunc(func() (int, error) {
 | 
				
			||||||
			s, err := s.Info()
 | 
								s, err := s.ServerInfo()
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return http.StatusNotFound, err
 | 
									return http.StatusNotFound, err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ package server
 | 
				
			||||||
import "time"
 | 
					import "time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Service interface {
 | 
					type Service interface {
 | 
				
			||||||
	Info() (*Server, error)
 | 
						ServerInfo() (*Server, error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Server struct {
 | 
					type Server struct {
 | 
				
			||||||
							
								
								
									
										32
									
								
								features/web/index/handler.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								features/web/index/handler.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					package index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/web/weberror"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IndexGUIHandler(s Service, t template.Template) http.HandlerFunc {
 | 
				
			||||||
 | 
						return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							server, err := s.ServerInfo()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								weberror.NewPage(err, http.StatusNotFound).Send(w, t)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							channels, err := s.ChannelsRaw()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								weberror.NewPage(err, http.StatusNotFound).Send(w, t)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							clients, err := s.Clients()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								weberror.NewPage(err, http.StatusNotFound).Send(w, t)
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NewPage(*server, channels, clients).Send(w, t)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								features/web/index/page.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								features/web/index/page.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					package index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/channel"
 | 
				
			||||||
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/client"
 | 
				
			||||||
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/server"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Service interface {
 | 
				
			||||||
 | 
						ServerInfo() (*server.Server, error)
 | 
				
			||||||
 | 
						Clients() ([]*client.Client, error)
 | 
				
			||||||
 | 
						Channels() ([]*channel.Channel, error)
 | 
				
			||||||
 | 
						ChannelsRaw() ([]*channel.Channel, error)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IndexPage struct {
 | 
				
			||||||
 | 
						Server   server.Server
 | 
				
			||||||
 | 
						Channels []*channel.Channel
 | 
				
			||||||
 | 
						Clients  []*client.Client
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewPage(server server.Server, channels []*channel.Channel, clients []*client.Client) *IndexPage {
 | 
				
			||||||
 | 
						return &IndexPage{
 | 
				
			||||||
 | 
							Server:   server,
 | 
				
			||||||
 | 
							Channels: channels,
 | 
				
			||||||
 | 
							Clients:  clients,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (page IndexPage) Send(w io.Writer, t template.Template) {
 | 
				
			||||||
 | 
						t.Lookup("index.html").Execute(w, page)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										15
									
								
								features/web/index/routes.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								features/web/index/routes.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					package index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/go-chi/chi"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GUIRoutes(s Service, t template.Template) *chi.Mux {
 | 
				
			||||||
 | 
						router := chi.NewRouter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						router.Get("/", IndexGUIHandler(s, t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return router
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										22
									
								
								features/web/weberror/page.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								features/web/weberror/page.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					package weberror
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ErrorPage struct {
 | 
				
			||||||
 | 
						Error      error
 | 
				
			||||||
 | 
						StatusCode int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewPage(err error, statusCode int) *ErrorPage {
 | 
				
			||||||
 | 
						return &ErrorPage{
 | 
				
			||||||
 | 
							Error:      err,
 | 
				
			||||||
 | 
							StatusCode: statusCode,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (page ErrorPage) Send(w io.Writer, t template.Template) {
 | 
				
			||||||
 | 
						t.Lookup("error.html").Execute(w, page)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								gui/template.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								gui/template.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					package gui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func LoadTemplates() (*template.Template, error) {
 | 
				
			||||||
 | 
						return loadTemplates("templates/")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadTemplates(path string) (*template.Template, error) {
 | 
				
			||||||
 | 
						dir, err := ioutil.ReadDir(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var ff []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, file := range dir {
 | 
				
			||||||
 | 
							filename := file.Name()
 | 
				
			||||||
 | 
							if strings.HasSuffix(filename, ".html") {
 | 
				
			||||||
 | 
								ff = append(ff, fmt.Sprintf("%s%s", path, filename))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						templates, err := template.ParseFiles(ff...)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return templates, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										46
									
								
								main.go
									
										
									
									
									
								
							
							
						
						
									
										46
									
								
								main.go
									
										
									
									
									
								
							| 
						 | 
					@ -1,27 +1,38 @@
 | 
				
			||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/config"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/config"
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/features/channel"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/channel"
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/features/client"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/client"
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/features/server"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/server"
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/service"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/web/index"
 | 
				
			||||||
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/gui"
 | 
				
			||||||
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/service"
 | 
				
			||||||
	"github.com/go-chi/chi"
 | 
						"github.com/go-chi/chi"
 | 
				
			||||||
	"github.com/go-chi/chi/middleware"
 | 
						"github.com/go-chi/chi/middleware"
 | 
				
			||||||
 | 
						"github.com/go-chi/cors"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Routes(s service.Service) *chi.Mux {
 | 
					func Routes(s service.Service, t template.Template) *chi.Mux {
 | 
				
			||||||
	router := chi.NewRouter()
 | 
						router := chi.NewRouter()
 | 
				
			||||||
 | 
						cors := cors.New(cors.Options{
 | 
				
			||||||
 | 
							AllowedOrigins: []string{"*"},
 | 
				
			||||||
 | 
							AllowedMethods: []string{"Get"},
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	router.Use(
 | 
						router.Use(
 | 
				
			||||||
		middleware.Logger,
 | 
							middleware.Logger,
 | 
				
			||||||
		middleware.Timeout(5*time.Second),
 | 
							middleware.Timeout(5*time.Second),
 | 
				
			||||||
		middleware.DefaultCompress,
 | 
							middleware.DefaultCompress,
 | 
				
			||||||
		middleware.RedirectSlashes,
 | 
							middleware.RedirectSlashes,
 | 
				
			||||||
		middleware.Recoverer,
 | 
							middleware.Recoverer,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cors.Handler,
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	router.Route("/v1", func(r chi.Router) {
 | 
						router.Route("/v1", func(r chi.Router) {
 | 
				
			||||||
| 
						 | 
					@ -30,22 +41,41 @@ func Routes(s service.Service) *chi.Mux {
 | 
				
			||||||
		r.Mount("/server", server.APIRoutes(s))
 | 
							r.Mount("/server", server.APIRoutes(s))
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						router.Route("/", func(r chi.Router) {
 | 
				
			||||||
 | 
							r.Mount("/", index.GUIRoutes(s, t))
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return router
 | 
						return router
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
 | 
						log.Println("Loading configurations...")
 | 
				
			||||||
	config, err := config.New()
 | 
						config, err := config.New()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatal(err)
 | 
							log.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						log.Println("Configurations loaded!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Println("Starting query service...")
 | 
				
			||||||
	service, err := service.New(*config)
 | 
						service, err := service.New(*config)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Fatal(err)
 | 
							log.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	defer service.TSClient.Close()
 | 
						defer service.TSClient.Close()
 | 
				
			||||||
 | 
						log.Println("Query service connected to", fmt.Sprintf("%s:%d!", config.ServerTS.IP, config.ServerTS.PortQuery))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	router := Routes(*service)
 | 
						log.Println("Loading templates...")
 | 
				
			||||||
 | 
						templates, err := gui.LoadTemplates()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						log.Println("All templates loaded!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Fatal("Handler: ", http.ListenAndServe(":8080", router))
 | 
						router := Routes(*service, *templates)
 | 
				
			||||||
 | 
						router.Get("/static/*", func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							http.StripPrefix("/static", http.FileServer(http.Dir("./static"))).ServeHTTP(w, r)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Println("Starting the web server locally on port", config.ServerWeb.Port)
 | 
				
			||||||
 | 
						log.Fatal("Handler: ", http.ListenAndServe(fmt.Sprintf(":%d", config.ServerWeb.Port), router))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,12 +10,10 @@ type Error struct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewError creates a new Response fill with an error
 | 
					// NewError creates a new Response fill with an error
 | 
				
			||||||
func NewError(status int, err error) *Response {
 | 
					func NewError(status int, err error) *Error {
 | 
				
			||||||
	return &Response{
 | 
						return &Error{
 | 
				
			||||||
		Content: Error{
 | 
							Status:    status,
 | 
				
			||||||
			Status:    status,
 | 
							Error:     err.Error(),
 | 
				
			||||||
			Error:     err.Error(),
 | 
							Timestamp: time.Now().Format("2006-01-02T15:04:05Z"), //.Format("02 Jan 2006, 15:04:05 MST"),
 | 
				
			||||||
			Timestamp: time.Now().Format("2006-01-02T15:04:05Z"), //.Format("02 Jan 2006, 15:04:05 MST"),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ import (
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/request/meta"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/request/meta"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type HandlerFunc func() (int, error)
 | 
					type HandlerFunc func() (int, error)
 | 
				
			||||||
| 
						 | 
					@ -74,14 +74,14 @@ func (resp Response) Send(w http.ResponseWriter, status int) (int, error) {
 | 
				
			||||||
	return status, nil
 | 
						return status, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func Handler(w http.ResponseWriter, hf HandlerFunc) {
 | 
					func Handler(w http.ResponseWriter, r *http.Request, hf HandlerFunc) {
 | 
				
			||||||
	status, err := hf()
 | 
						status, err := hf()
 | 
				
			||||||
	if err == nil {
 | 
						if err == nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	log.Printf("HTTP %d: %q", status, err)
 | 
						log.Printf("HTTP %d: %q", status, err)
 | 
				
			||||||
	if status, err = NewError(status, err).Send(w, status); err != nil {
 | 
						if status, err = New(NewError(status, err), r).Send(w, status); err != nil {
 | 
				
			||||||
		http.Error(w, http.StatusText(status), status)
 | 
							http.Error(w, http.StatusText(status), status)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ package service
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/features/channel"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/channel"
 | 
				
			||||||
	"github.com/multiplay/go-ts3"
 | 
						"github.com/multiplay/go-ts3"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,28 +37,64 @@ func (s Service) Channels() ([]*channel.Channel, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var cc []*channel.Channel
 | 
						var cc []*channel.Channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, channel := range channels {
 | 
						for i, channel := range channels {
 | 
				
			||||||
		if channel.ParentID == 0 {
 | 
							if channel == nil {
 | 
				
			||||||
			cc = append(cc, convertChannel(channel))
 | 
					 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for _, c := range cc {
 | 
							if channel.ParentID == 0 {
 | 
				
			||||||
			if c.ID == channel.ParentID {
 | 
								channels[i] = nil
 | 
				
			||||||
				c.Subchannels = append(c.Subchannels, *convertChannel(channel))
 | 
								cc = append(cc, convertChannel(channel))
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, c := range cc {
 | 
				
			||||||
 | 
							addSubChannels(c, channels)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cc, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (s Service) ChannelsRaw() ([]*channel.Channel, error) {
 | 
				
			||||||
 | 
						channels, err := s.TSClient.Server.ChannelList()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var cc []*channel.Channel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, channel := range channels {
 | 
				
			||||||
 | 
							if channel == nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cc = append(cc, convertChannel(channel))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cc, nil
 | 
						return cc, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func convertChannel(c *ts3.Channel) *channel.Channel {
 | 
					func convertChannel(c *ts3.Channel) *channel.Channel {
 | 
				
			||||||
	return &channel.Channel{
 | 
						return &channel.Channel{
 | 
				
			||||||
		ID:                   c.ID,
 | 
							ID:                   c.ID,
 | 
				
			||||||
		Subchannels:          []channel.Channel{},
 | 
					 | 
				
			||||||
		Name:                 c.ChannelName,
 | 
							Name:                 c.ChannelName,
 | 
				
			||||||
 | 
							Subchannels:          []channel.Channel{},
 | 
				
			||||||
		TotalClients:         c.TotalClients,
 | 
							TotalClients:         c.TotalClients,
 | 
				
			||||||
		NeededSubscribePower: c.NeededSubscribePower,
 | 
							NeededSubscribePower: c.NeededSubscribePower,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func addSubChannels(c *channel.Channel, channels []*ts3.Channel) {
 | 
				
			||||||
 | 
						for i, channel := range channels {
 | 
				
			||||||
 | 
							if channel == nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if c.ID == channel.ParentID {
 | 
				
			||||||
 | 
								channels[i] = nil
 | 
				
			||||||
 | 
								subChannel := convertChannel(channel)
 | 
				
			||||||
 | 
								addSubChannels(subChannel, channels)
 | 
				
			||||||
 | 
								c.Subchannels = append(c.Subchannels, *subChannel)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ package service
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/features/client"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/client"
 | 
				
			||||||
	"github.com/multiplay/go-ts3"
 | 
						"github.com/multiplay/go-ts3"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,10 +26,6 @@ func (s Service) Client(id int) (*client.Client, error) {
 | 
				
			||||||
		return nil, errors.New("client does not exist")
 | 
							return nil, errors.New("client does not exist")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* 	if _, err := s.TSClient.Server.ExecCmd(ts3.NewCmd(fmt.Sprintf("clientinfo clid=%d", c.ID)).WithResponse(&c)); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	} */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return c, nil
 | 
						return c, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,10 +3,10 @@ package service
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/features/server"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/features/api/server"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s Service) Info() (*server.Server, error) {
 | 
					func (s Service) ServerInfo() (*server.Server, error) {
 | 
				
			||||||
	serverInfo, err := s.TSClient.Server.Info()
 | 
						serverInfo, err := s.TSClient.Server.Info()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,11 @@
 | 
				
			||||||
package service
 | 
					package service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"strconv"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/config"
 | 
						"git.cliffbreak.de/Cliffbreak/tsviewer/config"
 | 
				
			||||||
	"git.cliffbreak.de/haveachin/go-tsviewer/stringer"
 | 
					 | 
				
			||||||
	ts3 "github.com/multiplay/go-ts3"
 | 
						ts3 "github.com/multiplay/go-ts3"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,12 +14,7 @@ type Service struct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func New(config config.Config) (*Service, error) {
 | 
					func New(config config.Config) (*Service, error) {
 | 
				
			||||||
	addr, err := stringer.Build(config.IP, ":", strconv.Itoa(int(config.Port)))
 | 
						client, err := ts3.NewClient(fmt.Sprintf("%s:%d", config.ServerTS.IP, config.ServerTS.PortQuery))
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	client, err := ts3.NewClient(addr)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -27,10 +23,22 @@ func New(config config.Config) (*Service, error) {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := client.UsePort(int(config.Server.Port)); err != nil {
 | 
						if err := client.UsePort(int(config.ServerTS.PortServer)); err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := client.SetNick(config.User.Nickname); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							for true {
 | 
				
			||||||
 | 
								time.Sleep(time.Second * 150)
 | 
				
			||||||
 | 
								client.Server.Version()
 | 
				
			||||||
 | 
								log.Println("keep alive")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &Service{
 | 
						return &Service{
 | 
				
			||||||
		TSClient: client,
 | 
							TSClient: client,
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								static/styles.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								static/styles.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					*{
 | 
				
			||||||
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.content {
 | 
				
			||||||
 | 
					    max-width: 500px;
 | 
				
			||||||
 | 
					    margin: auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					h2{
 | 
				
			||||||
 | 
					    padding-top: 20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					small{
 | 
				
			||||||
 | 
					    margin-left: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					p.client{
 | 
				
			||||||
 | 
					    margin-left: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,49 +0,0 @@
 | 
				
			||||||
package stringer
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"strings"
 | 
					 | 
				
			||||||
	"unicode"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func Build(ss ...string) (string, error) {
 | 
					 | 
				
			||||||
	var builder strings.Builder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, s := range ss {
 | 
					 | 
				
			||||||
		if _, err := builder.WriteString(s); err != nil {
 | 
					 | 
				
			||||||
			return "", err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return builder.String(), nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func ToCamel(str string) string {
 | 
					 | 
				
			||||||
	if len(str) < 1 {
 | 
					 | 
				
			||||||
		return str
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for i, c := range str[1:] {
 | 
					 | 
				
			||||||
		if c >= 'A' && c <= 'Z' {
 | 
					 | 
				
			||||||
			str = fmt.Sprintf("%s_%c%s", str[:i+1], unicode.ToLower(c), str[i+2:])
 | 
					 | 
				
			||||||
			return ToCamel(str)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return str
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func ToSnake(str string) string {
 | 
					 | 
				
			||||||
	if len(str) < 1 {
 | 
					 | 
				
			||||||
		return str
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for i, c := range str[1:] {
 | 
					 | 
				
			||||||
		if c == '_' {
 | 
					 | 
				
			||||||
			str = fmt.Sprintf("%s%c%s", str[:i+1], unicode.ToUpper(rune(str[i+2])), str[i+3:])
 | 
					 | 
				
			||||||
			return ToSnake(str)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return str
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										11
									
								
								templates/error.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								templates/error.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					    <head>
 | 
				
			||||||
 | 
					        <title>Error</title>
 | 
				
			||||||
 | 
					    </head>
 | 
				
			||||||
 | 
					    <body>
 | 
				
			||||||
 | 
					        <h1>Oops, an error occurred!</h1>
 | 
				
			||||||
 | 
					        <p1>Error {{.StatusCode}}</p1>
 | 
				
			||||||
 | 
					        <p1>{{.Error}}</p1>
 | 
				
			||||||
 | 
					    </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										33
									
								
								templates/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								templates/index.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					    <title>TS3 Viewer</title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <link rel="stylesheet" href="static/styles.css">
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					        <div class="content">
 | 
				
			||||||
 | 
					    <h2>Online Members</h2>
 | 
				
			||||||
 | 
					    <ul>
 | 
				
			||||||
 | 
					        {{range .Clients}}
 | 
				
			||||||
 | 
					        <li>{{.Nickname}}</li>
 | 
				
			||||||
 | 
					        {{end}}
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					    <h2>{{.Server.Name}}</h2>
 | 
				
			||||||
 | 
					    <!-- <small>{{.Server.Version}}</small> -->
 | 
				
			||||||
 | 
					    {{$clients := .Clients}}
 | 
				
			||||||
 | 
					    {{range .Channels}}
 | 
				
			||||||
 | 
					        <p class="channel">{{.Name}}</p>
 | 
				
			||||||
 | 
					        {{$channelId := .ID}}
 | 
				
			||||||
 | 
					        {{range $clients}}
 | 
				
			||||||
 | 
					            {{if eq $channelId .ChannelID}}
 | 
				
			||||||
 | 
					                <p class="client">{{.Nickname}}</p>
 | 
				
			||||||
 | 
					            {{end}}
 | 
				
			||||||
 | 
					        {{end}}
 | 
				
			||||||
 | 
					    {{end}}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue