diff --git a/.gitignore b/.gitignore index f8570a4397f29573a951604cabb93db9762f742c..0155fe2c0bb82aff7f369a0ea1ba6a7a1b273473 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.idea/ /vendor/ -/node_modules/ \ No newline at end of file +/node_modules/ +/config.yaml diff --git a/api/album_get.go b/api/album_get.go new file mode 100644 index 0000000000000000000000000000000000000000..741a40a7fbd1b85f4951dda190416eb3ece9edc8 --- /dev/null +++ b/api/album_get.go @@ -0,0 +1,25 @@ +package api + +import ( + "database/sql" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "github.com/gorilla/mux" + "net/http" +) + +func GetAlbum(env environment.Environment) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + vars := mux.Vars(request) + album, err := env.Repositories.Albums.Get(vars["albumId"]) + if err == sql.ErrNoRows { + http.NotFound(writer, request) + return + } else if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return + } + + util.ReturnJson(writer, album) + }) +} diff --git a/api/album_list.go b/api/album_list.go new file mode 100644 index 0000000000000000000000000000000000000000..94297599d14ea952ec9bb477f323af47fdd5f35b --- /dev/null +++ b/api/album_list.go @@ -0,0 +1,28 @@ +package api + +import ( + "database/sql" + "git.kuschku.de/justjanne/imghost-frontend/auth" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "net/http" +) + +func ListAlbums(env environment.Environment) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + user, err := auth.ParseUser(request, env) + if err != nil { + http.Error(writer, err.Error(), http.StatusUnauthorized) + } + albums, err := env.Repositories.Albums.List(user) + if err == sql.ErrNoRows { + http.NotFound(writer, request) + return + } else if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return + } + + util.ReturnJson(writer, albums) + }) +} diff --git a/api/albumimage_get.go b/api/albumimage_get.go new file mode 100644 index 0000000000000000000000000000000000000000..f14085618201a84e1158b1c6f0a88a5f629cb5c8 --- /dev/null +++ b/api/albumimage_get.go @@ -0,0 +1,25 @@ +package api + +import ( + "database/sql" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "github.com/gorilla/mux" + "net/http" +) + +func GetAlbumImage(env environment.Environment) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + vars := mux.Vars(request) + albumImage, err := env.Repositories.AlbumImages.Get(vars["albumId"], vars["imageId"]) + if err == sql.ErrNoRows { + http.NotFound(writer, request) + return + } else if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return + } + + util.ReturnJson(writer, albumImage) + }) +} diff --git a/api/albumimage_list.go b/api/albumimage_list.go new file mode 100644 index 0000000000000000000000000000000000000000..5b284df51aeec03a6f2317e4f9f9adaa5089e1b6 --- /dev/null +++ b/api/albumimage_list.go @@ -0,0 +1,25 @@ +package api + +import ( + "database/sql" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "github.com/gorilla/mux" + "net/http" +) + +func ListAlbumImages(env environment.Environment) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + vars := mux.Vars(request) + albumImages, err := env.Repositories.AlbumImages.List(vars["albumId"]) + if err == sql.ErrNoRows { + http.NotFound(writer, request) + return + } else if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return + } + + util.ReturnJson(writer, albumImages) + }) +} diff --git a/api/image_get.go b/api/image_get.go new file mode 100644 index 0000000000000000000000000000000000000000..9ec538a5e1a1e441e86dc66181f617e8e5f3fe58 --- /dev/null +++ b/api/image_get.go @@ -0,0 +1,25 @@ +package api + +import ( + "database/sql" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "github.com/gorilla/mux" + "net/http" +) + +func GetImage(env environment.Environment) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + vars := mux.Vars(request) + image, err := env.Repositories.Images.Get(vars["imageId"]) + if err == sql.ErrNoRows { + http.NotFound(writer, request) + return + } else if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return + } + + util.ReturnJson(writer, image) + }) +} diff --git a/api/image_list.go b/api/image_list.go new file mode 100644 index 0000000000000000000000000000000000000000..4148b4c397d18a72fc08fef13f93a71fd2dbe32e --- /dev/null +++ b/api/image_list.go @@ -0,0 +1,28 @@ +package api + +import ( + "database/sql" + "git.kuschku.de/justjanne/imghost-frontend/auth" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "net/http" +) + +func ListImages(env environment.Environment) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + user, err := auth.ParseUser(request, env) + if err != nil { + http.Error(writer, err.Error(), http.StatusUnauthorized) + } + images, err := env.Repositories.Images.List(user) + if err == sql.ErrNoRows { + http.NotFound(writer, request) + return + } else if err != nil { + http.Error(writer, err.Error(), http.StatusInternalServerError) + return + } + + util.ReturnJson(writer, images) + }) +} diff --git a/auth/parse_user.go b/auth/parse_user.go new file mode 100644 index 0000000000000000000000000000000000000000..fab59f358297cc588c9953380c3b989676dae78c --- /dev/null +++ b/auth/parse_user.go @@ -0,0 +1,19 @@ +package auth + +import ( + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/model" + "net/http" +) + +func ParseUser(request *http.Request, env environment.Environment) (user model.User, err error) { + // TODO: Implement actual user auth + user = model.User{ + Id: "ad45284c-be4d-4546-8171-41cf126ac091", + Name: "justJanne", + Email: "janne@kuschku.de", + Roles: []string{"imghost:user", "imghost:admin"}, + } + + return +} diff --git a/cmd/backend/main.go b/cmd/backend/main.go new file mode 100644 index 0000000000000000000000000000000000000000..102b6d20d7f308be5caec65accfd69df35a0aac9 --- /dev/null +++ b/cmd/backend/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "git.kuschku.de/justjanne/imghost-frontend/configuration" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/task" + "github.com/hibiken/asynq" + _ "github.com/lib/pq" + "gopkg.in/yaml.v2" + "log" + "os" +) + +func main() { + var config configuration.Configuration + configFile, err := os.Open("config.yaml") + if err != nil { + panic(err) + } + err = yaml.NewDecoder(configFile).Decode(&config) + if err != nil { + panic(err) + } + + env, err := environment.NewServerEnvironment(config) + if err != nil { + panic(err) + } + defer env.Destroy() + + mux := asynq.NewServeMux() + mux.HandleFunc(config.Conversion.ResizeTaskId, task.HandleImageResizeTask) + if err := env.QueueServer.Run(mux); err != nil { + log.Fatalf("could not run server: %v", err) + } +} diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go new file mode 100644 index 0000000000000000000000000000000000000000..d101b770cf7f8257e8ee406da7ef38739aa07ea1 --- /dev/null +++ b/cmd/frontend/main.go @@ -0,0 +1,62 @@ +package main + +import ( + "git.kuschku.de/justjanne/imghost-frontend/api" + "git.kuschku.de/justjanne/imghost-frontend/configuration" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/util" + "github.com/gorilla/mux" + _ "github.com/lib/pq" + "gopkg.in/yaml.v2" + "net/http" + "os" +) + +func main() { + var config configuration.Configuration + configFile, err := os.Open("config.yaml") + if err != nil { + panic(err) + } + err = yaml.NewDecoder(configFile).Decode(&config) + if err != nil { + panic(err) + } + + env, err := environment.NewClientEnvironment(config) + if err != nil { + panic(err) + } + defer env.Destroy() + + router := mux.NewRouter() + // Image API + router.Handle( + "/api/v1/images", + api.ListImages(env)).Methods(http.MethodGet) + router.Handle( + "/api/v1/images/{imageId}", + api.GetImage(env)).Methods(http.MethodGet) + + // Album API + router.Handle( + "/api/v1/albums", + api.ListAlbums(env)).Methods(http.MethodGet) + router.Handle( + "/api/v1/albums/{imageId}", + api.GetAlbum(env)).Methods(http.MethodGet) + + // Album Image API + router.Handle( + "/api/v1/albums/{albumId}/images", + api.ListAlbumImages(env)).Methods(http.MethodGet) + router.Handle( + "/api/v1/albums/{albumId}/images/{imageId}", + api.GetAlbumImage(env)).Methods(http.MethodGet) + + // TODO: Implement mutating API methods + + if err = http.ListenAndServe(":8080", util.MethodOverride(router)); err != nil { + panic(err) + } +} diff --git a/config.example.yaml b/config.example.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1d7a960372dd7c09dd5fbe765c590cd53ec72dda --- /dev/null +++ b/config.example.yaml @@ -0,0 +1,65 @@ +auth: + role_prefix: "imghost" + +queue: + concurrency: 10 + log_level: "info" + strict_priority: false + queues: + critical: 6 + default: 3 + low: 1 + +database: + type: "postgres" + url: "postgresql://imghost:hunter2@db.example.com/imghost" + +redis: + address: ":6379" + password: "" + +conversion: + task_id: "image:resize" + max_retry: 10 + timeout: "3m" + queue: "default" + unique_timeout: "3m" + quality: + compression_quality: 100 + sampling_factors: [ 1,1 ] + sizes: + - suffix: "s" + size: + width: 90 + height: 90 + format: "cover" + - suffix: "b" + size: + width: 160 + height: 160 + format: "cover" + - suffix: "t" + size: + width: 160 + height: 160 + format: "contain" + - suffix: "m" + size: + width: 320 + height: 320 + format: "contain" + - suffix: "l" + size: + width: 640 + height: 640 + format: "contain" + - suffix: "h" + size: + width: 1024 + height: 1024 + format: "contain" + - suffix: "" + size: + width: 0 + height: 0 + format: "contain" diff --git a/configuration/auth.go b/configuration/auth.go new file mode 100644 index 0000000000000000000000000000000000000000..d87ba42206f59a5823efef06f9f1f049723df6d2 --- /dev/null +++ b/configuration/auth.go @@ -0,0 +1,5 @@ +package configuration + +type AuthConfiguration struct { + RolePrefix string `json:"role_prefix"` +} diff --git a/configuration/configuration.go b/configuration/configuration.go new file mode 100644 index 0000000000000000000000000000000000000000..42558aec55f779c4794b9b9ab85c25b201bdac2a --- /dev/null +++ b/configuration/configuration.go @@ -0,0 +1,9 @@ +package configuration + +type Configuration struct { + Queue QueueConfiguration `json:"queue"` + Database DatabaseConfiguration `json:"database"` + Redis RedisConfiguration `json:"redis"` + Conversion ConversionConfiguration `json:"conversion"` + Auth AuthConfiguration `json:"auth"` +} diff --git a/configuration/conversion.go b/configuration/conversion.go new file mode 100644 index 0000000000000000000000000000000000000000..11d896d999970378d524fcad13a6de941304ee51 --- /dev/null +++ b/configuration/conversion.go @@ -0,0 +1,16 @@ +package configuration + +import ( + "git.kuschku.de/justjanne/imghost-frontend/configuration/types" + "github.com/justjanne/imgconv" +) + +type ConversionConfiguration struct { + TaskId string `json:"task_id"` + MaxRetry int `json:"max_retry"` + Timeout types.Timeout `json:"timeout"` + Queue string `json:"queue"` + UniqueTimeout types.Timeout `json:"unique_timeout"` + Quality imgconv.Quality `json:"quality"` + Sizes []imgconv.Size `json:"sizes"` +} diff --git a/configuration/database.go b/configuration/database.go new file mode 100644 index 0000000000000000000000000000000000000000..2719adde14ac94a52f5c04153ada1ed69ba5baac --- /dev/null +++ b/configuration/database.go @@ -0,0 +1,6 @@ +package configuration + +type DatabaseConfiguration struct { + Type string `json:"type"` + Url string `json:"url"` +} diff --git a/configuration/queue.go b/configuration/queue.go new file mode 100644 index 0000000000000000000000000000000000000000..b10105c5f7f705079a702c641166c9c2173bb9f1 --- /dev/null +++ b/configuration/queue.go @@ -0,0 +1,10 @@ +package configuration + +import "git.kuschku.de/justjanne/imghost-frontend/configuration/types" + +type QueueConfiguration struct { + Concurrency int `json:"concurrency"` + LogLevel types.Severity `json:"log_level"` + StrictPriority bool `json:"strict_priority"` + Queues map[string]int `json:"queues"` +} diff --git a/configuration/redis.go b/configuration/redis.go new file mode 100644 index 0000000000000000000000000000000000000000..cb9381858fd63b632bae66bef8dea8dc33044ce8 --- /dev/null +++ b/configuration/redis.go @@ -0,0 +1,6 @@ +package configuration + +type RedisConfiguration struct { + Address string `json:"address"` + Password string `json:"password"` +} diff --git a/configuration/types/loglevel.go b/configuration/types/loglevel.go new file mode 100644 index 0000000000000000000000000000000000000000..8338ad7086843d357c953cddef324dfa0c54156e --- /dev/null +++ b/configuration/types/loglevel.go @@ -0,0 +1,24 @@ +package types + +import ( + "github.com/hibiken/asynq" +) + +type Severity asynq.LogLevel + +func (severity *Severity) UnmarshalYAML(unmarshal func(interface{}) error) error { + var spec string + if err := unmarshal(&spec); err != nil { + return err + } + + var loglevel asynq.LogLevel + err := loglevel.Set(spec) + if err != nil { + return err + } + + *severity = Severity(loglevel) + + return nil +} diff --git a/configuration/types/timeout.go b/configuration/types/timeout.go new file mode 100644 index 0000000000000000000000000000000000000000..8a988e31491eb2115f24126ff10b5a97889cca64 --- /dev/null +++ b/configuration/types/timeout.go @@ -0,0 +1,21 @@ +package types + +import "time" + +type Timeout time.Duration + +func (timeout *Timeout) UnmarshalYAML(unmarshal func(interface{}) error) error { + var spec string + if err := unmarshal(&spec); err != nil { + return err + } + + duration, err := time.ParseDuration(spec) + if err != nil { + return err + } + + *timeout = Timeout(duration) + + return nil +} diff --git a/environment/environment.go b/environment/environment.go index 114924aa50eefea902fee010aa3e5722887acbea..31a0e4e8d1f843e7f1fd5856ff73d02b393f9d2b 100644 --- a/environment/environment.go +++ b/environment/environment.go @@ -1,62 +1,88 @@ package environment import ( - "encoding/json" + "git.kuschku.de/justjanne/imghost-frontend/configuration" + "git.kuschku.de/justjanne/imghost-frontend/repo" "github.com/hibiken/asynq" "github.com/jmoiron/sqlx" - "github.com/justjanne/imgconv" - "os" + "time" ) type Environment struct { - Queue *asynq.Client - Database *sqlx.DB - RolePrefix string - Sizes []imgconv.Size - Quality imgconv.Quality + Configuration configuration.Configuration + QueueClient *asynq.Client + QueueServer *asynq.Server + Database *sqlx.DB + Repositories Repositories } -func NewEnvironment( - redisAddress string, - dbType string, - dbUrl string, - rolePrefix string, - sizes []imgconv.Size, - quality imgconv.Quality, -) (env Environment, err error) { - env.Queue = asynq.NewClient(asynq.RedisClientOpt{ - Addr: redisAddress, - }) - env.Database, err = sqlx.Open(dbType, dbUrl) - env.RolePrefix = rolePrefix - env.Sizes = sizes - env.Quality = quality - return -} - -func InitializeEnvironment() (env Environment, err error) { - var sizes []imgconv.Size - if err = json.Unmarshal([]byte(os.Getenv("CONFIG_SIZES")), &sizes); err != nil { +func newCommonEnvironment(config configuration.Configuration) (env Environment, err error) { + env.Configuration = config + if env.Database, err = sqlx.Open(config.Database.Type, config.Database.Url); err != nil { + return + } + if env.Repositories.Images, err = repo.NewImageRepo(env.Database); err != nil { + return + } + if env.Repositories.Albums, err = repo.NewAlbumRepo(env.Database); err != nil { return } - var quality imgconv.Quality - if err = json.Unmarshal([]byte(os.Getenv("CONFIG_QUALITY")), &quality); err != nil { + if env.Repositories.AlbumImages, err = repo.NewAlbumImageRepo(env.Database); err != nil { return } - rolePrefix := os.Getenv("CONFIG_ROLE_PREFIX") + return +} - redisAddress := os.Getenv("REDIS_ADDRESS") - dbType := os.Getenv("DB_TYPE") - dbUrl := os.Getenv("DB_URL") - return NewEnvironment(redisAddress, dbType, dbUrl, rolePrefix, sizes, quality) +func NewClientEnvironment(config configuration.Configuration) (Environment, error) { + env, err := newCommonEnvironment(config) + if err != nil { + return env, err + } + env.QueueClient = asynq.NewClient(asynq.RedisClientOpt{ + Addr: config.Redis.Address, + Password: config.Redis.Password, + }) + env.QueueClient.SetDefaultOptions( + config.Conversion.TaskId, + asynq.MaxRetry(config.Conversion.MaxRetry), + asynq.Timeout(time.Duration(config.Conversion.Timeout)), + asynq.Queue(config.Conversion.Queue), + asynq.Unique(time.Duration(config.Conversion.UniqueTimeout)), + ) + return env, err } -func (env Environment) Destroy() error { - if err := env.Queue.Close(); err != nil { - return err +func NewServerEnvironment(config configuration.Configuration) (Environment, error) { + env, err := newCommonEnvironment(config) + if err != nil { + return env, err } + env.QueueServer = asynq.NewServer( + asynq.RedisClientOpt{ + Addr: config.Redis.Address, + Password: config.Redis.Password, + }, + asynq.Config{ + Concurrency: config.Queue.Concurrency, + LogLevel: asynq.LogLevel(config.Queue.LogLevel), + Queues: config.Queue.Queues, + StrictPriority: config.Queue.StrictPriority, + }, + ) + return env, err +} + +func (env Environment) Destroy() error { if err := env.Database.Close(); err != nil { return err } + if env.QueueClient != nil { + if err := env.QueueClient.Close(); err != nil { + return err + } + } + if env.QueueServer != nil { + env.QueueServer.Shutdown() + } return nil } diff --git a/environment/repositories.go b/environment/repositories.go new file mode 100644 index 0000000000000000000000000000000000000000..ff2a7ec5efc15f5bb91d508d5b03ff03d1c02cb8 --- /dev/null +++ b/environment/repositories.go @@ -0,0 +1,9 @@ +package environment + +import "git.kuschku.de/justjanne/imghost-frontend/repo" + +type Repositories struct { + Images repo.Images + Albums repo.Albums + AlbumImages repo.AlbumImages +} diff --git a/go.mod b/go.mod index 96db1b4367823f02aad20f4964a48c1f05b8eb34..3698c097a3a8052edf61a3b274f4a205dcb7e9d0 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.kuschku.de/justjanne/imghost-frontend go 1.13 require ( + github.com/gorilla/mux v1.8.0 // indirect github.com/hibiken/asynq v0.18.2 github.com/jmoiron/sqlx v1.3.4 github.com/justjanne/imgconv v1.0.3 // indirect diff --git a/go.sum b/go.sum index 190c08b6451b72e1f0b75aaf35d5a69b58cec899..89853b5398e92ea7417be07b08f09745cc4b68a2 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hibiken/asynq v0.18.2 h1:hbLVygnmQMc2evTmNildtUWaUPHIBtggA59MoaHp/bY= github.com/hibiken/asynq v0.18.2/go.mod h1:Sn3Ql1clxIO5kXoFOAE3W73tX81Hkau+2Kam9LfgymM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= diff --git a/main.go b/main.go deleted file mode 100644 index e5a5af7d474fcb5ec5cd8d632efc946cc369ce03..0000000000000000000000000000000000000000 --- a/main.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "fmt" - "git.kuschku.de/justjanne/imghost-frontend/environment" - "git.kuschku.de/justjanne/imghost-frontend/model" - "git.kuschku.de/justjanne/imghost-frontend/repo" - _ "github.com/lib/pq" -) - -func main() { - user := model.User{ - Id: "ad45284c-be4d-4546-8171-41cf126ac091", - Name: "justJanne", - Email: "janne@kuschku.de", - Roles: []string{"imghost:user", "imghost:admin"}, - } - - var env environment.Environment - env, err := environment.InitializeEnvironment() - if err != nil { - panic(err) - } - defer env.Destroy() - - imageRepo, err := repo.NewImageRepo(env.Database) - if err != nil { - panic(err) - } - - albumRepo, err := repo.NewAlbumRepo(env.Database) - if err != nil { - panic(err) - } - - albumImageRepo, err := repo.NewAlbumImageRepo(env.Database) - if err != nil { - panic(err) - } - - images, err := imageRepo.List(user) - if err != nil { - panic(err) - } - fmt.Printf("images: %v\n", len(images)) - - albums, err := albumRepo.List(user) - if err != nil { - panic(err) - } - fmt.Printf("albums: %v\n", len(albums)) - - albumImages, err := albumImageRepo.List(model.Album{}) - if err != nil { - panic(err) - } - fmt.Printf("albumImages: %v\n", len(albumImages)) -} diff --git a/repo/album_images.go b/repo/album_images.go index 9cfdbc590d692dfc189615c018495a2cb7375e56..b58a0a164fd69902d8589f940e6597a80f860f8d 100644 --- a/repo/album_images.go +++ b/repo/album_images.go @@ -71,9 +71,9 @@ func NewAlbumImageRepo(db *sqlx.DB) (repo AlbumImages, err error) { return repo, nil } -func (repo AlbumImages) List(album model.Album) (images []model.AlbumImage, err error) { +func (repo AlbumImages) List(albumId string) (images []model.AlbumImage, err error) { rows, err := repo.queryList.Queryx(map[string]interface{}{ - "albumId": album.Id, + "albumId": albumId, }) if err != nil { return @@ -89,9 +89,9 @@ func (repo AlbumImages) List(album model.Album) (images []model.AlbumImage, err return } -func (repo AlbumImages) Get(album model.Album, imageId string) (image model.AlbumImage, err error) { +func (repo AlbumImages) Get(albumId string, imageId string) (image model.AlbumImage, err error) { err = repo.queryGet.Get(&image, map[string]interface{}{ - "albumId": album.Id, + "albumId": albumId, "imageId": imageId, }) return diff --git a/s3/upload_source.go b/s3/upload_source.go new file mode 100644 index 0000000000000000000000000000000000000000..8393c1767ba08746c9cf8e3ce224e412bd54c8c1 --- /dev/null +++ b/s3/upload_source.go @@ -0,0 +1,19 @@ +package s3 + +import ( + "git.kuschku.de/justjanne/imghost-frontend/environment" + "github.com/justjanne/imgconv" +) + +// TODO: Implement +func UploadSource(env environment.Environment, imageId string, source string) error { + return nil +} + +func DownloadSource(env environment.Environment, imageId string) (string, error) { + return "", nil +} + +func UploadImage(env environment.Environment, imageId string, format imgconv.Size, source string) error { + return nil +} diff --git a/task/image_resize.go b/task/image_resize.go index 1e140b2e4adb49d78fb2a655774fb70651f3f2b2..99021ccca05d33d55b08f760fabcc50fd1887e2f 100644 --- a/task/image_resize.go +++ b/task/image_resize.go @@ -3,34 +3,38 @@ package task import ( "context" "encoding/json" + "git.kuschku.de/justjanne/imghost-frontend/configuration" + "git.kuschku.de/justjanne/imghost-frontend/environment" + "git.kuschku.de/justjanne/imghost-frontend/s3" "git.kuschku.de/justjanne/imghost-frontend/util" "github.com/hibiken/asynq" "github.com/justjanne/imgconv" "gopkg.in/gographics/imagick.v2/imagick" ) -const TypeImageResize = "image:Resize" - type ImageResizePayload struct { ImageId string Sizes []imgconv.Size Quality imgconv.Quality } -func NewResizeTask(imageId string, sizes []imgconv.Size, quality imgconv.Quality) (task *asynq.Task, err error) { +func NewResizeTask(imageId string, config configuration.Configuration) (task *asynq.Task, err error) { payload, err := json.Marshal(ImageResizePayload{ ImageId: imageId, - Sizes: sizes, - Quality: quality, + Sizes: config.Conversion.Sizes, + Quality: config.Conversion.Quality, }) if err != nil { return } - task = asynq.NewTask(TypeImageResize, payload) + task = asynq.NewTask(config.Conversion.ResizeTaskId, payload) return } func HandleImageResizeTask(ctx context.Context, task *asynq.Task) (err error) { + // TODO: Handle environment for tasks + env := environment.Environment{} + var payload ImageResizePayload if err = json.Unmarshal(task.Payload(), &payload); err != nil { return @@ -39,8 +43,11 @@ func HandleImageResizeTask(ctx context.Context, task *asynq.Task) (err error) { wand := imagick.NewMagickWand() defer wand.Destroy() - tmpFile := "" - if err = wand.ReadImage(tmpFile); err != nil { + file, err := s3.DownloadSource(env, payload.ImageId) + if err != nil { + return + } + if err = wand.ReadImage(file); err != nil { return } var originalImage imgconv.ImageHandle @@ -50,7 +57,8 @@ func HandleImageResizeTask(ctx context.Context, task *asynq.Task) (err error) { err = util.LaunchGoroutines(len(payload.Sizes), func(index int) error { size := payload.Sizes[index] - tmpTargetFile := "" + // TODO: Allocate temp file + tmpFile := "" image := originalImage.CloneImage() if err := image.Crop(size); err != nil { return err @@ -58,7 +66,10 @@ func HandleImageResizeTask(ctx context.Context, task *asynq.Task) (err error) { if err := image.Resize(size); err != nil { return err } - if err := image.Write(payload.Quality, tmpTargetFile); err != nil { + if err := image.Write(payload.Quality, tmpFile); err != nil { + return err + } + if err := s3.UploadImage(env, payload.ImageId, size, tmpFile); err != nil { return err } return nil diff --git a/util/return_json.go b/util/return_json.go new file mode 100644 index 0000000000000000000000000000000000000000..aad85ef7b80ab58e8cffcdefac22b1c9387821c2 --- /dev/null +++ b/util/return_json.go @@ -0,0 +1,13 @@ +package util + +import ( + "encoding/json" + "net/http" +) + +func ReturnJson(writer http.ResponseWriter, data interface{}) { + writer.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(writer).Encode(data); err != nil { + writer.WriteHeader(http.StatusInternalServerError) + } +}