Initial checkin
This commit is contained in:
		
						commit
						ef921ff728
					
				
							
								
								
									
										8
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Datasource local storage ignored files | ||||
| /dataSources/ | ||||
| /dataSources.local.xml | ||||
| # Editor-based HTTP Client requests | ||||
| /httpRequests/ | ||||
							
								
								
									
										8
									
								
								.idea/cure.iml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/cure.iml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="WEB_MODULE" version="4"> | ||||
|   <component name="NewModuleRootManager"> | ||||
|     <content url="file://$MODULE_DIR$" /> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										4
									
								
								.idea/encodings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								.idea/encodings.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="Encoding" addBOMForNewFiles="with NO BOM" /> | ||||
| </project> | ||||
							
								
								
									
										10
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| <component name="InspectionProjectProfileManager"> | ||||
|   <profile version="1.0"> | ||||
|     <option name="myName" value="Project Default" /> | ||||
|     <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> | ||||
|       <option name="processCode" value="true" /> | ||||
|       <option name="processLiterals" value="true" /> | ||||
|       <option name="processComments" value="true" /> | ||||
|     </inspection_tool> | ||||
|   </profile> | ||||
| </component> | ||||
							
								
								
									
										6
									
								
								.idea/misc.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/misc.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,6 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="JavaScriptSettings"> | ||||
|     <option name="languageLevel" value="ES6" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/.idea/cure.iml" filepath="$PROJECT_DIR$/.idea/cure.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										208
									
								
								cure.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								cure.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,208 @@ | |||
| // Common Uniform Rest Endpoint
 | ||||
| //
 | ||||
| // This is a library to access REST endpoints in a simplified way.
 | ||||
| package cure // import "udico.de/cure"
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"github.com/golang/protobuf/jsonpb" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| type Endpoint struct { | ||||
| 	// The base url of the REST API
 | ||||
| 	Base string | ||||
| 
 | ||||
| 	// use this string as user agent
 | ||||
| 	UserAgent string | ||||
| 
 | ||||
| 	// Additional HTTP header attributes to set in every call.
 | ||||
| 	// You can (and should) also set per Call attributes within the Call object
 | ||||
| 	Head map[string]string | ||||
| 
 | ||||
| 	client *http.Client | ||||
| } | ||||
| 
 | ||||
