2022-01-09 05:27:18 +01:00
package main
import (
"encoding/json"
"fmt"
2022-04-06 08:31:24 +02:00
"io/ioutil"
2022-04-07 03:18:46 +02:00
"log"
2022-01-09 05:27:18 +01:00
"net/http"
2022-04-08 05:59:40 +02:00
"os"
2022-01-09 05:27:18 +01:00
2022-01-09 06:59:28 +01:00
"github.com/ddworken/hishtory/shared"
2022-03-30 06:56:28 +02:00
_ "github.com/lib/pq"
"gorm.io/driver/postgres"
2022-04-06 08:31:24 +02:00
"gorm.io/driver/sqlite"
2022-03-30 06:56:28 +02:00
"gorm.io/gorm"
)
const (
POSTGRES_DB = "postgresql://postgres:O74Ji4735C@postgres-postgresql.default.svc.cluster.local:5432/hishtory?sslmode=disable"
2022-01-09 06:59:28 +01:00
)
2022-01-09 05:27:18 +01:00
2022-04-03 07:27:20 +02:00
var GLOBAL_DB * gorm . DB
func apiESubmitHandler ( w http . ResponseWriter , r * http . Request ) {
2022-04-06 08:31:24 +02:00
data , err := ioutil . ReadAll ( r . Body )
2022-03-30 06:56:28 +02:00
if err != nil {
panic ( err )
}
2022-04-06 08:31:24 +02:00
var entries [ ] shared . EncHistoryEntry
err = json . Unmarshal ( data , & entries )
if err != nil {
panic ( fmt . Sprintf ( "body=%#v, err=%v" , data , err ) )
}
2022-04-04 05:55:37 +02:00
GLOBAL_DB . Where ( "user_id = ?" )
2022-04-07 07:43:07 +02:00
fmt . Printf ( "apiESubmitHandler: received request containg %d EncHistoryEntry\n" , len ( entries ) )
2022-04-03 07:27:20 +02:00
for _ , entry := range entries {
2022-04-03 19:08:18 +02:00
tx := GLOBAL_DB . Where ( "user_id = ?" , entry . UserId )
2022-04-04 05:55:37 +02:00
var devices [ ] * shared . Device
2022-04-03 19:08:18 +02:00
result := tx . Find ( & devices )
if result . Error != nil {
panic ( fmt . Errorf ( "DB query error: %v" , result . Error ) )
}
2022-04-04 05:55:37 +02:00
if len ( devices ) == 0 {
2022-04-08 06:40:22 +02:00
panic ( fmt . Errorf ( "found no devices associated with user_id=%s, can't save history entry" , entry . UserId ) )
2022-04-03 19:08:18 +02:00
}
2022-04-07 07:43:07 +02:00
fmt . Printf ( "apiESubmitHandler: Found %d devices\n" , len ( devices ) )
2022-04-03 19:08:18 +02:00
for _ , device := range devices {
2022-04-04 05:55:37 +02:00
entry . DeviceId = device . DeviceId
2022-04-07 07:43:07 +02:00
result := GLOBAL_DB . Create ( & entry )
if result . Error != nil {
panic ( result . Error )
}
2022-04-03 19:08:18 +02:00
}
2022-04-03 07:27:20 +02:00
}
}
func apiEQueryHandler ( w http . ResponseWriter , r * http . Request ) {
deviceId := r . URL . Query ( ) . Get ( "device_id" )
2022-04-04 05:55:37 +02:00
// Increment the count
2022-04-03 07:27:20 +02:00
GLOBAL_DB . Exec ( "UPDATE enc_history_entries SET read_count = read_count + 1 WHERE device_id = ?" , deviceId )
// Then retrieve, to avoid a race condition
tx := GLOBAL_DB . Where ( "device_id = ?" , deviceId )
var historyEntries [ ] * shared . EncHistoryEntry
result := tx . Find ( & historyEntries )
if result . Error != nil {
panic ( fmt . Errorf ( "DB query error: %v" , result . Error ) )
}
2022-04-07 07:43:07 +02:00
fmt . Printf ( "apiEQueryHandler: Found %d entries\n" , len ( historyEntries ) )
2022-04-03 07:27:20 +02:00
resp , err := json . Marshal ( historyEntries )
if err != nil {
panic ( err )
}
w . Write ( resp )
}
2022-04-06 08:31:24 +02:00
// TODO: bootstrap is a janky solution for the initial version of this. Long term, need to support deleting entries from the DB which means replacing bootstrap with a queued message sent to any live instances.
2022-04-03 07:27:20 +02:00
func apiEBootstrapHandler ( w http . ResponseWriter , r * http . Request ) {
userId := r . URL . Query ( ) . Get ( "user_id" )
tx := GLOBAL_DB . Where ( "user_id = ?" , userId )
var historyEntries [ ] * shared . EncHistoryEntry
result := tx . Find ( & historyEntries )
if result . Error != nil {
panic ( fmt . Errorf ( "DB query error: %v" , result . Error ) )
}
resp , err := json . Marshal ( historyEntries )
2022-01-09 05:27:18 +01:00
if err != nil {
panic ( err )
}
2022-04-03 07:27:20 +02:00
w . Write ( resp )
}
2022-04-03 19:08:18 +02:00
func apiERegisterHandler ( w http . ResponseWriter , r * http . Request ) {
userId := r . URL . Query ( ) . Get ( "user_id" )
deviceId := r . URL . Query ( ) . Get ( "device_id" )
GLOBAL_DB . Create ( & shared . Device { UserId : userId , DeviceId : deviceId } )
2022-01-09 05:27:18 +01:00
}
2022-04-07 07:43:07 +02:00
func apiBannerHandler ( w http . ResponseWriter , r * http . Request ) {
commitHash := r . URL . Query ( ) . Get ( "commit_hash" )
deviceId := r . URL . Query ( ) . Get ( "device_id" )
forcedBanner := r . URL . Query ( ) . Get ( "forced_banner" )
fmt . Printf ( "apiBannerHandler: commit_hash=%#v, device_id=%#v, forced_banner=%#v\n" , commitHash , deviceId , forcedBanner )
w . Write ( [ ] byte ( forcedBanner ) )
}
2022-04-08 05:59:40 +02:00
func isTestEnvironment ( ) bool {
return os . Getenv ( "HISHTORY_TEST" ) != ""
}
2022-03-30 06:56:28 +02:00
func OpenDB ( ) ( * gorm . DB , error ) {
2022-04-08 05:59:40 +02:00
if isTestEnvironment ( ) {
2022-04-06 08:31:24 +02:00
db , err := gorm . Open ( sqlite . Open ( "file::memory:?cache=shared" ) , & gorm . Config { } )
if err != nil {
return nil , fmt . Errorf ( "failed to connect to the DB: %v" , err )
}
db . AutoMigrate ( & shared . EncHistoryEntry { } )
db . AutoMigrate ( & shared . Device { } )
return db , nil
2022-03-30 06:56:28 +02:00
}
db , err := gorm . Open ( postgres . Open ( POSTGRES_DB ) , & gorm . Config { } )
if err != nil {
return nil , fmt . Errorf ( "failed to connect to the DB: %v" , err )
}
2022-04-03 07:27:20 +02:00
db . AutoMigrate ( & shared . EncHistoryEntry { } )
db . AutoMigrate ( & shared . Device { } )
2022-03-30 06:56:28 +02:00
return db , nil
}
2022-04-03 07:27:20 +02:00
func init ( ) {
2022-04-03 07:54:09 +02:00
InitDB ( )
}
func InitDB ( ) {
2022-04-03 07:27:20 +02:00
var err error
GLOBAL_DB , err = OpenDB ( )
2022-01-09 05:27:18 +01:00
if err != nil {
panic ( err )
}
2022-04-03 07:27:20 +02:00
tx , err := GLOBAL_DB . DB ( )
if err != nil {
panic ( err )
}
err = tx . Ping ( )
if err != nil {
panic ( err )
}
}
func main ( ) {
2022-01-09 05:27:18 +01:00
fmt . Println ( "Listening on localhost:8080" )
2022-04-03 07:27:20 +02:00
http . HandleFunc ( "/api/v1/esubmit" , apiESubmitHandler )
http . HandleFunc ( "/api/v1/equery" , apiEQueryHandler )
http . HandleFunc ( "/api/v1/ebootstrap" , apiEBootstrapHandler )
2022-04-03 19:08:18 +02:00
http . HandleFunc ( "/api/v1/eregister" , apiERegisterHandler )
2022-04-07 07:43:07 +02:00
http . HandleFunc ( "/api/v1/banner" , apiBannerHandler )
2022-01-09 05:27:18 +01:00
log . Fatal ( http . ListenAndServe ( ":8080" , nil ) )
}