first commit
This commit is contained in:
35
cmd/server/api/api.go
Normal file
35
cmd/server/api/api.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Server struct {
|
||||||
|
handler http.Handler
|
||||||
|
services *Services
|
||||||
|
}
|
||||||
|
|
||||||
|
Services struct {
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(services *Services) *Server {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
r.Use(middleware.RequestID)
|
||||||
|
r.Use(middleware.Logger)
|
||||||
|
r.Use(middleware.Recoverer)
|
||||||
|
|
||||||
|
return &Server{
|
||||||
|
handler: r,
|
||||||
|
services: services,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListenAndServe(port uint16) error {
|
||||||
|
return http.ListenAndServe(fmt.Sprintf(":%d", port), s.handler)
|
||||||
|
}
|
||||||
23
cmd/server/main.go
Normal file
23
cmd/server/main.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cloudsync/cmd/server/api"
|
||||||
|
"cloudsync/pkg/data"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const version = "0.1.0-alpha"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf(" -- CloudSync server | Version %s (%s/%s) --\n\n", version, runtime.GOOS, runtime.GOARCH)
|
||||||
|
|
||||||
|
data.New("./")
|
||||||
|
server := api.New(nil)
|
||||||
|
log.Println("[INFO] starting server on port 8080")
|
||||||
|
err := server.ListenAndServe(8080)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("[PANIC] %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
8
go.mod
Normal file
8
go.mod
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module cloudsync
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-chi/chi/v5 v5.0.12
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22
|
||||||
|
)
|
||||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||||
|
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
58
pkg/data/data.go
Normal file
58
pkg/data/data.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Repository struct {
|
||||||
|
path string
|
||||||
|
conn *sql.DB
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(path string) *Repository {
|
||||||
|
dbPath := filepath.Join(path, "system.db")
|
||||||
|
conn, err := sql.Open("sqlite3", dbPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := &Repository{
|
||||||
|
path: path,
|
||||||
|
conn: conn,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.check(); err != nil {
|
||||||
|
log.Fatalf("[PANIC] %s", err)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) Close() error {
|
||||||
|
return r.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repository) check() error {
|
||||||
|
rows, err := r.conn.Query("SELECT value FROM system WHERE key = 'db.version'")
|
||||||
|
if err != nil {
|
||||||
|
m := new(migratorVersion1)
|
||||||
|
m.conn = r.conn
|
||||||
|
return m.create()
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var version string
|
||||||
|
if !rows.Next() {
|
||||||
|
return errors.New("no version found in the system database")
|
||||||
|
}
|
||||||
|
if err := rows.Scan(&version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[INFO] database loaded with version %s", version)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
40
pkg/data/db_struct_v1.sql
Normal file
40
pkg/data/db_struct_v1.sql
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
CREATE TABLE system (
|
||||||
|
key string primary key,
|
||||||
|
value string
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
uuid string primary key,
|
||||||
|
username string,
|
||||||
|
password string
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE roles (
|
||||||
|
uuid string primary key,
|
||||||
|
descriptor string
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE role_permissions (
|
||||||
|
uuid string primary key,
|
||||||
|
role string,
|
||||||
|
system_permission string
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE user_roles (
|
||||||
|
uuid string primary key,
|
||||||
|
role string,
|
||||||
|
user string
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE saves (
|
||||||
|
uuid string primary key,
|
||||||
|
name string,
|
||||||
|
user string,
|
||||||
|
path string
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO system (key, value) VALUES ('db.version', '1');
|
||||||
|
INSERT INTO users (uuid, username) VALUES ('4b5b9489-973c-44e7-bae0-5ab23b56abe7', 'root');
|
||||||
|
INSERT INTO roles (uuid, descriptor) VALUES ('4b5b9489-973c-44e7-bae0-5ab23b56abe7', 'root');
|
||||||
|
INSERT INTO role_permissions (uuid, role, system_permission) VALUES ('4b5b9489-973c-44e7-bae0-5ab23b56abe7', '4b5b9489-973c-44e7-bae0-5ab23b56abe7', '*.*');
|
||||||
|
INSERT INTO user_roles (uuid, role, user) VALUES ('4b5b9489-973c-44e7-bae0-5ab23b56abe7', '4b5b9489-973c-44e7-bae0-5ab23b56abe7', '4b5b9489-973c-44e7-bae0-5ab23b56abe7');
|
||||||
27
pkg/data/migration.go
Normal file
27
pkg/data/migration.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
_ "embed"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed db_struct_v1.sql
|
||||||
|
var dbStructV1SQL string
|
||||||
|
|
||||||
|
type (
|
||||||
|
migratorVersion1 struct {
|
||||||
|
conn *sql.DB
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *migratorVersion1) create() error {
|
||||||
|
log.Printf("[INFO] no database, creating system database structure...")
|
||||||
|
_, err := m.conn.Exec(dbStructV1SQL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[INFO] root user and role inserted by default")
|
||||||
|
log.Println("[INFO] database created with success!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
101
pkg/http/http.go
Normal file
101
pkg/http/http.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
BaseResponse interface {
|
||||||
|
IsSuccess() bool
|
||||||
|
SentAt() time.Time
|
||||||
|
Copy(w io.Writer) error
|
||||||
|
}
|
||||||
|
Response struct {
|
||||||
|
status uint16
|
||||||
|
timestamp time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
Message struct {
|
||||||
|
Response
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
Object struct {
|
||||||
|
Response
|
||||||
|
data any
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func MakeResponse(status uint16) Response {
|
||||||
|
return Response{
|
||||||
|
status: status,
|
||||||
|
timestamp: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeMessage(status uint16, message string) Message {
|
||||||
|
r := MakeResponse(status)
|
||||||
|
return Message{
|
||||||
|
Response: r,
|
||||||
|
message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeObject(status uint16, data any) Object {
|
||||||
|
r := MakeResponse(status)
|
||||||
|
return Object{
|
||||||
|
Response: r,
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) IsSuccess() bool {
|
||||||
|
return r.status >= 200 && r.status < 300
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) SentAt() time.Time {
|
||||||
|
return r.timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) Copy(w io.Writer) error {
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
err := encoder.Encode(r)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(r.toMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Response) toMap() map[string]any {
|
||||||
|
return map[string]any{
|
||||||
|
"status": r.status,
|
||||||
|
"timestamp": r.timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) Copy(w io.Writer) error {
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
err := encoder.Encode(m)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) MarshalJSON() ([]byte, error) {
|
||||||
|
mp := m.toMap()
|
||||||
|
mp["message"] = m.message
|
||||||
|
return json.Marshal(mp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Object) Copy(w io.Writer) error {
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
err := encoder.Encode(o)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Object) MarshalJSON() ([]byte, error) {
|
||||||
|
mp := o.toMap()
|
||||||
|
mp["data"] = o.data
|
||||||
|
return json.Marshal(mp)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user