...

Source file src/golang.conradwood.net/go-easyops/http/http_caching.go

Documentation: golang.conradwood.net/go-easyops/http

     1  package http
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"time"
     9  
    10  	"golang.conradwood.net/go-easyops/errors"
    11  	"golang.yacloud.eu/apis/urlcacher"
    12  )
    13  
    14  var (
    15  	foo_ctr int
    16  )
    17  
    18  // caching http
    19  type cHTTP struct {
    20  	timeout               time.Duration
    21  	ctx                   context.Context
    22  	ctx_cancel            context.CancelFunc
    23  	tio                   *timeouter
    24  	last_message_received time.Time
    25  	cancelled             bool
    26  	debug                 bool
    27  }
    28  type timeouter struct {
    29  	ch  chan bool
    30  	idx int
    31  }
    32  
    33  func (h *cHTTP) SetDebug(b bool) {
    34  	h.debug = b
    35  }
    36  func (h *cHTTP) Cookie(name string) *http.Cookie {
    37  	panic("cookie not supported")
    38  }
    39  func (h *cHTTP) Cookies() []*http.Cookie {
    40  	panic("cookies not supported")
    41  }
    42  func (h *cHTTP) Delete(url string, body []byte) *HTTPResponse {
    43  	panic("delete not supported")
    44  }
    45  func (h *cHTTP) Get(url string) *HTTPResponse {
    46  	defer h.stop_timeouter()
    47  	ctx := h.ctx
    48  	hr := &HTTPResponse{}
    49  	empty := &urlcacher.GetRequest{URL: url}
    50  	srv, err := urlcacher.GetURLCacherClient().Get(ctx, empty)
    51  	if err != nil {
    52  		hr.err = err
    53  		return hr
    54  	}
    55  
    56  	l := uint64(0)
    57  	started := time.Now()
    58  	var buf []byte
    59  	for {
    60  		if h.timeout != 0 {
    61  			dur := time.Since(started)
    62  			if dur > h.timeout {
    63  				hr.err = fmt.Errorf("timeout after %0.2fs seconds", dur.Seconds())
    64  			}
    65  		}
    66  
    67  		data, err := srv.Recv()
    68  		if h.ctx.Err() != nil {
    69  			hr.err = fmt.Errorf("ctx error after %0.2fs: %s", time.Since(started).Seconds(), h.ctx.Err())
    70  			break
    71  		}
    72  		if h.cancelled {
    73  			hr.err = fmt.Errorf("Cancelled (timeout)")
    74  			break
    75  		}
    76  		h.last_message_received = time.Now()
    77  		if (data != nil) && (len(data.Data)) > 0 {
    78  			buf = append(buf, data.Data...)
    79  		}
    80  		if (data != nil) && (data.Result != nil) {
    81  			r := data.Result
    82  			hr.httpCode = int(r.HTTPCode)
    83  			if !r.Success {
    84  				if hr.httpCode == 404 {
    85  					hr.err = errors.NotFound(ctx, "url \"%s\" not found (code %d): %s", url, hr.httpCode, r.Message)
    86  				} else {
    87  					hr.err = fmt.Errorf("failed to retrieve url \"%s\" (code %d): %s", url, hr.httpCode, r.Message)
    88  				}
    89  				break
    90  			}
    91  		}
    92  
    93  		if err == io.EOF {
    94  			break
    95  		}
    96  		if err != nil {
    97  			hr.err = err
    98  			break
    99  		}
   100  		r := uint64(len(data.Data))
   101  		l = l + r
   102  	}
   103  	hr.setBody(buf)
   104  	return hr
   105  }
   106  func (h *cHTTP) GetStream(url string) *HTTPResponse {
   107  	return nil
   108  }
   109  func (h *cHTTP) Head(url string) *HTTPResponse {
   110  	panic("head not supported")
   111  }
   112  func (h *cHTTP) Post(url string, body []byte) *HTTPResponse {
   113  	panic("post not supported")
   114  }
   115  func (h *cHTTP) Put(url string, body string) *HTTPResponse {
   116  	panic("put not supported")
   117  }
   118  func (h *cHTTP) SetHeader(key string, value string) {
   119  	panic("setheader not supported")
   120  }
   121  func (h *cHTTP) SetTimeout(dur time.Duration) {
   122  	h.debugf("setting timeout to %0.2fs\n", dur.Seconds())
   123  	h.timeout = dur
   124  	h.stop_timeouter()
   125  	foo_ctr++
   126  	h.tio = &timeouter{ch: make(chan bool), idx: foo_ctr}
   127  	if h.tio == nil {
   128  		panic("no timeouter")
   129  	}
   130  	//	h.debugf("h=%v\n", h.tio)
   131  	go h.timeouter(h.tio)
   132  }
   133  func (h *cHTTP) stop_timeouter() {
   134  	if h.tio == nil {
   135  		h.debugf("no timeouter to stop\n")
   136  		return
   137  	}
   138  	h.debugf("stopping timeouter %d\n", h.tio.idx)
   139  	select {
   140  	case h.tio.ch <- false:
   141  	case <-time.After(time.Duration(10) * time.Millisecond):
   142  	}
   143  }
   144  func (h *cHTTP) SetCreds(username, password string) {
   145  	panic("cannot use credentials for caching http")
   146  }
   147  
   148  func (h *cHTTP) timeouter(t *timeouter) {
   149  	h.debugf("timeouter %d started\n", t.idx)
   150  	var b bool
   151  	ch := t.ch
   152  	select {
   153  	case b = <-ch:
   154  		h.debugf("timeouter %d received %v\n", t.idx, b)
   155  	case <-time.After(h.timeout):
   156  		h.debugf("timeouter %d timer-outed\n", t.idx)
   157  		b = true
   158  	}
   159  	if b {
   160  		h.ctx_cancel()
   161  		h.cancelled = true
   162  		h.debugf("timeouter %d cancelled context\n", t.idx)
   163  	}
   164  	h.debugf("timeouter %d done\n", t.idx)
   165  
   166  }
   167  
   168  func (h *cHTTP) debugf(format string, args ...interface{}) {
   169  	if !*debug {
   170  		return
   171  	}
   172  	sn := "[cHTTP] "
   173  	sx := fmt.Sprintf(format, args...)
   174  	fmt.Print(sn + sx)
   175  }
   176  

View as plain text