A basic physics simulator made as part of revision for a physics course
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.5 KiB

package main
import (
func main() {
// Inject config into the router. This should run before doing anything
// with the router.
routes.SharedMemory["conf"] = CONF
// Also inject the signal channel to allow routes to request exit
routes.SharedMemory["sigchan"] = make(chan os.Signal, 1)
// While we're at it, forward signals from C to that channel
signal.Notify(routes.SharedMemory["sigchan"].(chan os.Signal),
// Determine the address to listen on
addr := ""
if CONF["LOCAL_ONLY"] == true {
addr = ""
} else if _, exists := CONF["LISTEN_ADDR"]; exists {
addr = fmt.Sprint(CONF["LISTEN_ADDR"])
// Determine the port to listen on
port := 8080
if _, exists := CONF["LISTEN_PORT"]; exists {
port = CONF["LISTEN_PORT"].(int)
// Create a HTTP server
listen := fmt.Sprintf("%s:%d", addr, port)
srv := http.Server{Addr: listen}
// Register the route handlers to their correct routes
for route, handler := range routes.RouteHandlers {
http.HandleFunc(route, handler)
// Start server
fmt.Printf("Starting GoPhysicsLab server on `%s`\n", listen)
go srv.ListenAndServe()
// If configured to, start the browser pointing to this server
// Don't use `addr` as it is sometimes blank or which we can't connect to
// Instead, it most cases the program will listen on localhost anyway
if val, ok := CONF["OPEN_BROWSER_ON_RUN"]; ok && val.(bool) {
browser.OpenURL(fmt.Sprintf("http://localhost:%d", port))
// Catch signals and exit gracefully upon receiving one. While we don't check the type
// of signal here, only exit signals are passed to this channel so there is no need
sig := <-routes.SharedMemory["sigchan"].(chan os.Signal)
// If another signal comes through, force exit
go func() {
sig := <-routes.SharedMemory["sigchan"].(chan os.Signal)
fmt.Printf("Received follow-up signal (`%s`). Forcing exit.\n", sig.String())
fmt.Printf("Received signal (`%s`). Exiting cleanly with timeout of 5 seconds. Resend to force exit.\n", sig.String())
// Tell HTTP server to exit with a timeout of 5 seconds
timeout := time.Duration(5 * time.Second)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
err := srv.Shutdown(ctx)
if err != nil {
fmt.Printf("Shutting down the HTTP server failed with error (`%s`) but we will exit anyway.\n", err.Error())