pls pull #1
10 changed files with 250 additions and 19 deletions
56
README.md
56
README.md
|
@ -1 +1,55 @@
|
||||||
# go-tsviewer
|
# go-tsviewer **[WIP]**
|
||||||
|
## **WARNING** This API is not usable ATM
|
||||||
|
|
||||||
|
A REST API made for TS3 Viewer.
|
||||||
|
|
||||||
|
# Features
|
||||||
|
## Config
|
||||||
|
The config file is generated automatically on first startup.
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ip": "127.0.0.1", // Server IP
|
||||||
|
"port": 10011, // Dataquery Port
|
||||||
|
"user": {
|
||||||
|
"name": "serveradmin", // Username
|
||||||
|
"password": "" // Password
|
||||||
|
},
|
||||||
|
"server": {
|
||||||
|
"port": 9987 // Port of the target server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## URL-Parameter
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---------- | -------- | ------------------------ |
|
||||||
|
| `pretty` | `bool` | pretty-prints JSON |
|
||||||
|
| `envelope` | `bool` | wraps JSON in data array |
|
||||||
|
## Channels
|
||||||
|
- **`GET`** `/v1/channels/:id`
|
||||||
|
- **`GET`** `/v1/channels`
|
||||||
|
```json
|
||||||
|
A channel object in JSON
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"databaseId": 1,
|
||||||
|
"nickname": "serveradmin from 127.0.0.1:58359",
|
||||||
|
"type": 1,
|
||||||
|
"away": false,
|
||||||
|
"awayMessage": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Clients
|
||||||
|
- **`GET`** `/v1/clients/:id`
|
||||||
|
- **`GET`** `/v1/clients/`
|
||||||
|
```json
|
||||||
|
A client object in JSON
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"subchannels": [
|
||||||
|
... (contains all subchannel)
|
||||||
|
],
|
||||||
|
"name": "main1",
|
||||||
|
"totalClients": 0,
|
||||||
|
"neededSubscribePower": 0
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
|
@ -11,6 +11,7 @@ type Config struct {
|
||||||
IP string `json:"ip"`
|
IP string `json:"ip"`
|
||||||
Port uint16 `json:"port"`
|
Port uint16 `json:"port"`
|
||||||
User User `json:"user"`
|
User User `json:"user"`
|
||||||
|
Server Server `json:"server"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
@ -18,6 +19,10 @@ type User struct {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Port uint16 `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
const FileName = "config.json"
|
const FileName = "config.json"
|
||||||
|
|
||||||
func New() (*Config, error) {
|
func New() (*Config, error) {
|
||||||
|
@ -25,9 +30,7 @@ func New() (*Config, error) {
|
||||||
|
|
||||||
configFile, err := os.Open(FileName)
|
configFile, err := os.Open(FileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Made it")
|
|
||||||
if err := config.createFile(); err != nil {
|
if err := config.createFile(); err != nil {
|
||||||
log.Println("WUT?")
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,5 +62,8 @@ func defaults() Config {
|
||||||
Name: "serveradmin",
|
Name: "serveradmin",
|
||||||
Password: "",
|
Password: "",
|
||||||
},
|
},
|
||||||
|
Server: Server{
|
||||||
|
Port: 9987,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ type Service interface {
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Subchannels []Channel `json:"subchannel"`
|
Subchannels []Channel `json:"subchannels,omitempty"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
TotalClients int `json:"totalClients"`
|
TotalClients int `json:"totalClients"`
|
||||||
NeededSubscribePower int `json:"neededSubscribePower"`
|
NeededSubscribePower int `json:"neededSubscribePower"`
|
||||||
|
|
15
features/client/client.go
Normal file
15
features/client/client.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Client(id int) (*Client, error)
|
||||||
|
Clients() ([]*Client, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
DatabaseID int `json:"databaseId"`
|
||||||
|
Nickname string `json:"nickname"`
|
||||||
|
Type int `json:"type"`
|
||||||
|
Away bool `json:"away"`
|
||||||
|
AwayMessage string `json:"awayMessage"`
|
||||||
|
}
|
40
features/client/handler.go
Normal file
40
features/client/handler.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.cliffbreak.de/haveachin/go-tsviewer/response"
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ClientHandler(s Service) http.HandlerFunc {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
response.Handler(w, response.HandlerFunc(func() (int, error) {
|
||||||
|
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusBadRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := s.Client(int(id))
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusNotFound, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.New(c, r).Send(w, http.StatusOK)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClientsHandler(s Service) http.HandlerFunc {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
response.Handler(w, response.HandlerFunc(func() (int, error) {
|
||||||
|
cc, err := s.Clients()
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusBadRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.New(cc, r).Send(w, http.StatusOK)
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
14
features/client/routes.go
Normal file
14
features/client/routes.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Routes(s Service) *chi.Mux {
|
||||||
|
router := chi.NewRouter()
|
||||||
|
|
||||||
|
router.Get("/{id}", ClientHandler(s))
|
||||||
|
router.Get("/", ClientsHandler(s))
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
4
main.go
4
main.go
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"git.cliffbreak.de/haveachin/go-tsviewer/config"
|
"git.cliffbreak.de/haveachin/go-tsviewer/config"
|
||||||
"git.cliffbreak.de/haveachin/go-tsviewer/features/channel"
|
"git.cliffbreak.de/haveachin/go-tsviewer/features/channel"
|
||||||
|
"git.cliffbreak.de/haveachin/go-tsviewer/features/client"
|
||||||
"git.cliffbreak.de/haveachin/go-tsviewer/service"
|
"git.cliffbreak.de/haveachin/go-tsviewer/service"
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
"github.com/go-chi/chi/middleware"
|
"github.com/go-chi/chi/middleware"
|
||||||
|
@ -24,6 +25,7 @@ func Routes(s service.Service) *chi.Mux {
|
||||||
|
|
||||||
router.Route("/v1", func(r chi.Router) {
|
router.Route("/v1", func(r chi.Router) {
|
||||||
r.Mount("/channels", channel.Routes(s))
|
r.Mount("/channels", channel.Routes(s))
|
||||||
|
r.Mount("/clients", client.Routes(s))
|
||||||
})
|
})
|
||||||
|
|
||||||
return router
|
return router
|
||||||
|
@ -39,7 +41,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer service.Client.Close()
|
defer service.TSClient.Close()
|
||||||
|
|
||||||
router := Routes(*service)
|
router := Routes(*service)
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,64 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"errors"
|
||||||
|
|
||||||
"git.cliffbreak.de/haveachin/go-tsviewer/features/channel"
|
"git.cliffbreak.de/haveachin/go-tsviewer/features/channel"
|
||||||
|
"github.com/multiplay/go-ts3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s Service) Channel(id int) (*channel.Channel, error) {
|
func (s Service) Channel(id int) (*channel.Channel, error) {
|
||||||
return nil, nil
|
channels, err := s.TSClient.Server.ChannelList()
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) Channels() ([]*channel.Channel, error) {
|
|
||||||
cc, err := s.Client.Server.ClientList()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cc {
|
var c *channel.Channel
|
||||||
log.Println(*c)
|
|
||||||
|
for _, channel := range channels {
|
||||||
|
if channel.ID == id {
|
||||||
|
c = convertChannel(channel)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
if c == nil {
|
||||||
|
return nil, errors.New("channel does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) Channels() ([]*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.ParentID == 0 {
|
||||||
|
cc = append(cc, convertChannel(channel))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cc {
|
||||||
|
if c.ID == channel.ParentID {
|
||||||
|
c.Subchannels = append(c.Subchannels, *convertChannel(channel))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertChannel(c *ts3.Channel) *channel.Channel {
|
||||||
|
return &channel.Channel{
|
||||||
|
ID: c.ID,
|
||||||
|
Subchannels: []channel.Channel{},
|
||||||
|
Name: c.ChannelName,
|
||||||
|
TotalClients: c.TotalClients,
|
||||||
|
NeededSubscribePower: c.NeededSubscribePower,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
56
service/client.go
Normal file
56
service/client.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"git.cliffbreak.de/haveachin/go-tsviewer/features/client"
|
||||||
|
"github.com/multiplay/go-ts3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) Client(id int) (*client.Client, error) {
|
||||||
|
clients, err := s.TSClient.Server.ClientList()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var c *client.Client
|
||||||
|
|
||||||
|
for _, client := range clients {
|
||||||
|
if client.ID == id {
|
||||||
|
c = convertClient(client)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == nil {
|
||||||
|
return nil, errors.New("client does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) Clients() ([]*client.Client, error) {
|
||||||
|
clients, err := s.TSClient.Server.ClientList()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var cc []*client.Client
|
||||||
|
|
||||||
|
for _, client := range clients {
|
||||||
|
cc = append(cc, convertClient(client))
|
||||||
|
}
|
||||||
|
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertClient(c *ts3.OnlineClient) *client.Client {
|
||||||
|
return &client.Client{
|
||||||
|
ID: c.ID,
|
||||||
|
DatabaseID: c.DatabaseID,
|
||||||
|
Nickname: c.Nickname,
|
||||||
|
Type: c.Type,
|
||||||
|
Away: c.Away,
|
||||||
|
AwayMessage: c.AwayMessage,
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
Client *ts3.Client
|
TSClient *ts3.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config config.Config) (*Service, error) {
|
func New(config config.Config) (*Service, error) {
|
||||||
|
@ -27,7 +27,11 @@ func New(config config.Config) (*Service, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := client.UsePort(int(config.Server.Port)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &Service{
|
return &Service{
|
||||||
Client: client,
|
TSClient: client,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue