mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-30 06:38:37 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			289 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			289 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package couchbase
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"github.com/couchbase/goutils/logging"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| )
 | |
| 
 | |
| // ViewDefinition represents a single view within a design document.
 | |
| type ViewDefinition struct {
 | |
| 	Map    string `json:"map"`
 | |
| 	Reduce string `json:"reduce,omitempty"`
 | |
| }
 | |
| 
 | |
| // DDoc is the document body of a design document specifying a view.
 | |
| type DDoc struct {
 | |
| 	Language string                    `json:"language,omitempty"`
 | |
| 	Views    map[string]ViewDefinition `json:"views"`
 | |
| }
 | |
| 
 | |
| // DDocsResult represents the result from listing the design
 | |
| // documents.
 | |
| type DDocsResult struct {
 | |
| 	Rows []struct {
 | |
| 		DDoc struct {
 | |
| 			Meta map[string]interface{}
 | |
| 			JSON DDoc
 | |
| 		} `json:"doc"`
 | |
| 	} `json:"rows"`
 | |
| }
 | |
| 
 | |
| // GetDDocs lists all design documents
 | |
| func (b *Bucket) GetDDocs() (DDocsResult, error) {
 | |
| 	var ddocsResult DDocsResult
 | |
| 	b.RLock()
 | |
| 	pool := b.pool
 | |
| 	uri := b.DDocs.URI
 | |
| 	b.RUnlock()
 | |
| 
 | |
| 	// MB-23555 ephemeral buckets have no ddocs
 | |
| 	if uri == "" {
 | |
| 		return DDocsResult{}, nil
 | |
| 	}
 | |
| 
 | |
| 	err := pool.client.parseURLResponse(uri, &ddocsResult)
 | |
| 	if err != nil {
 | |
| 		return DDocsResult{}, err
 | |
| 	}
 | |
| 	return ddocsResult, nil
 | |
| }
 | |
| 
 | |
