The first something

master
Caj Larsson 3 years ago
parent 2f4473fca1
commit a26782d6cd

@ -0,0 +1,71 @@
package application
import (
"net/http"
"fmt"
"log"
"io"
"caj-larsson/bog/domain"
"caj-larsson/bog/integration"
)
type Bog struct {
config *Configuration
mux *http.ServeMux
// file_service *domain.BogFileService
fileDataRepo domain.FileDataRepository
}
func New(config *Configuration) *Bog {
b := new(Bog)
b.config = config
log.Print(config)
fsBogRepo := new(integration.FileSystemBogRepository)
fsBogRepo.Root = "/tmp/datta"
b.fileDataRepo = *fsBogRepo
// uaRepo *domain.UserAgentRepository
b.mux = http.NewServeMux()
b.mux.HandleFunc("/",func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
fmt.Fprintf(w, "Hi")
return
}
bog_file, err := b.fileDataRepo.OpenOrCreate(r.URL.Path, r.Header["User-Agent"][0])
if err != nil {
}
switch r.Method {
case "GET":
src := domainFileSource { bog_file.Path(),
http.ServeContent(w, r, , bog_file.Modified(), bog_file)
case "POST":
fallthrough
case "PUT":
io.Copy(bog_file, r.Body)
bog_file.Close()
}
return
})
return b
}
func (b *Bog) Run() {
http.ListenAndServe(b.config.address(), b.mux)
}
func CreateFileHandler(w http.ResponseWriter, r *http.Request) {
}

@ -0,0 +1,29 @@
package application
import (
"fmt"
"github.com/BurntSushi/toml"
)
type Configuration struct {
Port int64
Host string
Path string
}
func (c *Configuration) address() string {
return fmt.Sprintf("%s:%d", c.Host, c.Port)
}
func ConfigFromToml(toml_data string) (*Configuration, error) {
var config Configuration
_, err := toml.Decode(toml_data, &config)
if err != nil {
return nil, err
}
return &config, nil
}

@ -0,0 +1,2 @@
port = 8002
host = "127.0.0.1"

@ -0,0 +1,28 @@
package domain
import (
"time"
"errors"
)
type UserAgent struct {
ID int64
Name string
LastSeen time.Time
AllowanceDuration time.Duration
FileQuota FileSizeQuota
}
type BogFile struct {
UserAgentId int64
Path string
Size int64
CreatedAt time.Time
}
var (
ErrDuplicate = errors.New("record already exists")
ErrNotExists = errors.New("row not exists")
ErrUpdateFailed = errors.New("update failed")
ErrDeleteFailed = errors.New("delete failed")
)

@ -0,0 +1,10 @@
package domain
import "testing"
func TestSum(t *testing.T) {
total := 3
if total != 10 {
t.Errorf("It failed ok")
}
}

@ -0,0 +1,15 @@
package domain
type UserAgentRepository interface{
Migrate() error
CreateUserAgent(useragent UserAgent) (*UserAgent, error)
All() ([]UserAgent, error)
GetByName(name string) (*UserAgent, error)
Update(id int64, useragent UserAgent) (*UserAgent, error)
Delete(id int64) error
}
type FileDataRepository interface {
OpenOrCreate(path string, user_agent string) (BogFileData, error)
Delete(file_data *BogFileData)
}

@ -0,0 +1,30 @@
package domain
import "io"
type BogFileService struct {
user_agent_repo UserAgentRepository
file_data_repo FileDataRepository
}
func (b *BogFileService) RecieveFile(src FileSource) error {
f, err := b.file_data_repo.OpenOrCreate(src.Path(), src.UserAgent())
if err != nil {
return err
}
io.Copy(f, src)
return nil
}
func (b *BogFileService) SendFile(dst FileDestination) error {
f, err := b.file_data_repo.OpenOrCreate(dst.Path(), dst.UserAgent())
if err != nil {
return err
}
io.Copy(dst, f)
return nil
}

