// Copyright 2024 Matthew Rich . All rights reserved. package transport import ( "errors" _ "fmt" "net/url" "net/http" _ "strings" _ "path/filepath" "io" "io/fs" _ "os" "context" ) var ( ErrTransportResourceAbsent error = errors.New("Transport resource is absent") ) type Handler interface { URI() *url.URL ContentType() string SetGzip(bool) DetectGzip() Gzip() bool Signature() string Stat() (fs.FileInfo, error) } type HandlerReader interface { Reader() io.ReadCloser } type HandlerWriter interface { Writer() io.WriteCloser } type Reader struct { uri *url.URL handle Handler stream io.ReadCloser exists func() bool } func NewReader(u *url.URL) (reader *Reader, e error) { return NewReaderWithContext(u, context.Background()) } func NewReaderWithContext(u *url.URL, ctx context.Context) (reader *Reader, e error) { reader = &Reader{ uri: u } switch u.Scheme { case "http", "https": reader.handle, e = NewHTTPReader(u, ctx) case "file": fallthrough default: reader.handle, e = NewFileReader(u) reader.exists = func() bool { return FileExists(u) } } reader.SetStream(reader.handle.(HandlerReader).Reader()) return } func NewReaderURI(uri string) (reader *Reader, e error) { var u *url.URL if u, e = url.Parse(uri); e == nil { return NewReader(u) } return } type Writer struct { uri *url.URL handle Handler stream io.WriteCloser exists func() bool } func NewWriter(u *url.URL) (writer *Writer, e error) { return NewWriterWithContext(u, context.Background()) } func NewWriterWithContext(u *url.URL, ctx context.Context) (writer *Writer, e error) { writer = &Writer{ uri: u } switch u.Scheme { case "http", "https": writer.handle, e = NewHTTPWriter(u, ctx) case "file": fallthrough default: writer.handle, e = NewFileWriter(u) writer.exists = func() bool { return FileExists(u) } } writer.SetStream(writer.handle.(HandlerWriter).Writer()) return writer, e } func NewWriterURI(uri string) (writer *Writer, e error) { var u *url.URL if u, e = url.Parse(uri); e == nil { return NewWriter(u) } return } func ExistsURI(uri string) bool { if u, e := url.Parse(uri); e == nil { return Exists(u) } return false } func Exists(u *url.URL) bool { switch u.Scheme { case "http", "https": return HTTPExists(u) case "file": fallthrough default: return FileExists(u) } } func (r *Reader) Exists() bool { return r.exists() } func (r *Reader) Read(b []byte) (int, error) { return r.stream.Read(b) } func (r *Reader) Close() error { return r.stream.Close() } func (r *Reader) ContentType() string { return r.handle.ContentType() } func (r *Reader) SetGzip(value bool) { r.handle.SetGzip(value) } func (r *Reader) DetectGzip() { r.handle.DetectGzip() } func (r *Reader) Gzip() bool { return r.handle.Gzip() } func (r *Reader) Stat() (info fs.FileInfo, err error) { return r.handle.Stat() } func (r *Reader) Signature() string { return r.handle.Signature() } func (r *Reader) SetStream(s io.ReadCloser) { r.stream = s } func (r *Reader) AddHeader(name string, value string) { r.handle.(*HTTPReader).GetRequest().Header.Add(name, value) } func (r *Reader) Status() string { if httpReader, ok := r.handle.(*HTTPReader); ok { return httpReader.GetResponse().Status } panic("Unable to get HTTP status from reader") } func (r *Reader) StatusCode() int { if httpReader, ok := r.handle.(*HTTPReader); ok { return httpReader.GetResponse().StatusCode } panic("Unable to get HTTP status code from reader") } func (r *Reader) Response() *http.Response { return r.handle.(*HTTPReader).GetResponse() } func (w *Writer) Exists() bool { return w.exists() } func (w *Writer) Write(b []byte) (int, error) { return w.stream.Write(b) } func (w *Writer) ReadFrom(r io.Reader) (n int64, e error) { if v, ok := w.stream.(io.ReaderFrom); ok { return v.ReadFrom(r) } else { panic("io.ReaderFrom interface not supported by writer") } } func (w *Writer) Close() error { return w.stream.Close() } func (w *Writer) ContentType() string { return w.handle.ContentType() } func (w *Writer) SetGzip(value bool) { w.handle.SetGzip(value) } func (w *Writer) DetectGzip() { w.handle.DetectGzip() } func (w *Writer) Gzip() bool { return w.handle.Gzip() } func (w *Writer) Signature() string { return w.handle.Signature() } func (w *Writer) SetStream(s io.WriteCloser) { w.stream = s } func (w *Writer) AddHeader(name string, value string) { w.handle.(*HTTPWriter).PostRequest().Header.Add(name, value) } func (w *Writer) Status() string { return w.handle.(*HTTPWriter).PostResponse().Status } func (w *Writer) StatusCode() int { return w.handle.(*HTTPWriter).PostResponse().StatusCode } func (w *Writer) Response() *http.Response { return w.handle.(*HTTPWriter).PostResponse() }