| func (b *Bucket) GetDDocWithRetry(docname string, into interface{}) error {
 | |
| 	ddocURI := fmt.Sprintf("/%s/_design/%s", b.GetName(), docname)
 | |
| 	err := b.parseAPIResponse(ddocURI, &into)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (b *Bucket) GetDDocsWithRetry() (DDocsResult, error) {
 | |
| 	var ddocsResult DDocsResult
 | |
| 	b.RLock()
 | |
| 	uri := b.DDocs.URI
 | |
| 	b.RUnlock()
 | |
| 
 | |
| 	// MB-23555 ephemeral buckets have no ddocs
 | |
| 	if uri == "" {
 | |
| 		return DDocsResult{}, nil
 | |
| 	}
 | |
| 
 | |
| 	err := b.parseURLResponse(uri, &ddocsResult)
 | |
| 	if err != nil {
 | |
| 		return DDocsResult{}, err
 | |
| 	}
 | |
| 	return ddocsResult, nil
 | |
| }
 | |
| 
 | |
| func (b *Bucket) ddocURL(docname string) (string, error) {
 | |
| 	u, err := b.randomBaseURL()
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	u.Path = fmt.Sprintf("/%s/_design/%s", b.GetName(), docname)
 | |
| 	return u.String(), nil
 | |
| }
 | |
| 
 | |
| func (b *Bucket) ddocURLNext(nodeId int, docname string) (string, int, error) {
 | |
| 	u, selected, err := b.randomNextURL(nodeId)
 | |
| 	if err != nil {
 | |
| 		return "", -1, err
 | |
| 	}
 | |
| 	u.Path = fmt.Sprintf("/%s/_design/%s", b.GetName(), docname)
 | |
| 	return u.String(), selected, nil
 | |
| }
 | |
| 
 | |
| const ABS_MAX_RETRIES = 10
 | |
| const ABS_MIN_RETRIES = 3
 | |
| 
 | |
| func (b *Bucket) getMaxRetries() (int, error) {
 | |
| 
 | |
| 	maxRetries := len(b.Nodes())
 | |
| 
 | |
| 	if maxRetries == 0 {
 | |
| 		return 0, fmt.Errorf("No available Couch rest URLs")
 | |
| 	}
 | |
| 
 | |
| 	if maxRetries > ABS_MAX_RETRIES {
 | |
| 		maxRetries = ABS_MAX_RETRIES
 | |
| 	} else if maxRetries < ABS_MIN_RETRIES {
 | |
| 		maxRetries = ABS_MIN_RETRIES
 | |
| 	}
 | |
| 
 | |
| 	return maxRetries, nil
 | |
| }
 | |
| 
 | |
| // PutDDoc installs a design document.
 | |
| func (b *Bucket) PutDDoc(docname string, value interface{}) error {
 | |
| 
 | |
| 	var Err error
 | |
| 
 | |
| 	maxRetries, err := b.getMaxRetries()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	lastNode := START_NODE_ID
 | |
| 
 | |
| 	for retryCount := 0; retryCount < maxRetries; retryCount++ {
 | |
| 
 | |
| 		Err = nil
 | |
| 
 | |
| 		ddocU, selectedNode, err := b.ddocURLNext(lastNode, docname)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		lastNode = selectedNode
 | |
| 
 | |
| 		logging.Infof(" Trying with selected node %d", selectedNode)
 | |
| 		j, err := json.Marshal(value)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		req, err := http.NewRequest("PUT", ddocU, bytes.NewReader(j))
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		req.Header.Set("Content-Type", "application/json")
 | |
| 		err = maybeAddAuth(req, b.authHandler(false /* bucket not yet locked */))
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		res, err := doHTTPRequest(req)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		if res.StatusCode != 201 {
 | |
| 			body, _ := ioutil.ReadAll(res.Body)
 | |
| 			Err = fmt.Errorf("error installing view: %v / %s",
 | |
| 				res.Status, body)
 | |
| 			logging.Errorf(" Error in PutDDOC %v. Retrying...", Err)
 | |
| 			res.Body.Close()
 | |
| 			b.Refresh()
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		res.Body.Close()
 | |
| 		break
 | |
| 	}
 | |
| 
 | |
| 	return Err
 | |
| }
 | |
| 
 | |
| // GetDDoc retrieves a specific a design doc.
 | |
| func (b *Bucket) GetDDoc(docname string, into interface{}) error {
 | |
| 	var Err error
 | |
| 	var res *http.Response
 | |
| 
 | |
| 	maxRetries, err := b.getMaxRetries()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	lastNode := START_NODE_ID
 | |
| 	for retryCount := 0; retryCount < maxRetries; retryCount++ {
 | |
| 
 | |
| 		Err = nil
 | |
| 		ddocU, selectedNode, err := b.ddocURLNext(lastNode, docname)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		lastNode = selectedNode
 | |
| 		logging.Infof(" Trying with selected node %d", selectedNode)
 | |
| 
 | |
| 		req, err := http.NewRequest("GET", ddocU, nil)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		req.Header.Set("Content-Type", "application/json")
 | |
| 		err = maybeAddAuth(req, b.authHandler(false /* bucket not yet locked */))
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		res, err = doHTTPRequest(req)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if res.StatusCode != 200 {
 | |
| 			body, _ := ioutil.ReadAll(res.Body)
 | |
| 			Err = fmt.Errorf("error reading view: %v / %s",
 | |
| 				res.Status, body)
 | |
| 			logging.Errorf(" Error in GetDDOC %v Retrying...", Err)
 | |
| 			b.Refresh()
 | |
| 			res.Body.Close()
 | |
| 			continue
 | |
| 		}
 | |
| 		defer res.Body.Close()
 | |
| 		break
 | |
| 	}
 | |
| 
 | |
| 	if Err != nil {
 | |
| 		return Err
 | |
| 	}
 | |
| 
 | |
| 	d := json.NewDecoder(res.Body)
 | |
| 	return d.Decode(into)
 | |
| }
 | |
| 
 | |
| // DeleteDDoc removes a design document.
 | |
| func (b *Bucket) DeleteDDoc(docname string) error {
 | |
| 
 | |
| 	var Err error
 | |
| 
 | |
| 	maxRetries, err := b.getMaxRetries()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	lastNode := START_NODE_ID
 | |
| 
 | |
| 	for retryCount := 0; retryCount < maxRetries; retryCount++ {
 | |
| 
 | |
| 		Err = nil
 | |
| 		ddocU, selectedNode, err := b.ddocURLNext(lastNode, docname)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		lastNode = selectedNode
 | |
| 		logging.Infof(" Trying with selected node %d", selectedNode)
 | |
| 
 | |
| 		req, err := http.NewRequest("DELETE", ddocU, nil)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		req.Header.Set("Content-Type", "application/json")
 | |
| 		err = maybeAddAuth(req, b.authHandler(false /* bucket not already locked */))
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 
 | |
| 		res, err := doHTTPRequest(req)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if res.StatusCode != 200 {
 | |
| 			body, _ := ioutil.ReadAll(res.Body)
 | |
| 			Err = fmt.Errorf("error deleting view : %v / %s", res.Status, body)
 | |
| 			logging.Errorf(" Error in DeleteDDOC %v. Retrying ... ", Err)
 | |
| 			b.Refresh()
 | |
| 			res.Body.Close()
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		res.Body.Close()
 | |
| 		break
 | |
| 	}
 | |
| 	return Err
 | |
| }
 |