Rewrite environment variable configurations
This commit is contained in:
parent
48520a7d2d
commit
b4676af3c1
|
@ -2,6 +2,8 @@
|
|||
.gitignore
|
||||
.prettierrc
|
||||
.vscode
|
||||
.env
|
||||
example.env
|
||||
photos_path
|
||||
screenshots
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Build UI
|
||||
FROM node:10 as ui
|
||||
|
||||
ARG GRAPHQL_ENDPOINT
|
||||
ENV GRAPHQL_ENDPOINT=${GRAPHQL_ENDPOINT}
|
||||
ARG API_ENDPOINT
|
||||
ENV API_ENDPOINT=${API_ENDPOINT}
|
||||
|
||||
RUN mkdir -p /app
|
||||
WORKDIR /app
|
||||
|
|
|
@ -2,9 +2,17 @@
|
|||
|
||||
MYSQL_URL=user:password@tcp(localhost)/dbname
|
||||
|
||||
API_ENDPOINT=http://localhost:4001/
|
||||
API_LISTEN_IP=localhost
|
||||
API_LISTEN_PORT=4001
|
||||
|
||||
PUBLIC_ENDPOINT=http://localhost:1234/
|
||||
# The url from which the server can be accessed publicly
|
||||
API_ENDPOINT=http://localhost:4001/
|
||||
UI_ENDPOINT=http://localhost:1234/
|
||||
|
||||
# Set to 1 for the server to also serve the built static ui files
|
||||
SERVE_UI=0
|
||||
# When SERVE_UI is 1, PUBLIC_ENDPOINT is used instead of API_ENDPOINT and UI_ENDPOINT
|
||||
#PUBLIC_ENDPOINT=http://localhost:4001/
|
||||
|
||||
# Set to 1 to set server in development mode, this enables graphql playground
|
||||
# Remove this if running in production
|
||||
|
|
|
@ -2,10 +2,9 @@ package models
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/viktorstrate/photoview/api/utils"
|
||||
)
|
||||
|
||||
type Photo struct {
|
||||
|
@ -66,18 +65,9 @@ func NewPhotosFromRows(rows *sql.Rows) ([]*Photo, error) {
|
|||
|
||||
func (p *PhotoURL) URL() string {
|
||||
|
||||
publicUrl := os.Getenv("PUBLIC_ENDPOINT")
|
||||
if publicUrl == "" {
|
||||
publicUrl = os.Getenv("API_ENDPOINT")
|
||||
}
|
||||
imageUrl := utils.ApiEndpointUrl()
|
||||
imageUrl.Path = path.Join(imageUrl.Path, "photo", p.PhotoName)
|
||||
|
||||
imageUrl, err := url.Parse(publicUrl)
|
||||
if err != nil {
|
||||
log.Println("Endpoint url is not properly configured, make sure the PUBLIC_ENDPOINT AND API_ENDPOINT environment variables are set correctly")
|
||||
return p.PhotoName
|
||||
}
|
||||
|
||||
imageUrl.Path = path.Join(imageUrl.Path, "api", "photo", p.PhotoName)
|
||||
return imageUrl.String()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -16,14 +15,13 @@ import (
|
|||
"github.com/viktorstrate/photoview/api/graphql/auth"
|
||||
"github.com/viktorstrate/photoview/api/routes"
|
||||
"github.com/viktorstrate/photoview/api/server"
|
||||
"github.com/viktorstrate/photoview/api/utils"
|
||||
|
||||
"github.com/99designs/gqlgen/handler"
|
||||
photoview_graphql "github.com/viktorstrate/photoview/api/graphql"
|
||||
"github.com/viktorstrate/photoview/api/graphql/resolvers"
|
||||
)
|
||||
|
||||
const defaultPort = "4001"
|
||||
|
||||
// spaHandler implements the http.Handler interface, so we can use it
|
||||
// to respond to HTTP requests. The path to the static directory and
|
||||
// path to the index file within that static directory are used to
|
||||
|
@ -98,23 +96,19 @@ func main() {
|
|||
Directives: graphqlDirective,
|
||||
}
|
||||
|
||||
endpointURL, err := url.Parse(os.Getenv("API_ENDPOINT"))
|
||||
if err != nil {
|
||||
log.Println("WARN: Environment variable API_ENDPOINT not specified")
|
||||
endpointURL, _ = url.Parse("/")
|
||||
}
|
||||
apiListenUrl := utils.ApiListenUrl()
|
||||
|
||||
endpointRouter := rootRouter.PathPrefix(endpointURL.Path).Subrouter()
|
||||
endpointRouter := rootRouter.PathPrefix(apiListenUrl.Path).Subrouter()
|
||||
|
||||
if devMode {
|
||||
endpointRouter.Handle("/api", handler.Playground("GraphQL playground", path.Join(endpointURL.Path, "/graphql")))
|
||||
endpointRouter.Handle("/", handler.Playground("GraphQL playground", path.Join(apiListenUrl.Path, "/graphql")))
|
||||
} else {
|
||||
endpointRouter.HandleFunc("/api", func(w http.ResponseWriter, req *http.Request) {
|
||||
endpointRouter.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Write([]byte("photoview api endpoint"))
|
||||
})
|
||||
}
|
||||
|
||||
endpointRouter.Handle("/api/graphql",
|
||||
endpointRouter.Handle("/graphql",
|
||||
handler.GraphQL(photoview_graphql.NewExecutableSchema(graphqlConfig),
|
||||
handler.IntrospectionEnabled(devMode),
|
||||
handler.WebsocketUpgrader(server.WebsocketUpgrader(devMode)),
|
||||
|
@ -122,22 +116,28 @@ func main() {
|
|||
),
|
||||
)
|
||||
|
||||
photoRouter := endpointRouter.PathPrefix("/api/photo").Subrouter()
|
||||
photoRouter := endpointRouter.PathPrefix("/photo").Subrouter()
|
||||
routes.RegisterPhotoRoutes(db, photoRouter)
|
||||
|
||||
spa := spaHandler{staticPath: "/ui", indexPath: "index.html"}
|
||||
endpointRouter.PathPrefix("/").Handler(spa)
|
||||
shouldServeUI := os.Getenv("SERVE_UI") == "1"
|
||||
|
||||
if devMode {
|
||||
log.Printf("🚀 Graphql playground ready at %s\n", endpointURL.String())
|
||||
} else {
|
||||
log.Printf("Photoview API endpoint listening at %s\n", endpointURL.String())
|
||||
|
||||
publicEndpoint := os.Getenv("PUBLIC_ENDPOINT")
|
||||
if publicEndpoint != "" && publicEndpoint != endpointURL.String() {
|
||||
log.Printf("Photoview API public endpoint ready at %s\n", publicEndpoint)
|
||||
}
|
||||
if shouldServeUI {
|
||||
spa := spaHandler{staticPath: "/ui", indexPath: "index.html"}
|
||||
rootRouter.PathPrefix("/").Handler(spa)
|
||||
}
|
||||
|
||||
log.Fatal(http.ListenAndServe(":"+endpointURL.Port(), rootRouter))
|
||||
if devMode {
|
||||
log.Printf("🚀 Graphql playground ready at %s\n", apiListenUrl.String())
|
||||
} else {
|
||||
log.Printf("Photoview API endpoint listening at %s\n", apiListenUrl.String())
|
||||
|
||||
uiEndpoint := utils.UiEndpointUrl()
|
||||
apiEndpoint := utils.ApiEndpointUrl()
|
||||
|
||||
log.Printf("Photoview API public endpoint ready at %s\n", apiEndpoint.String())
|
||||
log.Printf("Photoview UI public endpoint ready at %s\n", uiEndpoint.String())
|
||||
|
||||
}
|
||||
|
||||
log.Fatal(http.ListenAndServe(":"+apiListenUrl.Port(), rootRouter))
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/viktorstrate/photoview/api/utils"
|
||||
)
|
||||
|
||||
func CORSMiddleware(devMode bool) mux.MiddlewareFunc {
|
||||
|
@ -22,10 +20,7 @@ func CORSMiddleware(devMode bool) mux.MiddlewareFunc {
|
|||
w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ","))
|
||||
w.Header().Set("Access-Control-Expose-Headers", "content-length")
|
||||
|
||||
endpoint, err := url.Parse(os.Getenv("API_ENDPOINT"))
|
||||
if err != nil {
|
||||
log.Fatalln("Could not parse API_ENDPOINT environment variable as url")
|
||||
}
|
||||
endpoint := utils.ApiEndpointUrl()
|
||||
endpoint.Path = path.Join(endpoint.Path, "graphql")
|
||||
|
||||
if devMode {
|
||||
|
@ -34,12 +29,8 @@ func CORSMiddleware(devMode bool) mux.MiddlewareFunc {
|
|||
w.Header().Set("Vary", "Origin")
|
||||
} else {
|
||||
// Production environment
|
||||
publicEndpoint, err := url.Parse(os.Getenv("PUBLIC_ENDPOINT"))
|
||||
if err != nil {
|
||||
log.Printf("Error parsing environment variable PUBLIC_ENDPOINT as url: %s", err)
|
||||
} else {
|
||||
w.Header().Set("Access-Control-Allow-Origin", publicEndpoint.Scheme+"://"+publicEndpoint.Host)
|
||||
}
|
||||
uiEndpoint := utils.UiEndpointUrl()
|
||||
w.Header().Set("Access-Control-Allow-Origin", uiEndpoint.Scheme+"://"+uiEndpoint.Host)
|
||||
}
|
||||
|
||||
if req.Method != http.MethodOptions {
|
||||
|
|
|
@ -4,9 +4,9 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/viktorstrate/photoview/api/utils"
|
||||
)
|
||||
|
||||
func WebsocketUpgrader(devMode bool) websocket.Upgrader {
|
||||
|
@ -15,11 +15,7 @@ func WebsocketUpgrader(devMode bool) websocket.Upgrader {
|
|||
if devMode {
|
||||
return true
|
||||
} else {
|
||||
pubEndpoint, err := url.Parse(os.Getenv("PUBLIC_ENDPOINT"))
|
||||
if err != nil {
|
||||
log.Printf("Could not parse API_ENDPOINT environment variable as url: %s", err)
|
||||
return false
|
||||
}
|
||||
uiEndpoint := utils.UiEndpointUrl()
|
||||
|
||||
if r.Header.Get("origin") == "" {
|
||||
return true
|
||||
|
@ -31,10 +27,10 @@ func WebsocketUpgrader(devMode bool) websocket.Upgrader {
|
|||
return false
|
||||
}
|
||||
|
||||
if pubEndpoint.Host == originURL.Host {
|
||||
if uiEndpoint.Host == originURL.Host {
|
||||
return true
|
||||
} else {
|
||||
log.Printf("Not allowing websocket request from %s because it doesn't match PUBLIC_ENDPOINT %s", originURL.Host, pubEndpoint.Host)
|
||||
log.Printf("Not allowing websocket request from %s because it doesn't match UI_ENDPOINT %s", originURL.Host, uiEndpoint.Host)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ApiListenUrl() *url.URL {
|
||||
const defaultPort = "4001"
|
||||
|
||||
shouldServeUI := os.Getenv("SERVE_UI") == "1"
|
||||
|
||||
apiPrefix := "/"
|
||||
if shouldServeUI {
|
||||
apiPrefix = "/api"
|
||||
}
|
||||
|
||||
var listenAddr string
|
||||
|
||||
listenAddr = os.Getenv("API_LISTEN_IP")
|
||||
if listenAddr == "" {
|
||||
listenAddr = "127.0.0.1"
|
||||
}
|
||||
|
||||
listenPortStr := os.Getenv("API_LISTEN_PORT")
|
||||
if listenPortStr == "" {
|
||||
listenPortStr = defaultPort
|
||||
}
|
||||
|
||||
listenPort, err := strconv.Atoi(listenPortStr)
|
||||
if err != nil {
|
||||
log.Fatalf("API_LISTEN_PORT must be a number: '%s'\n%s", listenPortStr, err)
|
||||
}
|
||||
|
||||
apiUrl, err := url.Parse(fmt.Sprintf("http://%s:%d", listenAddr, listenPort))
|
||||
if err != nil {
|
||||
log.Fatalf("Could not format api url: %s", err)
|
||||
}
|
||||
apiUrl.Path = apiPrefix
|
||||
|
||||
return apiUrl
|
||||
}
|
||||
|
||||
func ApiEndpointUrl() *url.URL {
|
||||
apiEndpointStr := os.Getenv("API_ENDPOINT")
|
||||
|
||||
shouldServeUI := os.Getenv("SERVE_UI") == "1"
|
||||
if shouldServeUI {
|
||||
apiEndpointStr = os.Getenv("PUBLIC_ENDPOINT")
|
||||
}
|
||||
|
||||
apiEndpointUrl, err := url.Parse(apiEndpointStr)
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR: Environment variable API_ENDPOINT is not a proper url")
|
||||
}
|
||||
|
||||
if shouldServeUI {
|
||||
apiEndpointUrl.Path = path.Join(apiEndpointUrl.Path, "/api")
|
||||
}
|
||||
|
||||
return apiEndpointUrl
|
||||
}
|
||||
|
||||
func UiEndpointUrl() *url.URL {
|
||||
uiEndpointStr := os.Getenv("UI_ENDPOINT")
|
||||
|
||||
shouldServeUI := os.Getenv("SERVE_UI") == "1"
|
||||
if shouldServeUI {
|
||||
uiEndpointStr = os.Getenv("PUBLIC_ENDPOINT")
|
||||
}
|
||||
|
||||
uiEndpointUrl, err := url.Parse(uiEndpointStr)
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR: Environment variable UI_ENDPOINT is not a proper url")
|
||||
}
|
||||
|
||||
return uiEndpointUrl
|
||||
}
|
|
@ -16,7 +16,7 @@ services:
|
|||
build:
|
||||
context: "."
|
||||
args:
|
||||
- GRAPHQL_ENDPOINT=http://localhost:8000/api/graphql
|
||||
- API_ENDPOINT=http://localhost:8000/api/
|
||||
|
||||
restart: always
|
||||
ports:
|
||||
|
@ -26,21 +26,24 @@ services:
|
|||
|
||||
environment:
|
||||
- MYSQL_URL=photoview:photo-secret@tcp(db)/photoview
|
||||
- API_LISTEN_IP=photoview
|
||||
- API_LISTEN_PORT=80
|
||||
- PHOTO_CACHE=/app/cache
|
||||
- SERVE_UI=1
|
||||
|
||||
# Change This: The publicly exposed url for the api
|
||||
# For example if the server is available from the domain example.com,
|
||||
# change this value to http://example.com/api
|
||||
- API_ENDPOINT=http://localhost:80/
|
||||
# change this value to http://example.com/
|
||||
- PUBLIC_ENDPOINT=http://localhost:8000/
|
||||
|
||||
volumes:
|
||||
# Change This: Link photo paths from the host machine
|
||||
- api_cache:/app/cache
|
||||
|
||||
# Change this to the directory where your photos are located on your server.
|
||||
# If the photos are located at `/home/user/photos`, then change this value
|
||||
# to the following: `/home/user/photos:/photos:ro`.
|
||||
# You can mount multiple paths, if your photos are spread across multiple directories.
|
||||
- ./photos_path:/photos:ro
|
||||
- api_cache:/app/cache
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
|
|
|
@ -1 +1 @@
|
|||
GRAPHQL_ENDPOINT=http://localhost:4001/graphql
|
||||
API_ENDPOINT=http://localhost:4001/
|
|
@ -10996,6 +10996,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"url-join": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
|
||||
},
|
||||
"use": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
"semantic-ui-css": "^2.4.1",
|
||||
"semantic-ui-react": "^0.88.0",
|
||||
"styled-components": "^5.0.1",
|
||||
"subscriptions-transport-ws": "^0.9.16"
|
||||
"subscriptions-transport-ws": "^0.9.16",
|
||||
"url-join": "^4.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "parcel start src/index.html",
|
||||
|
|
|
@ -7,17 +7,20 @@ import { setContext } from 'apollo-link-context'
|
|||
import { ApolloLink, split } from 'apollo-link'
|
||||
import { getMainDefinition } from 'apollo-utilities'
|
||||
import { MessageState } from './components/messages/Messages'
|
||||
import urlJoin from 'url-join'
|
||||
|
||||
const GRAPHQL_ENDPOINT = urlJoin(process.env.API_ENDPOINT, '/graphql')
|
||||
|
||||
const httpLink = new HttpLink({
|
||||
uri: process.env.GRAPHQL_ENDPOINT,
|
||||
uri: GRAPHQL_ENDPOINT,
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
|
||||
console.log('GRAPHQL ENDPOINT', process.env.GRAPHQL_ENDPOINT)
|
||||
console.log('API ENDPOINT', process.env.API_ENDPOINT)
|
||||
|
||||
const apiProtocol = new URL(process.env.GRAPHQL_ENDPOINT).protocol
|
||||
const apiProtocol = new URL(process.env.API_ENDPOINT).protocol
|
||||
|
||||
let websocketUri = new URL(process.env.GRAPHQL_ENDPOINT)
|
||||
let websocketUri = new URL(GRAPHQL_ENDPOINT)
|
||||
websocketUri.protocol = apiProtocol === 'https:' ? 'wss:' : 'ws:'
|
||||
|
||||
const wsLink = new WebSocketLink({
|
||||
|
|
Loading…
Reference in New Issue