github.com/nuvolaris/nuv@v0.0.0-20240511174247-a74e3a52bfd8/serve.go (about) 1 // Licensed to the Apache Software Foundation (ASF) under one 2 // or more contributor license agreements. See the NOTICE file 3 // distributed with this work for additional information 4 // regarding copyright ownership. The ASF licenses this file 5 // to you under the Apache License, Version 2.0 (the 6 // "License"); you may not use this file except in compliance 7 // with the License. You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package main 19 20 import ( 21 "flag" 22 "fmt" 23 "log" 24 "net" 25 "net/http" 26 "net/http/httputil" 27 "net/url" 28 "os" 29 30 "github.com/pkg/browser" 31 ) 32 33 func Serve(olarisDir string, args []string) error { 34 flag := flag.NewFlagSet("serve", flag.ExitOnError) 35 flag.Usage = func() { 36 fmt.Println(`Serve a local directory on http://localhost:9768. You can change port with the NUV_PORT environment variable. 37 38 Usage: 39 nuv -serve [options] <dir> 40 41 Options: 42 -h, --help Print help message 43 --no-open Do not open browser automatically 44 --proxy <proxy> Use proxy server 45 `) 46 } 47 // Define command line flags 48 49 var helpFlag bool 50 var noBrowserFlag bool 51 var proxyFlag string 52 53 flag.BoolVar(&helpFlag, "h", false, "Print help message") 54 flag.BoolVar(&helpFlag, "help", false, "Print help message") 55 flag.BoolVar(&noBrowserFlag, "no-open", false, "Do not open browser") 56 flag.StringVar(&proxyFlag, "proxy", "", "Use proxy server") 57 58 // Parse command line flags 59 os.Args = args 60 err := flag.Parse(os.Args[1:]) 61 if err != nil { 62 return err 63 } 64 65 // Print help message if requested 66 if flag.NArg() != 1 || helpFlag { 67 flag.Usage() 68 return nil 69 } 70 71 webDir := flag.Arg(0) 72 73 // run nuv server and open browser 74 port := getNuvPort() 75 webDirPath := joinpath(os.Getenv("NUV_PWD"), webDir) 76 log.Println("Serving directory: " + webDirPath) 77 78 if !noBrowserFlag { 79 if err := browser.OpenURL("http://localhost:" + port); err != nil { 80 return err 81 } 82 } 83 84 localHandler := webFileServerHandler(webDirPath) 85 86 var proxy *httputil.ReverseProxy = nil 87 if proxyFlag != "" { 88 remoteUrl, err := url.Parse(proxyFlag) 89 if err != nil { 90 return err 91 } 92 proxy = httputil.NewSingleHostReverseProxy(remoteUrl) 93 } 94 95 customHandler := func(w http.ResponseWriter, r *http.Request) { 96 // Check if the file exists locally 97 98 _, err := http.Dir(webDirPath).Open(r.URL.Path) 99 if err == nil { 100 // Serve the file using the file server 101 localHandler.ServeHTTP(w, r) 102 return 103 } 104 105 // File not found locally, proxy the request to the remote server 106 log.Printf("not found locally %s\n", r.URL.Path) 107 108 if proxy != nil { 109 log.Printf("Proxying to %s\n", proxyFlag) 110 proxy.ServeHTTP(w, r) 111 } 112 } 113 114 handler := http.HandlerFunc(customHandler) 115 116 if checkPortAvailable(port) { 117 log.Println("Nuvolaris server started at http://localhost:" + port) 118 addr := fmt.Sprintf(":%s", port) 119 return http.ListenAndServe(addr, handler) 120 } else { 121 log.Println("Nuvolaris server failed to start. Port already in use?") 122 return nil 123 } 124 } 125 126 // Handler to serve the olaris/web directory 127 func webFileServerHandler(webDir string) http.Handler { 128 return http.FileServer(http.Dir(webDir)) 129 } 130 131 func checkPortAvailable(port string) bool { 132 ln, err := net.Listen("tcp", ":"+port) 133 if err != nil { 134 return false 135 } 136 //nolint:errcheck 137 ln.Close() 138 return true 139 }