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() }