mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 03:49:27 +01:00
Rip out REST API and web interface.
It's not really used and I'd rather not have it here unless I'm able to actively maintain it properly and build out the web interface. I might re-add it later but for now I'd rather not have it unless anyone's actively using it.
This commit is contained in:
parent
04d5d2fcc2
commit
f7f049973f
24
README.md
24
README.md
@ -19,7 +19,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). For the purpo
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* UTF-8 nick and channel names with rfc7613
|
* UTF-8 nick and channel names with rfc7613 (PRECIS)
|
||||||
* [yaml](http://yaml.org/) configuration
|
* [yaml](http://yaml.org/) configuration
|
||||||
* native TLS/SSL support
|
* native TLS/SSL support
|
||||||
* server password (`PASS` command)
|
* server password (`PASS` command)
|
||||||
@ -32,7 +32,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). For the purpo
|
|||||||
* banning ips/nets and masks with `KLINE` and `DLINE`
|
* banning ips/nets and masks with `KLINE` and `DLINE`
|
||||||
* [IRCv3 support](http://ircv3.net/software/servers.html)
|
* [IRCv3 support](http://ircv3.net/software/servers.html)
|
||||||
* a heavy focus on developing with [specifications](http://oragono.io/specs.html)
|
* a heavy focus on developing with [specifications](http://oragono.io/specs.html)
|
||||||
* integrated (alpha) REST API and web interface
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -131,27 +130,6 @@ After this, your channel will remember the fact that you're the owner, the topic
|
|||||||
Make sure to setup [SASL](https://freenode.net/kb/answer/sasl) in your client to automatically login to your account when you next join the server.
|
Make sure to setup [SASL](https://freenode.net/kb/answer/sasl) in your client to automatically login to your account when you next join the server.
|
||||||
|
|
||||||
|
|
||||||
<!--# Web interface
|
|
||||||
|
|
||||||
Oragono also includes a web interface, which works with the REST API to provide a way to manage user accounts and bans.
|
|
||||||
|
|
||||||
This interface is an early alpha, is in no way secure and will not be in a final release for a while. Requires the alpha REST API to be enabled (check your server config to enable that if you really want to).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```sh
|
|
||||||
go build oragono-web.go
|
|
||||||
cp oragono-web.yaml web.yaml
|
|
||||||
vim web.yaml # modify the config file to your liking
|
|
||||||
oragono-web mkcerts
|
|
||||||
```
|
|
||||||
|
|
||||||
## Running
|
|
||||||
|
|
||||||
```sh
|
|
||||||
oragono-web run
|
|
||||||
```-->
|
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
* Jeremy Latt, creator of Ergonomadic, <https://github.com/jlatt>
|
* Jeremy Latt, creator of Ergonomadic, <https://github.com/jlatt>
|
||||||
|
15
docs/INFO.md
15
docs/INFO.md
@ -72,21 +72,6 @@ This will make the server rehash its configuration files and TLS certificates, a
|
|||||||
useful if you're automatically updating your TLS certs!
|
useful if you're automatically updating your TLS certs!
|
||||||
|
|
||||||
|
|
||||||
## REST API
|
|
||||||
|
|
||||||
Oragono contains a draft, very early REST API implementation. My plans for this is to allow
|
|
||||||
external web interfaces or other automated programs to monitor what's going on with the
|
|
||||||
server, apply/remove bans, and to essentially allow administration of the server without
|
|
||||||
being connected to it and opered-up. This sort of API mimics InspIRCd and Anope, which
|
|
||||||
contain similar APIs.
|
|
||||||
|
|
||||||
I'm not sure exactly how it's going to continue to be developed, and I'm sure there'll be
|
|
||||||
lots of changes around appropriately restricting access to the API, which is why it's
|
|
||||||
disabled for now and not exposed in our Docker builds. As well, while it's very unstable,
|
|
||||||
the REST API doesn't count for our SemVer versioning. When this feature is more developed
|
|
||||||
and I'm happy with where it's at, I'll provide proper support and documentation for the API.
|
|
||||||
|
|
||||||
|
|
||||||
## Rejected Features
|
## Rejected Features
|
||||||
|
|
||||||
'Rejected' sounds harsh, but basically these are features I've decided I'm not gonna
|
'Rejected' sounds harsh, but basically these are features I've decided I'm not gonna
|
||||||
|
@ -108,12 +108,6 @@ func (conf *OperConfig) PasswordBytes() []byte {
|
|||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// RestAPIConfig controls the integrated REST API.
|
|
||||||
type RestAPIConfig struct {
|
|
||||||
Enabled bool
|
|
||||||
Listen string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnectionLimitsConfig controls the automated connection limits.
|
// ConnectionLimitsConfig controls the automated connection limits.
|
||||||
type ConnectionLimitsConfig struct {
|
type ConnectionLimitsConfig struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
@ -198,8 +192,7 @@ type Config struct {
|
|||||||
Listen []string
|
Listen []string
|
||||||
TLSListeners map[string]*TLSListenConfig `yaml:"tls-listeners"`
|
TLSListeners map[string]*TLSListenConfig `yaml:"tls-listeners"`
|
||||||
STS STSConfig
|
STS STSConfig
|
||||||
RestAPI RestAPIConfig `yaml:"rest-api"`
|
CheckIdent bool `yaml:"check-ident"`
|
||||||
CheckIdent bool `yaml:"check-ident"`
|
|
||||||
MOTD string
|
MOTD string
|
||||||
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
ProxyAllowedFrom []string `yaml:"proxy-allowed-from"`
|
||||||
MaxSendQString string `yaml:"max-sendq"`
|
MaxSendQString string `yaml:"max-sendq"`
|
||||||
|
200
irc/rest_api.go
200
irc/rest_api.go
@ -1,200 +0,0 @@
|
|||||||
// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
|
|
||||||
// released under the MIT license
|
|
||||||
|
|
||||||
// viewing and modifying accounts, registered channels, dlines, rehashing, etc
|
|
||||||
|
|
||||||
package irc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/tidwall/buntdb"
|
|
||||||
)
|
|
||||||
|
|
||||||
const restErr = "{\"error\":\"An unknown error occurred\"}"
|
|
||||||
|
|
||||||
// ircServer is used to keep a link to the current running server since this is the best
|
|
||||||
// way to do it, given how HTTP handlers dispatch and work.
|
|
||||||
var ircServer *Server
|
|
||||||
|
|
||||||
type restInfoResp struct {
|
|
||||||
ServerName string `json:"server-name"`
|
|
||||||
NetworkName string `json:"network-name"`
|
|
||||||
|
|
||||||
Version string `json:"version"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type restStatusResp struct {
|
|
||||||
Clients int `json:"clients"`
|
|
||||||
Opers int `json:"opers"`
|
|
||||||
Channels int `json:"channels"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type restXLinesResp struct {
|
|
||||||
DLines map[string]IPBanInfo `json:"dlines"`
|
|
||||||
KLines map[string]IPBanInfo `json:"klines"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
ServerName: ircServer.name,
|
|
||||||
NetworkName: ircServer.networkName,
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(rs)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(w, restErr)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(w, string(b))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func restStatus(w http.ResponseWriter, r *http.Request) {
|
|
||||||
rs := restStatusResp{
|
|
||||||
Clients: ircServer.clients.Count(),
|
|
||||||
Opers: len(ircServer.operators),
|
|
||||||
Channels: ircServer.channels.Len(),
|
|
||||||
}
|
|
||||||
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{
|
|
||||||
DLines: ircServer.dlines.AllBans(),
|
|
||||||
KLines: ircServer.klines.AllBans(),
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(rs)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(w, restErr)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(w, string(b))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func restGetAccounts(w http.ResponseWriter, r *http.Request) {
|
|
||||||
rs := restAccountsResp{
|
|
||||||
Verified: make(map[string]restAcct),
|
|
||||||
}
|
|
||||||
|
|
||||||
// get accounts
|
|
||||||
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
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func restRehash(w http.ResponseWriter, r *http.Request) {
|
|
||||||
err := ircServer.rehash()
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func StartRestAPI(s *Server, listenAddr string) (*http.Server, error) {
|
|
||||||
// so handlers can ref it later
|
|
||||||
ircServer = s
|
|
||||||
|
|
||||||
// start router
|
|
||||||
r := mux.NewRouter()
|
|
||||||
|
|
||||||
// GET methods
|
|
||||||
rg := r.Methods("GET").Subrouter()
|
|
||||||
rg.HandleFunc("/info", restInfo)
|
|
||||||
rg.HandleFunc("/status", restStatus)
|
|
||||||
rg.HandleFunc("/xlines", restGetXLines)
|
|
||||||
rg.HandleFunc("/accounts", restGetAccounts)
|
|
||||||
|
|
||||||
// PUT methods
|
|
||||||
rp := r.Methods("POST").Subrouter()
|
|
||||||
rp.HandleFunc("/rehash", restRehash)
|
|
||||||
|
|
||||||
// start api
|
|
||||||
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
|
|
||||||
}
|
|
@ -7,14 +7,12 @@ package irc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -39,14 +37,6 @@ var (
|
|||||||
couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
|
couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// when shutting down the REST server, wait this long
|
|
||||||
// before killing active connections. TODO: this might not be
|
|
||||||
// necessary at all? but it seems prudent to avoid potential resource
|
|
||||||
// leaks
|
|
||||||
httpShutdownTimeout = time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
// Limits holds the maximum limits for various things such as topic lengths.
|
// Limits holds the maximum limits for various things such as topic lengths.
|
||||||
type Limits struct {
|
type Limits struct {
|
||||||
AwayLen int
|
AwayLen int
|
||||||
@ -116,8 +106,6 @@ type Server struct {
|
|||||||
registeredChannelsMutex sync.RWMutex
|
registeredChannelsMutex sync.RWMutex
|
||||||
rehashMutex sync.Mutex
|
rehashMutex sync.Mutex
|
||||||
rehashSignal chan os.Signal
|
rehashSignal chan os.Signal
|
||||||
restAPI RestAPIConfig
|
|
||||||
restAPIServer *http.Server
|
|
||||||
proxyAllowedFrom []string
|
proxyAllowedFrom []string
|
||||||
signals chan os.Signal
|
signals chan os.Signal
|
||||||
snomasks *SnoManager
|
snomasks *SnoManager
|
||||||
@ -1445,7 +1433,6 @@ func (server *Server) applyConfig(config *Config, initial bool) error {
|
|||||||
|
|
||||||
// we are now open for business
|
// we are now open for business
|
||||||
server.setupListeners(config)
|
server.setupListeners(config)
|
||||||
server.setupRestAPI(config)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1583,32 +1570,6 @@ func (server *Server) setupListeners(config *Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) setupRestAPI(config *Config) {
|
|
||||||
restAPIEnabled := config.Server.RestAPI.Enabled
|
|
||||||
restAPIStarted := server.restAPIServer != nil
|
|
||||||
restAPIListenAddrChanged := server.restAPI.Listen != config.Server.RestAPI.Listen
|
|
||||||
|
|
||||||
// stop an existing REST server if it's been disabled or the addr changed
|
|
||||||
if restAPIStarted && (!restAPIEnabled || restAPIListenAddrChanged) {
|
|
||||||
ctx, _ := context.WithTimeout(context.Background(), httpShutdownTimeout)
|
|
||||||
server.restAPIServer.Shutdown(ctx)
|
|
||||||
server.restAPIServer.Close()
|
|
||||||
server.logger.Info("rehash", "server", fmt.Sprintf("%s rest API stopped on %s.", server.name, server.restAPI.Listen))
|
|
||||||
server.restAPIServer = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// start a new one if it's enabled or the addr changed
|
|
||||||
if restAPIEnabled && (!restAPIStarted || restAPIListenAddrChanged) {
|
|
||||||
server.restAPIServer, _ = StartRestAPI(server, config.Server.RestAPI.Listen)
|
|
||||||
server.logger.Info(
|
|
||||||
"rehash", "server",
|
|
||||||
fmt.Sprintf("%s rest API started on %s.", server.name, config.Server.RestAPI.Listen))
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the config information
|
|
||||||
server.restAPI = config.Server.RestAPI
|
|
||||||
}
|
|
||||||
|
|
||||||
func (server *Server) GetDefaultChannelModes() Modes {
|
func (server *Server) GetDefaultChannelModes() Modes {
|
||||||
server.configurableStateMutex.RLock()
|
server.configurableStateMutex.RLock()
|
||||||
defer server.configurableStateMutex.RUnlock()
|
defer server.configurableStateMutex.RUnlock()
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
# oragono web interface config
|
|
||||||
|
|
||||||
# hostname of the web interface
|
|
||||||
hostname: localhost
|
|
||||||
|
|
||||||
# address to listen on
|
|
||||||
listen: "localhost:8090"
|
|
||||||
|
|
||||||
# tls listeners
|
|
||||||
tls-listeners:
|
|
||||||
# listener on ":6697"
|
|
||||||
":8090":
|
|
||||||
key: web-tls.key
|
|
||||||
cert: web-tls.crt
|
|
||||||
|
|
||||||
# log level, one of error, warn, info, debug
|
|
||||||
log: debug
|
|
@ -43,14 +43,6 @@ server:
|
|||||||
# should clients include this STS policy when they ship their inbuilt preload lists?
|
# should clients include this STS policy when they ship their inbuilt preload lists?
|
||||||
preload: false
|
preload: false
|
||||||
|
|
||||||
# rest management API, for use with web interface
|
|
||||||
rest-api:
|
|
||||||
# whether the API is enabled or not
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# rest API listening port
|
|
||||||
listen: "localhost:8090"
|
|
||||||
|
|
||||||
# use ident protocol to get usernames
|
# use ident protocol to get usernames
|
||||||
check-ident: true
|
check-ident: true
|
||||||
|
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
// Copyright (c) 2012-2014 Jeremy Latt
|
|
||||||
// Copyright (c) 2014-2015 Edmund Huber
|
|
||||||
// Copyright (c) 2016 Daniel Oaks <daniel@danieloaks.net>
|
|
||||||
// released under the MIT license
|
|
||||||
|
|
||||||
package web
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TLSListenConfig defines configuration options for listening on TLS
|
|
||||||
type TLSListenConfig struct {
|
|
||||||
Cert string
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Certificate returns the TLS certificate assicated with this TLSListenConfig
|
|
||||||
func (conf *TLSListenConfig) Config() (*tls.Config, error) {
|
|
||||||
cert, err := tls.LoadX509KeyPair(conf.Cert, conf.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("tls cert+key: invalid pair")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &tls.Config{
|
|
||||||
Certificates: []tls.Certificate{cert},
|
|
||||||
}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Host string
|
|
||||||
Listen string
|
|
||||||
TLSListenersConf map[string]*TLSListenConfig `yaml:"tls-listeners"`
|
|
||||||
Log string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (conf *Config) TLSListeners() map[string]*tls.Config {
|
|
||||||
tlsListeners := make(map[string]*tls.Config)
|
|
||||||
for s, tlsListenersConf := range conf.TLSListenersConf {
|
|
||||||
config, err := tlsListenersConf.Config()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
tlsListeners[name] = config
|
|
||||||
}
|
|
||||||
return tlsListeners
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadConfig(filename string) (config *Config, err error) {
|
|
||||||
data, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = yaml.Unmarshal(data, &config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Listen == "" {
|
|
||||||
return nil, errors.New("Listening address missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
// Copyright (c) 2012-2014 Jeremy Latt
|
|
||||||
// Copyright (c) 2014-2015 Edmund Huber
|
|
||||||
// Copyright (c) 2016 Daniel Oaks <daniel@danieloaks.net>
|
|
||||||
// released under the MIT license
|
|
||||||
|
|
||||||
package web
|
|
||||||
|
|
||||||
// Server is the webserver
|
|
||||||
type Server struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServer returns a new Oragono server.
|
|
||||||
func NewServer(config *Config) *Server {
|
|
||||||
server := &Server{}
|
|
||||||
|
|
||||||
return server
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Server) Run() {
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user