github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/http/handlers/handler-v1.go (about)

     1  /* For license and copyright information please see the LEGAL file in the code repository */
     2  
     3  package hh
     4  
     5  import (
     6  	"github.com/GeniusesGroup/libgo/convert"
     7  	"github.com/GeniusesGroup/libgo/http"
     8  	hs "github.com/GeniusesGroup/libgo/http/services"
     9  	"github.com/GeniusesGroup/libgo/log"
    10  	"github.com/GeniusesGroup/libgo/protocol"
    11  )
    12  
    13  // Protocol Standard - HTTP/1 : https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
    14  type V1 struct{}
    15  
    16  // HandleIncomeRequest handle incoming HTTP request streams.
    17  // It can use for architectures like restful, ...
    18  func (h *V1) HandleIncomeRequest(st protocol.Stream) (err protocol.Error) {
    19  	var httpReq http.Request
    20  	var httpRes http.Response
    21  	httpReq.Init()
    22  	httpRes.Init()
    23  
    24  	_, err = httpReq.Decode(st)
    25  	if err != nil {
    26  		httpRes.SetStatus(http.StatusBadRequestCode, http.StatusBadRequestPhrase)
    27  		h.HandleOutcomeResponse(st, &httpReq, &httpRes)
    28  		return
    29  	}
    30  
    31  	err = h.ServeHTTP(st, &httpReq, &httpRes)
    32  	return
    33  }
    34  
    35  // ServeHTTP handle incoming HTTP request.
    36  // Developers can develope new one with its desire logic to more respect protocols like restful, ...
    37  func (h *V1) ServeHTTP(st protocol.Stream, httpReq *http.Request, httpRes *http.Response) (err protocol.Error) {
    38  	if !protocol.AppMode_Dev && !hs.HostSupportedService.ServeHTTP(st, httpReq, httpRes) {
    39  		h.HandleOutcomeResponse(st, httpReq, httpRes)
    40  		return
    41  	}
    42  
    43  	var path = httpReq.URI().Path()
    44  	switch path {
    45  	case hs.MuxService_Path:
    46  		err = hs.MuxService.ServeHTTP(st, httpReq, httpRes)
    47  	case hs.LandingService_Path:
    48  		// TODO:::
    49  	default:
    50  		// serve by URL
    51  		var service protocol.Service
    52  		service, err = protocol.App.GetServiceByURI(path)
    53  		if service == nil {
    54  			// If project don't have any logic that support data on e.g. HTTP (restful, ...) we send platform GUI app for web
    55  			err = hs.ServeWWWService.ServeHTTP(st, httpReq, httpRes)
    56  		} else {
    57  			err = service.ServeHTTP(st, httpReq, httpRes)
    58  		}
    59  	}
    60  	h.HandleOutcomeResponse(st, httpReq, httpRes)
    61  	return
    62  }
    63  
    64  // HandleOutcomeResponse use to handle outcome HTTP response stream.
    65  func (h *V1) HandleOutcomeResponse(st protocol.Stream, httpReq *http.Request, httpRes *http.Response) {
    66  	// Do some global assignment to response
    67  	httpRes.SetVersion(httpReq.Version())
    68  	if httpRes.Body() != nil {
    69  		var mediaType = httpRes.Body().MediaType()
    70  		if mediaType != nil {
    71  			httpRes.H.Set(http.HeaderKeyContentType, mediaType.ToString())
    72  		}
    73  		var compressType = httpRes.Body().CompressType()
    74  		if compressType != nil {
    75  			httpRes.H.Set(http.HeaderKeyContentEncoding, compressType.ContentEncoding())
    76  		}
    77  
    78  		if httpRes.Body().Len() > 0 {
    79  			httpRes.SetContentLength()
    80  		} else {
    81  			httpRes.H.SetTransferEncoding(http.HeaderValueChunked)
    82  		}
    83  	} else {
    84  		httpRes.H.SetZeroContentLength()
    85  	}
    86  
    87  	// httpRes.H.Set(HeaderKeyAccessControlAllowOrigin, "*")
    88  
    89  	st.Encode(httpRes)
    90  
    91  	if protocol.AppMode_Dev {
    92  		// TODO::: req||res not serialized yet to log it! any idea to have better performance below??
    93  		var req, _ = httpReq.Marshal()
    94  		var res, _ = httpRes.Marshal()
    95  		protocol.App.Log(log.ConfEvent(domainEnglish, convert.UnsafeByteSliceToString(req)))
    96  		protocol.App.Log(log.ConfEvent(domainEnglish, convert.UnsafeByteSliceToString(res)))
    97  	}
    98  }
    99  
   100  // SendBidirectionalRequest use to handle outcoming HTTP request stream
   101  // It block caller until get response or error
   102  func SendBidirectionalRequest(conn protocol.Connection, service protocol.Service, httpReq *http.Request) (httpRes *http.Response, err protocol.Error) {
   103  	var st protocol.Stream
   104  	st, err = conn.OutcomeStream(service)
   105  	if err != nil {
   106  		return
   107  	}
   108  
   109  	_, err = st.Encode(httpReq)
   110  	if err != nil {
   111  		return
   112  	}
   113  
   114  	var streamStatus = st.State()
   115  	for {
   116  		var status = <-streamStatus
   117  		switch status {
   118  		case protocol.NetworkStatus_Timeout:
   119  			// err =
   120  		case protocol.NetworkStatus_ReceivedCompletely:
   121  			var res http.Response
   122  			res.Init()
   123  			_, err = res.Decode(st)
   124  			if err == nil {
   125  				err = res.GetError()
   126  			}
   127  			httpRes = &res
   128  		default:
   129  			continue
   130  		}
   131  		st.Close()
   132  		break
   133  	}
   134  	return
   135  }
   136  
   137  // SendUnidirectionalRequest use to send outcome HTTP request and don't expect any response.
   138  // It block caller until request send successfully or return error
   139  func SendUnidirectionalRequest(conn protocol.Connection, service protocol.Service, httpReq *http.Request) (err protocol.Error) {
   140  	var st protocol.Stream
   141  	st, err = conn.OutcomeStream(service)
   142  	if err != nil {
   143  		return
   144  	}
   145  
   146  	_, err = st.Encode(httpReq)
   147  	if err != nil {
   148  		return
   149  	}
   150  
   151  	var streamStatus = st.State()
   152  	for {
   153  		var status = <-streamStatus
   154  		switch status {
   155  		case protocol.NetworkStatus_Timeout:
   156  			// err =
   157  		case protocol.NetworkStatus_SentCompletely:
   158  			// Nothing to do. Just let execution go to st.Close() and break the loop
   159  		default:
   160  			continue
   161  		}
   162  		st.Close()
   163  		break
   164  	}
   165  	return
   166  }