github.com/readium/readium-lcp-server@v0.0.0-20240509124024-799e77a0bbd6/lsdserver/lsdserver.go (about)

     1  // Copyright 2017 European Digital Reading Lab. All rights reserved.
     2  // Licensed to the Readium Foundation under one or more contributor license agreements.
     3  // Use of this source code is governed by a BSD-style license
     4  // that can be found in the LICENSE file exposed on Github (readium) in the project repository.
     5  
     6  package main
     7  
     8  import (
     9  	"database/sql"
    10  	"fmt"
    11  	"log"
    12  	"os"
    13  	"os/signal"
    14  	"runtime"
    15  	"strconv"
    16  	"strings"
    17  	"syscall"
    18  
    19  	auth "github.com/abbot/go-http-auth"
    20  	_ "github.com/go-sql-driver/mysql"
    21  	_ "github.com/lib/pq"
    22  	_ "github.com/mattn/go-sqlite3"
    23  	_ "github.com/microsoft/go-mssqldb"
    24  
    25  	"github.com/readium/readium-lcp-server/config"
    26  	licensestatuses "github.com/readium/readium-lcp-server/license_statuses"
    27  	"github.com/readium/readium-lcp-server/logging"
    28  	lsdserver "github.com/readium/readium-lcp-server/lsdserver/server"
    29  	"github.com/readium/readium-lcp-server/transactions"
    30  )
    31  
    32  func main() {
    33  	var config_file string
    34  	var readonly bool = false
    35  	var err error
    36  
    37  	if config_file = os.Getenv("READIUM_LSDSERVER_CONFIG"); config_file == "" {
    38  		config_file = "config.yaml"
    39  	}
    40  
    41  	config.ReadConfig(config_file)
    42  	log.Println("Config from " + config_file)
    43  
    44  	readonly = config.Config.LsdServer.ReadOnly
    45  
    46  	err = config.SetPublicUrls()
    47  	if err != nil {
    48  		panic(err)
    49  	}
    50  
    51  	driver, cnxn := config.GetDatabase(config.Config.LsdServer.Database)
    52  	log.Println("Database driver " + driver)
    53  
    54  	db, err := sql.Open(driver, cnxn)
    55  	if err != nil {
    56  		panic(err)
    57  	}
    58  	if driver == "sqlite3" && !strings.Contains(cnxn, "_journal") {
    59  		_, err = db.Exec("PRAGMA journal_mode = WAL")
    60  		if err != nil {
    61  			panic(err)
    62  		}
    63  	}
    64  
    65  	hist, err := licensestatuses.Open(db)
    66  	if err != nil {
    67  		panic(err)
    68  	}
    69  
    70  	trns, err := transactions.Open(db)
    71  	if err != nil {
    72  		panic(err)
    73  	}
    74  
    75  	authFile := config.Config.LsdServer.AuthFile
    76  	if authFile == "" {
    77  		panic("Must have passwords file")
    78  	}
    79  
    80  	_, err = os.Stat(authFile)
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  
    85  	htpasswd := auth.HtpasswdFileProvider(authFile)
    86  	authenticator := auth.NewBasicAuthenticator("Basic Realm", htpasswd)
    87  
    88  	// the server will behave strangely, to test the resilience of LCP compliant apps
    89  	goofyMode := config.Config.GoofyMode
    90  
    91  	// if the logging key is set, logs will be sent to a file and/or Slack channel for test purposes
    92  	err = logging.Init(config.Config.Logging)
    93  	if err != nil {
    94  		panic(err)
    95  	}
    96  
    97  	HandleSignals()
    98  
    99  	parsedPort := strconv.Itoa(config.Config.LsdServer.Port)
   100  	s := lsdserver.New(":"+parsedPort, readonly, goofyMode, &hist, &trns, authenticator)
   101  	if readonly {
   102  		log.Println("License status server running in readonly mode on port " + parsedPort)
   103  	} else {
   104  		log.Println("License status server running on port " + parsedPort)
   105  	}
   106  	log.Println("Public base URL=" + config.Config.LsdServer.PublicBaseUrl)
   107  
   108  	if err := s.ListenAndServe(); err != nil {
   109  		log.Println("Error " + err.Error())
   110  	}
   111  
   112  }
   113  
   114  func HandleSignals() {
   115  	sigChan := make(chan os.Signal)
   116  	go func() {
   117  		stacktrace := make([]byte, 1<<20)
   118  		for sig := range sigChan {
   119  			switch sig {
   120  			case syscall.SIGQUIT:
   121  				length := runtime.Stack(stacktrace, true)
   122  				fmt.Println(string(stacktrace[:length]))
   123  			case syscall.SIGINT:
   124  				fallthrough
   125  			case syscall.SIGTERM:
   126  				fmt.Println("Shutting down...")
   127  				os.Exit(0)
   128  			}
   129  		}
   130  	}()
   131  
   132  	signal.Notify(sigChan, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM)
   133  }