[🚀] downloader
This commit is contained in:
172
pkg/downloader/controller/controller.go
Normal file
172
pkg/downloader/controller/controller.go
Normal file
@ -0,0 +1,172 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"golang.org/x/net/proxy"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Controller interface {
|
||||
Touch(name string, size int64) (file *os.File, err error)
|
||||
Open(name string) (file *os.File, err error)
|
||||
Write(name string, offset int64, buf []byte) (int, error)
|
||||
Close(name string) error
|
||||
ContextDialer() (proxy.Dialer, error)
|
||||
ContextCookie() http.CookieJar
|
||||
ContextTimeout() time.Duration
|
||||
ContextProxy() func(*http.Request) (*url.URL, error)
|
||||
}
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
type option struct {
|
||||
CookieJar http.CookieJar
|
||||
Timeout time.Duration
|
||||
Dialer proxy.Dialer
|
||||
Proxy func(*http.Request) (*url.URL, error)
|
||||
}
|
||||
|
||||
func WithCookie(cookieJar http.CookieJar) Option {
|
||||
return func(opt *option) {
|
||||
opt.CookieJar = cookieJar
|
||||
}
|
||||
}
|
||||
|
||||
func WithTimeout(timeout time.Duration) Option {
|
||||
return func(opt *option) {
|
||||
opt.Timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
func WithDialer(dialer proxy.Dialer) Option {
|
||||
return func(opt *option) {
|
||||
opt.Dialer = dialer
|
||||
}
|
||||
}
|
||||
|
||||
func WithProxy(fn func(*http.Request) (*url.URL, error)) Option {
|
||||
return func(opt *option) {
|
||||
opt.Proxy = fn
|
||||
}
|
||||
}
|
||||
|
||||
type DefaultController struct {
|
||||
*option
|
||||
Files map[string]*os.File
|
||||
}
|
||||
|
||||
func NewController(options ...Option) *DefaultController {
|
||||
opt := new(option)
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
if opt.Timeout == 0 {
|
||||
opt.Timeout = time.Second * 30
|
||||
}
|
||||
if opt.Dialer == nil {
|
||||
opt.Dialer = proxy.FromEnvironment()
|
||||
}
|
||||
return &DefaultController{
|
||||
Files: make(map[string]*os.File),
|
||||
option: opt,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DefaultController) Touch(name string, size int64) (file *os.File, err error) {
|
||||
file, err = os.Create(name)
|
||||
if size > 0 {
|
||||
err = os.Truncate(name, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
c.Files[name] = file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *DefaultController) Open(name string) (file *os.File, err error) {
|
||||
file, err = os.OpenFile(name, os.O_RDWR, os.ModePerm)
|
||||
if err == nil {
|
||||
c.Files[name] = file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *DefaultController) Write(name string, offset int64, buf []byte) (int, error) {
|
||||
return c.Files[name].WriteAt(buf, offset)
|
||||
}
|
||||
|
||||
func (c *DefaultController) Close(name string) error {
|
||||
err := c.Files[name].Close()
|
||||
delete(c.Files, name)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DefaultController) ContextDialer() (proxy.Dialer, error) {
|
||||
return &DialerWarp{dialer: c.Dialer}, nil
|
||||
}
|
||||
|
||||
func (c *DefaultController) ContextCookie() http.CookieJar {
|
||||
return c.CookieJar
|
||||
}
|
||||
|
||||
func (c *DefaultController) ContextTimeout() time.Duration {
|
||||
return c.Timeout
|
||||
}
|
||||
|
||||
func (c *DefaultController) ContextProxy() func(*http.Request) (*url.URL, error) {
|
||||
return c.Proxy
|
||||
}
|
||||
|
||||
type DialerWarp struct {
|
||||
dialer proxy.Dialer
|
||||
}
|
||||
|
||||
type ConnWarp struct {
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func (c *ConnWarp) Read(b []byte) (n int, err error) {
|
||||
return c.conn.Read(b)
|
||||
}
|
||||
|
||||
func (c *ConnWarp) Write(b []byte) (n int, err error) {
|
||||
return c.conn.Write(b)
|
||||
}
|
||||
|
||||
func (c *ConnWarp) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *ConnWarp) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *ConnWarp) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (c *ConnWarp) SetDeadline(t time.Time) error {
|
||||
return c.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *ConnWarp) SetReadDeadline(t time.Time) error {
|
||||
return c.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *ConnWarp) SetWriteDeadline(t time.Time) error {
|
||||
return c.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (d *DialerWarp) Dial(network, addr string) (c net.Conn, err error) {
|
||||
conn, err := d.dialer.Dial(network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ConnWarp{conn: conn}, nil
|
||||
}
|
Reference in New Issue
Block a user