package main import ( "io" "net/http" "github.com/W-Floyd/qbittorrent-docker-multiplexer/qbittorrent" ) func (c *Config) HandleAll(w http.ResponseWriter, r *http.Request) { // if r.URL.Path == "/api/v2/torrents/info" { // c.HandlerFetchMergeArray(w, r) // } else if slices.Contains([]string{ // "/api/v2/sync/maindata", // "/api/v2/torrents/categories", // }, r.URL.Path) { // c.HandlerFetchMerge(w, r) // } else if r.Form.Has("hash") || r.Form.Has("hashes") { // c.HandlerHashFinder(w, r) // } else { if false { } else { c.HandlerPassthrough(w, r) } } func (c *Config) HandlerPassthrough(w http.ResponseWriter, r *http.Request) { i := qbittorrent.NextRoundRobin() resp, err := i.GetResponse(r) c.MakeResponse(err, resp, w) } // func (c *Config) MakeRequest(r *http.Request, i *uint) (*http.Response, error) { // body, err := io.ReadAll(r.Body) // r.Body = io.NopCloser(bytes.NewBuffer(body)) // proxy, err := qbittorrent.GetProxy(&c.QBittorrent, i) // if err != nil { // return nil, err // } // req, err := http.NewRequest( // r.Method, // qbittorrent.URL(&c.QBittorrent, i, r.URL).String(), // bytes.NewBuffer(body), // ) // if err != nil { // return nil, err // } // req.Header = r.Header.Clone() // err = PrepareRequest(req, c, i) // if err != nil { // return nil, err // } // oldDirector := proxy.Director // proxy.Director = func(r *http.Request) { // rewriteRequestURL(req, qbittorrent.URL(&c.QBittorrent, i, r.URL)) // r.Header.Del("Referer") // } // // if strings.HasPrefix(r.URL.RequestURI(), "/api/v2/torrents/add") { // // log.Println(req) // // } // resp, err := proxy.Transport.RoundTrip(req) // proxy.Director = oldDirector // return resp, err // } func (c Config) MakeResponse(err error, resp *http.Response, w http.ResponseWriter) { if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { for header := range resp.Header { w.Header().Add(header, resp.Header.Get(header)) } io.Copy(w, resp.Body) } } // func (c *Config) HandlerHashFinder(w http.ResponseWriter, r *http.Request) { // body, err := io.ReadAll(r.Body) // r.Body = io.NopCloser(bytes.NewBuffer(body)) // if helperError(err, w) { // return // } // hashes := []string{} // key := "hash" // if r.Form.Has("hash") { // hashes = append(hashes, r.Form.Get("hash")) // } // if r.Form.Has("hashes") { // key = "hashes" // hashes = append(hashes, strings.Split(r.Form.Get("hashes"), "|")...) // } // state.AppState.Locks.Torrents.Lock() // defer state.AppState.Locks.Torrents.Unlock() // resps := []*http.Response{} // for _, hash := range hashes { // form, err := url.ParseQuery(r.URL.RawQuery) // if helperError(err, w) { // return // } // form.Del("hash") // form.Del("hashes") // form.Set(key, hash) // r.URL.RawQuery = form.Encode() // instance, ok := state.AppState.Torrents[hash] // if ok { // resp, err := c.MakeRequest(r, &instance) // if err != nil || resp.StatusCode != http.StatusOK { // ok = false // } else { // resps = append(resps, resp) // } // r.Form.Del("") // } else if !ok { // log.Println("hash not known, looking up: " + hash) // for i := uint(0); i < state.AppState.NumberOfClients; i++ { // resp, err := c.MakeRequest(r, &i) // if helperError(err, w) { // return // } else if resp.StatusCode == http.StatusOK { // resps = append(resps, resp) // state.AppState.Torrents[hash] = i // } // } // } // } // if len(resps) == 1 { // c.MakeResponse(resps[0], w) // } else if len(resps) > 0 { // baseResp := resps[0] // baseBody := "" // for _, resp := range resps { // body, err := io.ReadAll(resp.Body) // if helperError(err, w) { // return // } // baseBody += string(body) // } // baseResp.Body = io.NopCloser(bytes.NewBuffer([]byte(baseBody))) // c.MakeResponse(baseResp, w) // } else { // http.Error(w, "no responses", http.StatusInternalServerError) // } // } // func (c *Config) Parallel(r *http.Request) (output []*struct { // response *gabs.Container // instance uint // }, err error) { // g, ctx := errgroup.WithContext(context.Background()) // responses := make(chan struct { // response *http.Response // instance uint // }) // body, err := io.ReadAll(r.Body) // if err != nil { // return // } // for i := uint(0); i < state.AppState.NumberOfClients; i++ { // g.Go(func() (err error) { // req, err := http.NewRequest( // r.Method, // qbittorrent.URL(&c.QBittorrent, &i, r.URL).String(), // bytes.NewBuffer(body), // ) // if err != nil { // return err // } // resp, err := c.MakeRequest(req, &i) // if err != nil { // return err // } else if resp.StatusCode != http.StatusOK { // body, _ := io.ReadAll(resp.Body) // return errors.New("Error" + string(body)) // } // select { // case responses <- struct { // response *http.Response // instance uint // }{ // response: resp, // instance: i, // }: // return nil // case <-ctx.Done(): // return ctx.Err() // } // }) // } // go func() { // g.Wait() // close(responses) // }() // for resp := range responses { // cont, err := gabs.ParseJSONBuffer(resp.response.Body) // if err != nil { // return nil, err // } // output = append(output, &struct { // response *gabs.Container // instance uint // }{ // response: cont, // instance: resp.instance, // }) // } // err = g.Wait() // if err != nil { // return // } // return output, nil // } // func (c *Config) HandlerFetchMergeArray(w http.ResponseWriter, r *http.Request) { // if r.URL.Path == "/api/v2/torrents/info" { // state.AppState.Locks.Torrents.Lock() // defer state.AppState.Locks.Torrents.Unlock() // state.AppState.Torrents = map[string]uint{} // } // resps, err := c.Parallel(r) // if helperError(err, w) { // return // } // output := []*gabs.Container{} // for _, resp := range resps { // for _, child := range resp.response.Children() { // output = append(output, child) // if r.URL.Path == "/api/v2/torrents/info" { // hash := child.Path("hash").Data().(string) // state.AppState.Torrents[hash] = resp.instance // log.Println("Stored hash", hash) // } // } // } // if r.URL.Path == "/api/v2/torrents/info" { // slices.SortStableFunc(output, func(a *gabs.Container, b *gabs.Container) int { // return strings.Compare(a.Path("added_on").String(), b.Path("added_on").String()) // }) // } // w.Write(gabs.Wrap(output).BytesIndent("", " ")) // } // func (c *Config) HandlerFetchMerge(w http.ResponseWriter, r *http.Request) { // resps, err := c.Parallel(r) // if helperError(err, w) { // return // } // output := &gabs.Container{} // for _, resp := range resps { // output.MergeFn(resp.response, func(dest, source interface{}) interface{} { // destArr, destIsArray := dest.([]interface{}) // sourceArr, sourceIsArray := source.([]interface{}) // if destIsArray { // if sourceIsArray { // return append(destArr, sourceArr...) // } // return append(destArr, source) // } // if sourceIsArray { // return append(append([]interface{}{}, dest), sourceArr...) // } // return source // }) // } // w.Write(gabs.Wrap(output).BytesIndent("", " ")) // } // // Prepepares and rewrites headers required to auth with qBittorrent // func PrepareRequest(r *http.Request, c *Config, i *uint) (err error) { // if r == nil { // return errors.New("empty request given") // } // if c == nil { // return errors.New("empty config given") // } // if i == nil { // return errors.New("empty instance given") // } // url := qbittorrent.URL(&c.QBittorrent, i, r.URL) // r.Host = url.String() // r.Header.Del("Referer") // r.Header.Del("Origin") // r.Header.Del("Accept-Encoding") // r.Header.Set("Cookie", state.AppState.Cookies[*i].Raw) // return // }