github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/maps/srv.go (about)

     1  package maps
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"strconv"
     9  
    10  	"github.com/keybase/client/go/avatars"
    11  	"github.com/keybase/client/go/chat/globals"
    12  	"github.com/keybase/client/go/protocol/keybase1"
    13  
    14  	"github.com/keybase/client/go/kbhttp/manager"
    15  )
    16  
    17  type Srv struct {
    18  	globals.Contextified
    19  	httpSrv *manager.Srv
    20  }
    21  
    22  func NewSrv(g *globals.Context, httpSrv *manager.Srv) *Srv {
    23  	s := &Srv{
    24  		Contextified: globals.NewContextified(g),
    25  		httpSrv:      httpSrv,
    26  	}
    27  	s.httpSrv.HandleFunc("map", manager.SrvTokenModeDefault, s.serve)
    28  	return s
    29  }
    30  
    31  func (s *Srv) debug(msg string, args ...interface{}) {
    32  	s.G().GetLog().Debug("Maps.Srv: %s", fmt.Sprintf(msg, args...))
    33  }
    34  
    35  func (s *Srv) makeError(w http.ResponseWriter, code int, msg string, args ...interface{}) {
    36  	s.debug("serve: error code: %d msg %s", code, fmt.Sprintf(msg, args...))
    37  	w.WriteHeader(code)
    38  }
    39  
    40  func (s *Srv) serve(w http.ResponseWriter, req *http.Request) {
    41  	ctx := globals.ChatCtx(context.Background(), s.G(), keybase1.TLFIdentifyBehavior_CHAT_GUI, nil, nil)
    42  	strlat := req.URL.Query().Get("lat")
    43  	strlon := req.URL.Query().Get("lon")
    44  	strwidth := req.URL.Query().Get("width")
    45  	strheight := req.URL.Query().Get("height")
    46  	username := req.URL.Query().Get("username")
    47  	lat, err := strconv.ParseFloat(strlat, 64)
    48  	if err != nil {
    49  		s.makeError(w, http.StatusBadRequest, "invalid lat: %s", err)
    50  		return
    51  	}
    52  	lon, err := strconv.ParseFloat(strlon, 64)
    53  	if err != nil {
    54  		s.makeError(w, http.StatusBadRequest, "invalid lon: %s", err)
    55  		return
    56  	}
    57  	width, err := strconv.ParseInt(strwidth, 0, 0)
    58  	if err != nil {
    59  		s.makeError(w, http.StatusBadRequest, "invalid width: %s", err)
    60  		return
    61  	}
    62  	height, err := strconv.ParseInt(strheight, 0, 0)
    63  	if err != nil {
    64  		s.makeError(w, http.StatusBadRequest, "invalid height: %s", err)
    65  		return
    66  	}
    67  	mapURL, err := GetCustomMapURL(ctx, s.G().ExternalAPIKeySource, lat, lon, int(width)*scale,
    68  		int(height)*scale)
    69  	if err != nil {
    70  		s.makeError(w, http.StatusInternalServerError, "unable to get map url: %s", err)
    71  		return
    72  	}
    73  	mapReader, _, err := MapReaderFromURL(ctx, s.G(), mapURL)
    74  	if err != nil {
    75  		s.makeError(w, http.StatusInternalServerError, "unable to get map reader: %s", err)
    76  		return
    77  	}
    78  
    79  	defer mapReader.Close()
    80  
    81  	var reader io.ReadCloser
    82  	if username != "" {
    83  		avatarReader, _, err := avatars.GetBorderedCircleAvatar(ctx, s.G(), username, 48, 8, 8)
    84  		if err != nil {
    85  			s.makeError(w, http.StatusInternalServerError, "unable to get avatar: %s", err)
    86  			return
    87  		}
    88  
    89  		fancyReader, _, err := DecorateMap(ctx, avatarReader, mapReader)
    90  		if err != nil {
    91  			s.makeError(w, http.StatusInternalServerError, "unable to decorate map: %s", err)
    92  			return
    93  		}
    94  		reader = fancyReader
    95  	} else {
    96  		reader = mapReader
    97  	}
    98  
    99  	if _, err := io.Copy(w, reader); err != nil {
   100  		s.makeError(w, http.StatusInternalServerError, "unable to read map: %s", err)
   101  		return
   102  	}
   103  }
   104  
   105  func ServiceInit(g *globals.Context, httpSrv *manager.Srv) {
   106  	NewSrv(g, httpSrv)
   107  }