@ -0,0 +1,46 @@
package domain
import (
"io"
"time"
)
type FileSizeQuota struct {
AllowanceKB int64
CurrentUsage int64
}
func (f *FileSizeQuota) Allows(size int64) bool {
return f.CurrentUsage + size <= f.AllowanceKB
}
func (f *FileSizeQuota) Add(size int64) {
f.CurrentUsage += size
}
func (f *FileSizeQuota) Remove(size int64) {
f.CurrentUsage -= size
}
type BogFileData interface {
Path() string
Size() int64
Modified() time.Time
io.Reader
io.Seeker
io.Writer
io.Closer
}
type FileSource struct {
Path string
UserAgent string
Size int64
Src io.ReadCloser
}
type FileDestination struct {
Path string
UserAgent string
Dst io.WriteCloser
}

@ -0,0 +1,8 @@
module caj-larsson/bog
go 1.18
require (
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/mattn/go-sqlite3 v1.14.12 // indirect
)

@ -0,0 +1,4 @@
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=

@ -0,0 +1,68 @@
package integration
import (
"time"
"os"
"path"
"caj-larsson/bog/domain"
)
type FileSystemBogFileData struct {
path string
file *os.File
}
func (f FileSystemBogFileData) Read(p []byte) (int, error) {
return f.file.Read(p)
}
func (f FileSystemBogFileData) Write(p []byte) (int, error) {
return f.file.Write(p)
}
func (f FileSystemBogFileData) Close() error {
return f.file.Close()
}
func (f FileSystemBogFileData) Seek(offset int64, whence int) (int64, error) {
return f.file.Seek(offset, whence)
}
func (f FileSystemBogFileData) Path() string {
return f.path
}
func (f FileSystemBogFileData) Size() int64 {
return 0
}
func (f FileSystemBogFileData) Modified() time.Time{
return time.Now()
}
type FileSystemBogRepository struct {
Root string
}
func (f FileSystemBogRepository) OpenOrCreate(open_path string, user_agent string) (domain.BogFileData, error) {
//file_name := path.Base(open_path)
abs_path := path.Join(f.Root, open_path)
dir := path.Dir(abs_path)
os.MkdirAll(dir, 0750)
file, err := os.OpenFile(abs_path, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
panic(err)
}
bfd := FileSystemBogFileData {open_path, file}
return bfd, nil
}
func (f FileSystemBogRepository) Delete(file *domain.BogFileData) {
}

@ -0,0 +1,45 @@
package integration
import (
"errors"
"time"
"caj-larsson/bog/domain"
)
type UserAgentDBRecord struct {
ID int64
Name string
LastSeen string
AllowanceSeconds int64
QuotaKB int64
QuotaUsedKB int64
}
var ErrUnparseableRecord = errors.New("record could not be mapped to entity")
func (r *UserAgentDBRecord) toEntity() (*domain.UserAgent, error) {
lastseen, err := time.Parse(time.RFC3339, r.LastSeen)
if err != nil {
return nil, ErrUnparseableRecord
}
var useragent = new(domain.UserAgent)
useragent.ID = r.ID
useragent.Name = r.Name
useragent.LastSeen = lastseen
useragent.AllowanceDuration = time.Duration(r.AllowanceSeconds * int64(time.Second))
useragent.FileQuota = domain.FileSizeQuota { r.QuotaKB, r.QuotaUsedKB }
return useragent, err
}
func fromEntity(useragent domain.UserAgent) (*UserAgentDBRecord, error) {
var record = new(UserAgentDBRecord)
record.ID = useragent.ID
record.Name = useragent.Name
record.LastSeen = useragent.LastSeen.Format(time.RFC3339)
record.AllowanceSeconds = int64(useragent.AllowanceDuration.Seconds())
record.QuotaKB = useragent.FileQuota.AllowanceKB
record.QuotaUsedKB = useragent.FileQuota.CurrentUsage
return record, nil
}

