3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-11 06:29:29 +01:00
ergo/irc/rest_api.go

201 lines
4.3 KiB
Go
Raw Normal View History

2017-03-27 14:15:02 +02:00
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
2016-11-06 02:05:29 +01:00
// released under the MIT license
// viewing and modifying accounts, registered channels, dlines, rehashing, etc
package irc
import (
"encoding/json"
"net/http"
"strconv"
"time"
2016-11-06 02:05:29 +01:00
"fmt"
"github.com/gorilla/mux"
"github.com/tidwall/buntdb"
2016-11-06 02:05:29 +01:00
)
const restErr = "{\"error\":\"An unknown error occurred\"}"
2017-09-28 07:30:53 +02:00
// ircServer is used to keep a link to the current running server since this is the best
2016-11-06 02:05:29 +01:00
// way to do it, given how HTTP handlers dispatch and work.
2017-09-28 07:30:53 +02:00
var ircServer *Server
2016-11-06 02:05:29 +01:00
type restInfoResp struct {
ServerName string `json:"server-name"`
NetworkName string `json:"network-name"`
2016-11-06 02:59:10 +01:00
Version string `json:"version"`
}
2016-11-06 02:05:29 +01:00
type restStatusResp struct {
Clients int `json:"clients"`
Opers int `json:"opers"`
Channels int `json:"channels"`
}
type restXLinesResp struct {
2016-11-06 02:05:29 +01:00
DLines map[string]IPBanInfo `json:"dlines"`
KLines map[string]IPBanInfo `json:"klines"`
2016-11-06 02:05:29 +01:00
}
type restAcct struct {
Name string `json:"name"`
RegisteredAt time.Time `json:"registered-at"`
Clients int `json:"clients"`
}
type restAccountsResp struct {
Verified map[string]restAcct `json:"verified"`
2016-11-06 02:59:10 +01:00
}
type restRehashResp struct {
Successful bool `json:"successful"`
Error string `json:"error"`
Time time.Time `json:"time"`
}
func restInfo(w http.ResponseWriter, r *http.Request) {
rs := restInfoResp{
Version: SemVer,
2017-09-28 07:30:53 +02:00
ServerName: ircServer.name,
NetworkName: ircServer.networkName,
2016-11-06 02:59:10 +01:00
}
b, err := json.Marshal(rs)
if err != nil {
fmt.Fprintln(w, restErr)
} else {
fmt.Fprintln(w, string(b))
}
}
2016-11-06 02:05:29 +01:00
func restStatus(w http.ResponseWriter, r *http.Request) {
rs := restStatusResp{
2017-09-28 07:30:53 +02:00
Clients: ircServer.clients.Count(),
Opers: len(ircServer.operators),
Channels: ircServer.channels.Len(),
2016-11-06 02:05:29 +01:00
}
b, err := json.Marshal(rs)
if err != nil {
fmt.Fprintln(w, restErr)
} else {
fmt.Fprintln(w, string(b))
}
}
func restGetXLines(w http.ResponseWriter, r *http.Request) {
rs := restXLinesResp{
2017-09-28 07:30:53 +02:00
DLines: ircServer.dlines.AllBans(),
KLines: ircServer.klines.AllBans(),
2016-11-06 02:05:29 +01:00
}
b, err := json.Marshal(rs)
if err != nil {
fmt.Fprintln(w, restErr)
} else {
fmt.Fprintln(w, string(b))
}
}
2016-11-06 02:59:10 +01:00
func restGetAccounts(w http.ResponseWriter, r *http.Request) {
rs := restAccountsResp{
Verified: make(map[string]restAcct),
}
// get accounts
2017-09-28 07:30:53 +02:00
err := ircServer.store.View(func(tx *buntdb.Tx) error {
tx.AscendKeys("account.exists *", func(key, value string) bool {
key = key[len("account.exists "):]
_, err := tx.Get(fmt.Sprintf(keyAccountVerified, key))
verified := err == nil
fmt.Println(fmt.Sprintf(keyAccountVerified, key))
// get other details
name, _ := tx.Get(fmt.Sprintf(keyAccountName, key))
regTimeStr, _ := tx.Get(fmt.Sprintf(keyAccountRegTime, key))
regTimeInt, _ := strconv.ParseInt(regTimeStr, 10, 64)
regTime := time.Unix(regTimeInt, 0)
var clients int
2017-09-28 07:30:53 +02:00
acct := ircServer.accounts[key]
if acct != nil {
clients = len(acct.Clients)
}
if verified {
rs.Verified[key] = restAcct{
Name: name,
RegisteredAt: regTime,
Clients: clients,
}
} else {
//TODO(dan): Add to unverified list
}
return true // true to continue I guess?
})
return nil
})
b, err := json.Marshal(rs)
if err != nil {
fmt.Fprintln(w, restErr)
} else {
fmt.Fprintln(w, string(b))
}
}
2016-11-06 02:59:10 +01:00
func restRehash(w http.ResponseWriter, r *http.Request) {
2017-09-28 07:30:53 +02:00
err := ircServer.rehash()
2016-11-06 02:59:10 +01:00
rs := restRehashResp{
Successful: err == nil,
Time: time.Now(),
}
if err != nil {
rs.Error = err.Error()
}
b, err := json.Marshal(rs)
if err != nil {
fmt.Fprintln(w, restErr)
} else {
fmt.Fprintln(w, string(b))
}
}
2017-09-28 07:30:53 +02:00
func StartRestAPI(s *Server, listenAddr string) (*http.Server, error) {
2016-11-06 02:05:29 +01:00
// so handlers can ref it later
2017-09-28 07:30:53 +02:00
ircServer = s
2016-11-06 02:05:29 +01:00
// start router
r := mux.NewRouter()
2016-11-06 02:59:10 +01:00
// GET methods
rg := r.Methods("GET").Subrouter()
rg.HandleFunc("/info", restInfo)
2016-11-06 02:59:10 +01:00
rg.HandleFunc("/status", restStatus)
rg.HandleFunc("/xlines", restGetXLines)
2016-11-06 02:59:10 +01:00
rg.HandleFunc("/accounts", restGetAccounts)
// PUT methods
rp := r.Methods("POST").Subrouter()
rp.HandleFunc("/rehash", restRehash)
2016-11-06 02:05:29 +01:00
// start api
2017-09-28 07:30:53 +02:00
httpserver := http.Server{
Addr: listenAddr,
Handler: r,
}
go func() {
if err := httpserver.ListenAndServe(); err != nil {
s.logger.Error("listeners", fmt.Sprintf("Rest API listenAndServe error: %s", err))
}
}()
return &httpserver, nil
2016-11-06 02:05:29 +01:00
}