API server initial commit
This commit is contained in:
commit
b4c2a10236
|
@ -0,0 +1,6 @@
|
||||||
|
[submodule "server/vendor/github.com/julienschmidt/httprouter"]
|
||||||
|
path = server/vendor/github.com/julienschmidt/httprouter
|
||||||
|
url = https://github.com/julienschmidt/httprouter.git
|
||||||
|
[submodule "server/vendor/github.com/gorilla/websocket"]
|
||||||
|
path = server/vendor/github.com/gorilla/websocket
|
||||||
|
url = https://github.com/gorilla/websocket.git
|
|
@ -0,0 +1 @@
|
||||||
|
server
|
|
@ -0,0 +1,82 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DispatchFunction func(httprouter.Params, []byte) (interface{}, error)
|
||||||
|
|
||||||
|
func apiHandler(f DispatchFunction) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||||
|
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
||||||
|
r.RemoteAddr = addr
|
||||||
|
}
|
||||||
|
log.Printf("%s \"%s %s\" [%s]\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent())
|
||||||
|
|
||||||
|
// Read the body
|
||||||
|
if r.ContentLength < 0 || r.ContentLength > 6553600 {
|
||||||
|
http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}"), http.StatusRequestEntityTooLarge)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var body []byte
|
||||||
|
if r.ContentLength > 0 {
|
||||||
|
tmp := make([]byte, 1024)
|
||||||
|
for {
|
||||||
|
n, err := r.Body.Read(tmp)
|
||||||
|
for j := 0; j < n; j++ {
|
||||||
|
body = append(body, tmp[j])
|
||||||
|
}
|
||||||
|
if err != nil || n <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret interface{}
|
||||||
|
var err error = nil
|
||||||
|
|
||||||
|
ret, err = f(ps, body)
|
||||||
|
|
||||||
|
// Format response
|
||||||
|
resStatus := http.StatusOK
|
||||||
|
if err != nil {
|
||||||
|
ret = map[string]string{"errmsg": err.Error()}
|
||||||
|
resStatus = http.StatusBadRequest
|
||||||
|
log.Println(r.RemoteAddr, resStatus, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret == nil {
|
||||||
|
ret = map[string]string{"errmsg": "Page not found"}
|
||||||
|
resStatus = http.StatusNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if str, found := ret.(string); found {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(resStatus)
|
||||||
|
io.WriteString(w, str)
|
||||||
|
} else if bts, found := ret.([]byte); found {
|
||||||
|
w.Header().Set("Content-Type", "application/octet-stream")
|
||||||
|
w.Header().Set("Content-Disposition", "attachment")
|
||||||
|
w.Header().Set("Content-Transfer-Encoding", "binary")
|
||||||
|
w.WriteHeader(resStatus)
|
||||||
|
w.Write(bts)
|
||||||
|
} else if j, err := json.Marshal(ret); err != nil {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", err), http.StatusInternalServerError)
|
||||||
|
} else {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(resStatus)
|
||||||
|
w.Write(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func notFound(ps httprouter.Params, _ []byte) (interface{}, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
var router = httprouter.New()
|
||||||
|
|
||||||
|
func Router() *httprouter.Router {
|
||||||
|
return router
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.GET("/version", apiHandler(showVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
func showVersion(_ httprouter.Params, body []byte) (interface{}, error) {
|
||||||
|
return map[string]interface{}{"version": 0.1}, nil
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"git.nemunai.re/filicop/server/api"
|
||||||
|
"git.nemunai.re/filicop/server/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResponseWriterPrefix struct {
|
||||||
|
real http.ResponseWriter
|
||||||
|
prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ResponseWriterPrefix) Header() http.Header {
|
||||||
|
return r.real.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ResponseWriterPrefix) WriteHeader(s int) {
|
||||||
|
if v, exists := r.real.Header()["Location"]; exists {
|
||||||
|
r.real.Header().Set("Location", r.prefix+v[0])
|
||||||
|
}
|
||||||
|
r.real.WriteHeader(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ResponseWriterPrefix) Write(z []byte) (int, error) {
|
||||||
|
return r.real.Write(z)
|
||||||
|
}
|
||||||
|
|
||||||
|
func StripPrefix(prefix string, h http.Handler) http.Handler {
|
||||||
|
if prefix == "" {
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if prefix != "/" && r.URL.Path == "/" {
|
||||||
|
http.Redirect(w, r, prefix+"/", http.StatusFound)
|
||||||
|
} else if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
|
||||||
|
r2 := new(http.Request)
|
||||||
|
*r2 = *r
|
||||||
|
r2.URL = new(url.URL)
|
||||||
|
*r2.URL = *r.URL
|
||||||
|
r2.URL.Path = p
|
||||||
|
h.ServeHTTP(ResponseWriterPrefix{w, prefix}, r2)
|
||||||
|
} else {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Read parameters from command line
|
||||||
|
var bind = flag.String("bind", "127.0.0.1:8081", "Bind port/socket")
|
||||||
|
var dsn = flag.String("dsn", filicop.DSNGenerator(), "DSN to connect to the MySQL server")
|
||||||
|
var baseURL = flag.String("baseurl", "/", "URL prepended to each URL")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Sanitize options
|
||||||
|
if *baseURL != "/" {
|
||||||
|
tmp := path.Clean(*baseURL)
|
||||||
|
baseURL = &tmp
|
||||||
|
} else {
|
||||||
|
tmp := ""
|
||||||
|
baseURL = &tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Opening database...")
|
||||||
|
if err := filicop.DBInit(*dsn); err != nil {
|
||||||
|
log.Fatal("Cannot open the database: ", err)
|
||||||
|
}
|
||||||
|
defer filicop.DBClose()
|
||||||
|
|
||||||
|
log.Println("Creating database...")
|
||||||
|
if err := filicop.DBCreate(); err != nil {
|
||||||
|
log.Fatal("Cannot create database: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare graceful shutdown
|
||||||
|
interrupt := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: *bind,
|
||||||
|
Handler: StripPrefix(*baseURL, api.Router()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve content
|
||||||
|
go func() {
|
||||||
|
log.Fatal(srv.ListenAndServe())
|
||||||
|
}()
|
||||||
|
log.Println(fmt.Sprintf("Ready, listening on %s", *bind))
|
||||||
|
|
||||||
|
// Wait shutdown signal
|
||||||
|
<-interrupt
|
||||||
|
|
||||||
|
log.Print("The service is shutting down...")
|
||||||
|
srv.Shutdown(context.Background())
|
||||||
|
log.Println("done")
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
package filicop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// db stores the connection to the database
|
||||||
|
var db *sql.DB
|
||||||
|
|
||||||
|
// DSNGenerator returns DSN filed with values from environment
|
||||||
|
func DSNGenerator() string {
|
||||||
|
db_user := "filicop"
|
||||||
|
db_password := "filicop"
|
||||||
|
db_host := ""
|
||||||
|
db_db := "filicop"
|
||||||
|
|
||||||
|
if v, exists := os.LookupEnv("MYSQL_HOST"); exists {
|
||||||
|
db_host = v
|
||||||
|
}
|
||||||
|
if v, exists := os.LookupEnv("MYSQL_PASSWORD"); exists {
|
||||||
|
db_password = v
|
||||||
|
} else if v, exists := os.LookupEnv("MYSQL_ROOT_PASSWORD"); exists {
|
||||||
|
db_user = "root"
|
||||||
|
db_password = v
|
||||||
|
}
|
||||||
|
if v, exists := os.LookupEnv("MYSQL_USER"); exists {
|
||||||
|
db_user = v
|
||||||
|
}
|
||||||
|
if v, exists := os.LookupEnv("MYSQL_DATABASE"); exists {
|
||||||
|
db_db = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return db_user + ":" + db_password + "@" + db_host + "/" + db_db
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBInit establishes the connection to the database
|
||||||
|
func DBInit(dsn string) (err error) {
|
||||||
|
if db, err = sql.Open("mysql", dsn+"?parseTime=true&foreign_key_checks=1"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = db.Exec(`SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO';`)
|
||||||
|
for i := 0; err != nil && i < 15; i += 1 {
|
||||||
|
if _, err = db.Exec(`SET SESSION sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO';`); err != nil && i <= 5 {
|
||||||
|
log.Println("An error occurs when trying to connect to DB, will retry in 2 seconds: ", err)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBCreate creates all necessary tables used by the package
|
||||||
|
func DBCreate() error {
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS fleets(
|
||||||
|
id_fleet INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
label VARCHAR(255) NOT NULL
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS vehicles(
|
||||||
|
id_vehicle INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
id_fleet INTEGER NOT NULL,
|
||||||
|
label VARCHAR(255) NOT NULL,
|
||||||
|
FOREIGN KEY(id_fleet) REFERENCES fleets(id_fleet)
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS vehicle_locations(
|
||||||
|
id_location INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
id_vehicle INTEGER NOT NULL,
|
||||||
|
date DATETIME NOT NULL,
|
||||||
|
location POINT NOT NULL,
|
||||||
|
FOREIGN KEY(id_vehicle) REFERENCES vehicles(id_vehicle)
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS requestors(
|
||||||
|
id_requestor INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
id_fleet INTEGER NOT NULL,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
FOREIGN KEY(id_fleet) REFERENCES fleets(id_fleet)
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS missions(
|
||||||
|
id_mission INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
id_requestor INTEGER NOT NULL,
|
||||||
|
id_vehicle INTEGER,
|
||||||
|
creation DATETIME NOT NULL,
|
||||||
|
location_source POINT NOT NULL,
|
||||||
|
location_destination POINT NOT NULL,
|
||||||
|
FOREIGN KEY(id_vehicle) REFERENCES vehicles(id_vehicle),
|
||||||
|
FOREIGN KEY(id_requestor) REFERENCES requestors(id_requestor)
|
||||||
|
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin;
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBClose closes the connection to the database
|
||||||
|
func DBClose() error {
|
||||||
|
return db.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func DBPrepare(query string) (*sql.Stmt, error) {
|
||||||
|
return db.Prepare(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DBQuery(query string, args ...interface{}) (*sql.Rows, error) {
|
||||||
|
return db.Query(query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DBExec(query string, args ...interface{}) (sql.Result, error) {
|
||||||
|
return db.Exec(query, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DBQueryRow(query string, args ...interface{}) *sql.Row {
|
||||||
|
return db.QueryRow(query, args...)
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package filicop
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
type Fleet struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFleets() (fleets []Fleet, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_fleet, label FROM fleets"); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var f Fleet
|
||||||
|
if err = rows.Scan(&f.Id, &f.Label); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fleets = append(fleets, f)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFleet(id int64) (f Fleet, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_fleet, label FROM fleets WHERE id_fleet = ?", id).Scan(&f.Id, &f.Label)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFleet(label string) (Fleet, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO fleets (label) VALUES (?)", label); err != nil {
|
||||||
|
return Fleet{}, err
|
||||||
|
} else if fid, err := res.LastInsertId(); err != nil {
|
||||||
|
return Fleet{}, err
|
||||||
|
} else {
|
||||||
|
return Fleet{fid, label}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fleet) Update() (int64, error) {
|
||||||
|
if res, err := DBExec("UPDATE fleets SET label = ? WHERE id_fleet = ?", f.Label, f.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fleet) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM fleets WHERE id_fleet = ?", f.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearFleets() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM fleets"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package filicop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mission struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdRequestor int64 `json:"id_requestor"`
|
||||||
|
IdVehicle *int64 `json:"id_vehicle"`
|
||||||
|
Creation time.Time `json:"creation"`
|
||||||
|
LocationFrom Point `json:"from"`
|
||||||
|
LocationTo Point `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMissions() (missions []Mission, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_mission, id_requestor, id_vehicle, creation, location_source, location_destination FROM missions"); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var m Mission
|
||||||
|
if err = rows.Scan(&m.Id, &m.IdRequestor, &m.IdVehicle, &m.Creation, &m.LocationFrom, &m.LocationTo); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
missions = append(missions, m)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMission(id int64) (m Mission, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_mission, id_requestor, id_vehicle, creation, location_source,location_destination FROM missions WHERE id_mission = ?", id).Scan(&m.Id, &m.IdRequestor, &m.IdVehicle, &m.Creation, &m.LocationFrom, &m.LocationTo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Requestor) NewMission(from Point, to Point, vehicle *Vehicle) (Mission, error) {
|
||||||
|
var vid *int64 = nil
|
||||||
|
if vehicle != nil {
|
||||||
|
vid = &vehicle.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
if res, err := DBExec("INSERT INTO missions (id_requestor, id_vehicle, location_source, location_destination) VALUES (?, ?, ?, ?)", r.Id, vid, from, to); err != nil {
|
||||||
|
return Mission{}, err
|
||||||
|
} else if mid, err := res.LastInsertId(); err != nil {
|
||||||
|
return Mission{}, err
|
||||||
|
} else {
|
||||||
|
return Mission{mid, r.Id, vid, time.Now(), from, to}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mission) Update() (int64, error) {
|
||||||
|
if res, err := DBExec("UPDATE missions SET id_requestor = ?, creation = ?, location_source = ?, location_destination = ? WHERE id_mission = ?", m.IdRequestor, m.Creation, m.LocationFrom, m.LocationTo, m.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Mission) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM missions WHERE id_mission = ?", m.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearMissions() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM missions"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Requestor) ClearMissions() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM missions WHERE id_requestor = ?", r.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package filicop
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
type Requestor struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdFleet int64 `json:"id_fleet"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRequestors() (requestors []Requestor, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_requestor, id_fleet, name FROM requestors"); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var r Requestor
|
||||||
|
if err = rows.Scan(&r.Id, &r.IdFleet, &r.Name); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
requestors = append(requestors, r)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRequestor(id int64) (r Requestor, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_requestor, id_fleet, name FROM requestors WHERE id_requestor = ?", id).Scan(&r.Id, &r.IdFleet, &r.Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fleet) NewRequestor(name string) (Requestor, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO requestors (id_fleet, name) VALUES (?, ?)", f.Id, name); err != nil {
|
||||||
|
return Requestor{}, err
|
||||||
|
} else if rid, err := res.LastInsertId(); err != nil {
|
||||||
|
return Requestor{}, err
|
||||||
|
} else {
|
||||||
|
return Requestor{rid, f.Id, name}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Requestor) Update() (int64, error) {
|
||||||
|
if res, err := DBExec("UPDATE requestors SET id_fleet = ?, name = ? WHERE id_requestor = ?", r.IdFleet, r.Name, r.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Requestor) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM requestors WHERE id_requestor = ?", r.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearRequestors() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM requestors"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fleet) ClearRequestors() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM requestors WHERE id_fleet = ?", f.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package filicop
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
type Vehicle struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdFleet int64 `json:"id_fleet"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVehicles() (vehicles []Vehicle, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_vehicle, id_fleet, label FROM vehicles"); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var v Vehicle
|
||||||
|
if err = rows.Scan(&v.Id, &v.IdFleet, &v.Label); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vehicles = append(vehicles, v)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVehicle(id int64) (v Vehicle, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_vehicle, id_fleet, label FROM vehicles WHERE id_vehicle = ?", id).Scan(&v.Id, &v.IdFleet, &v.Label)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fleet) NewVehicle(label string) (Vehicle, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO vehicles (id_fleet, label) VALUES (?, ?)", f.Id, label); err != nil {
|
||||||
|
return Vehicle{}, err
|
||||||
|
} else if vid, err := res.LastInsertId(); err != nil {
|
||||||
|
return Vehicle{}, err
|
||||||
|
} else {
|
||||||
|
return Vehicle{vid, f.Id, label}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vehicle) Update() (int64, error) {
|
||||||
|
if res, err := DBExec("UPDATE vehicles SET id_fleet = ?, label = ? WHERE id_vehicle = ?", v.IdFleet, v.Label, v.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vehicle) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM vehicles WHERE id_vehicle = ?", v.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearVehicles() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM vehicles"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fleet) ClearVehicles() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM vehicles WHERE id_fleet = ?", f.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package filicop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Point struct {
|
||||||
|
X float32 `json:"x"`
|
||||||
|
Y float32 `json:"y"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VehicleLocation struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
IdVehicle int64 `json:"id_vehicle"`
|
||||||
|
Location Point `json:"location"`
|
||||||
|
Date time.Time `json:"date"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vehicle) GetLocations() (locations []VehicleLocation, err error) {
|
||||||
|
if rows, errr := DBQuery("SELECT id_location, id_vehicle, location, date FROM vehicles_locations WHERE id_vehicle = ?", v.Id); errr != nil {
|
||||||
|
return nil, errr
|
||||||
|
} else {
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var l VehicleLocation
|
||||||
|
if err = rows.Scan(&l.Id, &l.IdVehicle, &l.Location, &l.Date); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
locations = append(locations, l)
|
||||||
|
}
|
||||||
|
if err = rows.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVehicleLocation(id int64) (l VehicleLocation, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_location, id_vehicle, location, date FROM vehicle_locations WHERE id_location = ?", id).Scan(&l.Id, &l.IdVehicle, &l.Location, &l.Date)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vehicle) GetLocation(id int64) (l VehicleLocation, err error) {
|
||||||
|
err = DBQueryRow("SELECT id_location, id_vehicle, location, date FROM vehicle_locations WHERE id_location = ? AND id_vehicle = ?", id, v.Id).Scan(&l.Id, &l.IdVehicle, &l.Location, &l.Date)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l VehicleLocation) GetVehicle() (Vehicle, error) {
|
||||||
|
return GetVehicle(l.IdVehicle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l VehicleLocation) SetVehicle(v Vehicle) {
|
||||||
|
l.IdVehicle = v.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vehicle) NewLocation(point Point) (VehicleLocation, error) {
|
||||||
|
if res, err := DBExec("INSERT INTO vehicle_locations (id_vehicle, location) VALUES (?, ?)", v.Id, point); err != nil {
|
||||||
|
return VehicleLocation{}, err
|
||||||
|
} else if lid, err := res.LastInsertId(); err != nil {
|
||||||
|
return VehicleLocation{}, err
|
||||||
|
} else {
|
||||||
|
return VehicleLocation{lid, v.Id, point, time.Now()}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l VehicleLocation) Update() (int64, error) {
|
||||||
|
if res, err := DBExec("UPDATE vehicle_locations SET id_vehicle = ?, location = ?, date = ? WHERE id_location = ?", l.IdVehicle, l.Location, l.Date, l.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l VehicleLocation) Delete() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM vehicle_locations WHERE id_location = ?", l.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearVehicleLocations() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM vehicle_locations"); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Vehicle) ClearVehicleLocations() (int64, error) {
|
||||||
|
if res, err := DBExec("DELETE FROM vehicle_locations WHERE id_vehicle = ?", v.Id); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
return nb, err
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5ed622c449da6d44c3c8329331ff47a9e5844f71
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit adbc77eec0d91467376ca515bc3a14b8434d0f18
|
Reference in New Issue