github.com/micro/go-micro/examples@v0.0.0-20210105173217-bf4ab679e18b/stream/web/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"log"
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/gorilla/websocket"
    11  	proto "github.com/micro/go-micro/examples/stream/server/proto"
    12  	"github.com/micro/go-micro/v2/client"
    13  	"github.com/micro/go-micro/v2/web"
    14  )
    15  
    16  var upgrader = websocket.Upgrader{
    17  	CheckOrigin: func(r *http.Request) bool { return true },
    18  }
    19  
    20  func Stream(cli proto.StreamerService, ws *websocket.Conn) error {
    21  	// Read initial request from websocket
    22  	var req proto.Request
    23  	err := ws.ReadJSON(&req)
    24  	if err != nil {
    25  		return err
    26  	}
    27  
    28  	// Even if we aren't expecting further requests from the websocket, we still need to read from it to ensure we
    29  	// get close signals
    30  	go func() {
    31  		for {
    32  			if _, _, err := ws.NextReader(); err != nil {
    33  				break
    34  			}
    35  		}
    36  	}()
    37  
    38  	log.Printf("Received Request: %v", req)
    39  
    40  	// Send request to stream server
    41  	stream, err := cli.ServerStream(context.Background(), &req)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	defer stream.Close()
    46  
    47  	// Read from the stream server and pass responses on to websocket
    48  	for {
    49  		// Read from stream, end request once the stream is closed
    50  		rsp, err := stream.Recv()
    51  		if err != nil {
    52  			if err != io.EOF {
    53  				return err
    54  			}
    55  
    56  			break
    57  		}
    58  
    59  		// Write server response to the websocket
    60  		err = ws.WriteJSON(rsp)
    61  		if err != nil {
    62  			// End request if socket is closed
    63  			if isExpectedClose(err) {
    64  				log.Println("Expected Close on socket", err)
    65  				break
    66  			} else {
    67  				return err
    68  			}
    69  		}
    70  	}
    71  
    72  	return nil
    73  }
    74  
    75  func isExpectedClose(err error) bool {
    76  	if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
    77  		log.Println("Unexpected websocket close: ", err)
    78  		return false
    79  	}
    80  
    81  	return true
    82  }
    83  
    84  func main() {
    85  	// New web service
    86  	service := web.NewService(
    87  		web.Name("go.micro.web.stream"),
    88  	)
    89  
    90  	if err := service.Init(); err != nil {
    91  		log.Fatal("Init", err)
    92  	}
    93  
    94  	// New RPC client
    95  	rpcClient := client.NewClient(client.RequestTimeout(time.Second * 120))
    96  	cli := proto.NewStreamerService("go.micro.srv.stream", rpcClient)
    97  
    98  	// Serve static html/js
    99  	service.Handle("/", http.FileServer(http.Dir("html")))
   100  
   101  	// Handle websocket connection
   102  	service.HandleFunc("/stream", func(w http.ResponseWriter, r *http.Request) {
   103  		// Upgrade request to websocket
   104  		conn, err := upgrader.Upgrade(w, r, nil)
   105  		if err != nil {
   106  			log.Fatal("Upgrade: ", err)
   107  			return
   108  		}
   109  		defer conn.Close()
   110  
   111  		// Handle websocket request
   112  		if err := Stream(cli, conn); err != nil {
   113  			log.Fatal("Echo: ", err)
   114  			return
   115  		}
   116  		log.Println("Stream complete")
   117  	})
   118  
   119  	if err := service.Run(); err != nil {
   120  		log.Fatal("Run: ", err)
   121  	}
   122  }