| func New(baseurl string) *Endpoint { | ||||
| 	return &Endpoint{ | ||||
| 		Base:      baseurl, | ||||
| 		UserAgent: "Common Uniform Rest Endpoint, 1.0.0", | ||||
| 		Head:      make(map[string]string), | ||||
| 		client:    &http.Client{}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type call struct { | ||||
| 	url    string | ||||
| 	method string | ||||
| 	api    *Endpoint | ||||
| 
 | ||||
| 	// HTTP header attributes to set. These will override the ones set within the endpoint.
 | ||||
| 	Head map[string]string | ||||
| 
 | ||||
| 	// The parameters of your call. Depending on the method, they'll be appended to the query or posted url-form-encoded
 | ||||
| 	Parameters map[string]string | ||||
| 
 | ||||
| 	// If set, this data will be used as POST data (
 | ||||
| 	Body *bytes.Reader | ||||
| } | ||||
| 
 | ||||
| type callret struct { | ||||
| 	Code    int | ||||
| 	Message string | ||||
| 	err     error | ||||
| } | ||||
| 
 | ||||
| func (r callret) Ok() bool { | ||||
| 	if r.err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	// We don't expect 1xx codes
 | ||||
| 	if (r.Code / 100) > 2 { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // Simplify error handling at client side
 | ||||
| func (r callret) Error() error { | ||||
| 	if r.err != nil { | ||||
| 		return r.err | ||||
| 	} | ||||
| 	if (r.Code / 100) > 2 { | ||||
| 		return errors.New(r.Message) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (a *Endpoint) createCall(method, endpoint string) *call { | ||||
| 	ret := &call{ | ||||
| 		url:        a.Base + endpoint, // todo: ensure we have a valid url
 | ||||
| 		method:     method, | ||||
| 		api:        a, | ||||
| 		Head:       make(map[string]string), | ||||
| 		Parameters: make(map[string]string), | ||||
| 	} | ||||
| 	ret.Head["user-agent"] = a.UserAgent | ||||
| 	for k, v := range a.Head { | ||||
| 		ret.Head[k] = v | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func (a *Endpoint) Get(endpoint string) *call { | ||||
| 	return a.createCall("GET", endpoint) | ||||
| } | ||||
| 
 | ||||
| func (a *Endpoint) PostForm(endpoint string) *call { | ||||
| 	ret := a.createCall("POST", endpoint) | ||||
| 	ret.Head["content-type"] = "application/x-www-form-urlencoded" | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func (a *Endpoint) PostBody(endpoint string) *call { | ||||
| 	ret := a.createCall("POST", endpoint) | ||||
| 	ret.Head["content-type"] = "application/json" | ||||
| 	return ret | ||||
| } | ||||
| 
 | ||||
| func (c *call) Param(param interface{}) *call { | ||||
| 	marshaller := new(jsonpb.Marshaler) | ||||
| 	marshaller.EmitDefaults = false | ||||
| 	marshaller.EnumsAsInts = false | ||||
| 	marshaller.OrigName = true | ||||
| 	buf := &bytes.Buffer{} | ||||
| 	_ = marshaller.Marshal(buf, param.(proto.Message)) | ||||
| 	logrus.Debug(string(buf.Bytes()[:])) | ||||
| 	logrus.Debug(string(buf.Bytes()[:])) | ||||
| 	c.Body = bytes.NewReader(buf.Bytes()) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| func (c *call) Fire(ctx context.Context, result interface{}) callret { | ||||
| 	// disable HTTP2
 | ||||
| 	//client := &http.Client{Transport: &http.Transport{TLSNextProto: make(map[string]func(string, *tls.Conn) http.RoundTripper)}}
 | ||||
| 	//client := &http.Client{}
 | ||||
| 
 | ||||
| 	// handle POST parameters
 | ||||
| 	var request *http.Request | ||||
| 	var err error | ||||
| 	if c.method == "POST" { | ||||
| 		if c.Body != nil { | ||||
| 			request, err = http.NewRequest(c.method, c.url, c.Body) | ||||
| 			//request.Header.Set("content-length", fmt.Sprintf("%v", c.Body.Len()))
 | ||||
| 		} else { | ||||
| 			fdata := url.Values{} | ||||
| 			for k, v := range c.Parameters { | ||||
| 				fdata.Add(k, v) | ||||
| 			} | ||||
| 			logrus.Debug(fdata.Encode()) | ||||
| 			sRead := strings.NewReader(fdata.Encode()) | ||||
| 			request, err = http.NewRequest(c.method, c.url, sRead) | ||||
| 		} | ||||
| 	} else { | ||||
| 		request, err = http.NewRequest(c.method, c.url, nil) | ||||
| 	} | ||||
| 
 | ||||
| 	for k, v := range c.Head { | ||||
| 		request.Header.Set(k, v) | ||||
| 	} | ||||
| 
 | ||||
| 	request = request.WithContext(ctx) | ||||
| 
 | ||||
| 	// handle GET parameters
 | ||||
| 	if c.method == "GET" { | ||||
| 		gdata := request.URL.Query() | ||||
| 		for k, v := range c.Parameters { | ||||
| 			gdata.Add(k, v) | ||||
| 		} | ||||
| 		request.URL.RawQuery = gdata.Encode() | ||||
| 	} | ||||
| 
 | ||||
| 	logrus.Debugf("%v %v", c.method, c.url) | ||||
| 	for k, v := range c.Head { | ||||
| 		logrus.Debugf("  [%v: %v]", k, v) | ||||
| 	} | ||||
| 	for k, v := range c.Parameters { | ||||
| 		logrus.Debugf("  + %v = '%v'", k, v) | ||||
| 	} | ||||
| 
 | ||||
| 	hbuf := &bytes.Buffer{} | ||||
| 	request.Header.Write(hbuf) | ||||
| 
 | ||||
| 	// go!
 | ||||
| 	response, err := c.api.client.Do(request) | ||||
| 	if err != nil { | ||||
| 		return callret{0, "", err} | ||||
| 	} | ||||
| 	logrus.Debugf("-> %v", response.Status) | ||||
| 
 | ||||
| 	if response == nil { | ||||
| 		return callret{0, "", errors.New("empty response")} | ||||
| 	} | ||||
| 
 | ||||
| 	// no result requested
 | ||||
| 	if result == nil { | ||||
| 		return callret{0, "", nil} | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: dump the content
 | ||||
| 	//buf := &bytes.Buffer{}
 | ||||
| 	buf, err := ioutil.ReadAll(response.Body) | ||||
| 	bbuf := bytes.NewReader(buf) | ||||
| 	logrus.Debug(string(buf[:])) | ||||
| 
 | ||||
| 	unmarshaller := new(jsonpb.Unmarshaler) | ||||
| 	unmarshaller.AllowUnknownFields = true | ||||
| 	return callret{ | ||||
| 		response.StatusCode, | ||||
| 		response.Status, | ||||
| 		unmarshaller.Unmarshal(bbuf, result.(proto.Message)), | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Thilo Karraß
						Thilo Karraß