@ -0,0 +1,149 @@
package integration
import (
"caj-larsson/bog/domain"
"database/sql"
"errors"
"github.com/mattn/go-sqlite3"
)
type SQLiteUserAgentRepository struct {
db *sql.DB
}
func NewSQLiteUserAgentRepository(db *sql.DB) *SQLiteUserAgentRepository {
return &SQLiteUserAgentRepository{
db: db,
}
}
func (r *SQLiteUserAgentRepository) Migrate() error {
query := `
CREATE TABLE IF NOT EXISTS useragent(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
lastseen text,
allowance_time bigint,
quota_kb bigint,
quota_usage_kb bigint
);
`
_, err := r.db.Exec(query)
return err
}
func (r *SQLiteUserAgentRepository) Create(useragent domain.UserAgent) (*domain.UserAgent, error) {
var record, err = fromEntity(useragent)
if err != nil {
}
res, err := r.db.Exec(
"INSERT INTO useragent(name, lastseen, allowance_time, quota_kb, quota_usage_kb) values(?,?,?,?,?)",
record.Name, record.LastSeen, record.AllowanceSeconds, record.QuotaKB, record.QuotaUsedKB,
)
if err != nil {
var sqliteErr sqlite3.Error
if errors.As(err, &sqliteErr) {
if errors.Is(sqliteErr.ExtendedCode, sqlite3.ErrConstraintUnique) {
return nil, domain.ErrDuplicate
}
}
return nil, err
}
id, err := res.LastInsertId()
if err != nil {
return nil, err
}
useragent.ID = id
return &useragent, nil
}
func (r *SQLiteUserAgentRepository) All() ([]domain.UserAgent, error) {
rows, err := r.db.Query("SELECT * FROM useragent")
if err != nil {
return nil, err
}
defer rows.Close()
var all []domain.UserAgent
for rows.Next() {
var record UserAgentDBRecord
if err := rows.Scan(&record.ID, &record.Name, &record.LastSeen, &record.AllowanceSeconds, &record.QuotaKB, &record.QuotaUsedKB); err != nil {
return nil, err
}
var useragent, err = record.toEntity()
if err != nil {
return nil, err
}
all = append(all, *useragent)
}
return all, nil
}
func (r *SQLiteUserAgentRepository) GetByName(name string) (*domain.UserAgent, error) {
row := r.db.QueryRow("SELECT id, name, lastseen, allowance_time, allowance_kb FROM useragent WHERE name = ?", name)
var record UserAgentDBRecord
if err := row.Scan(&record.ID, &record.Name, &record.LastSeen, &record.AllowanceSeconds, &record.QuotaKB, &record.QuotaUsedKB); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, domain.ErrNotExists
}
return nil, err
}
var useragent, err = record.toEntity()
if err != nil {
return nil, err
}
return useragent, nil
}
func (r *SQLiteUserAgentRepository) Update(id int64, updated domain.UserAgent) (*domain.UserAgent, error) {
if id == 0 {
return nil, errors.New("invalid updated ID")
}
var record, err = fromEntity(updated)
res, err := r.db.Exec("UPDATE useragent SET name = ?, lastseen = ?, allowance_time = ?, quota_kb = ?, quota_usage_kb = ? WHERE id = ?",
record.Name, record.LastSeen, record.AllowanceSeconds, &record.QuotaKB, &record.QuotaUsedKB, id)
if err != nil {
return nil, err
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return nil, err
}
if rowsAffected == 0 {
return nil, domain.ErrUpdateFailed
}
return &updated, nil
}
func (r *SQLiteUserAgentRepository) Delete(id int64) error {
res, err := r.db.Exec("DELETE FROM useragent WHERE id = ?", id)
if err != nil {
return err
}
rowsAffected, err := res.RowsAffected()
if err != nil {
return err
}
if rowsAffected == 0 {
return domain.ErrDeleteFailed
}
return err
}

@ -0,0 +1,22 @@
package main
import (
"caj-larsson/bog/application"
"io/ioutil"
)
func main() {
content, err := ioutil.ReadFile("default.toml")
if err != nil {
panic(err)
}
config, err := application.ConfigFromToml(string(content))
if err != nil {
panic(err)
}
bog := application.New(config)
bog.Run()
}
Loading…
Cancel
Save