101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
package service
|
|
|
|
import "log"
|
|
import "net"
|
|
import "sync"
|
|
import "bufio"
|
|
import "errors"
|
|
import "net/http"
|
|
import "hnakra/protocol"
|
|
|
|
// HTTP is an https:// mount.
|
|
type HTTP struct {
|
|
Mount
|
|
|
|
// AllowInsecure allows this mount to respond to plain-text HTTP
|
|
// requests. You can get a TLS cert for free nowadays so there are very
|
|
// few cases where you'd want this on.
|
|
AllowInsecure bool
|
|
|
|
// Handler specifies the handler to invoke. If it is nil,
|
|
// http.DefaultServeMux is used.
|
|
Handler http.Handler
|
|
|
|
conn net.Conn
|
|
connLock sync.Mutex
|
|
connReadWriter *bufio.ReadWriter
|
|
requests requestManager
|
|
}
|
|
|
|
// Close closes the mount abruptly, interrupting any active connections.
|
|
func (mount *HTTP) Close () error {
|
|
mount.connLock.Lock()
|
|
defer mount.connLock.Unlock()
|
|
return mount.conn.Close()
|
|
}
|
|
|
|
// Shutdown gracefully shuts down the service without interrupting any active
|
|
// connections.
|
|
func (mount *HTTP) Shutdown () error {
|
|
// TODO
|
|
return mount.Close()
|
|
}
|
|
|
|
// Run connects to the router, and blocks while fulfilling requests. This method
|
|
// will only return when the connection to the router has been closed.
|
|
func (mount *HTTP) Run () (err error) {
|
|
if mount.AllowInsecure {
|
|
mount.conn, err = mount.connect("http")
|
|
} else {
|
|
mount.conn, err = mount.connect("https")
|
|
}
|
|
if err != nil { return }
|
|
|
|
mount.connReadWriter = bufio.NewReadWriter (
|
|
bufio.NewReader(mount.conn),
|
|
bufio.NewWriter(mount.conn))
|
|
mount.requests.init()
|
|
|
|
for {
|
|
message, err := protocol.ReadMessage(mount.connReadWriter)
|
|
if err != nil { return err }
|
|
|
|
switch message.(type) {
|
|
case protocol.MessageHTTPRequest:
|
|
request := message.(protocol.MessageHTTPRequest)
|
|
mount.requests.add(request.ID)
|
|
go mount.handle(request)
|
|
|
|
case protocol.MessageHTTPBodySegment:
|
|
segment := message.(protocol.MessageHTTPBodySegment)
|
|
mount.requests.feed(segment.ID, segment.Data)
|
|
|
|
case protocol.MessageHTTPBodyEnd:
|
|
end := message.(protocol.MessageHTTPBodyEnd)
|
|
mount.requests.end(end.ID)
|
|
|
|
case protocol.MessageStatus:
|
|
status := message.(protocol.MessageStatus)
|
|
log.Println("router says:", status.Status)
|
|
|
|
default:
|
|
mount.Close()
|
|
return errors.New("router sent unknown type code")
|
|
}
|
|
}
|
|
}
|
|
|
|
// NewHTTP creates a very basic https:// mount with the specified name and
|
|
// description.
|
|
func NewHTTP (name, description string) HTTP {
|
|
return HTTP { Mount: M(name, description) }
|
|
}
|
|
|
|
func (mount *HTTP) send (message protocol.Message) (err error) {
|
|
mount.connLock.Lock()
|
|
defer mount.connLock.Unlock()
|
|
err = message.Send(mount.connReadWriter)
|
|
if err != nil { return }
|
|
return mount.connReadWriter.Flush()
|
|
}
|