Merge pull request 'base_events' (#1) from base_events into master

Reviewed-on: nilo/apifiber#1
main
Nilo Roberto C Paim 2023-09-07 14:03:13 +00:00
commit 6eef0934d5
18 changed files with 294 additions and 116 deletions

34
.env
View File

@ -2,19 +2,19 @@
API_SECRET=nyEX8BZ44KqTXeV2 API_SECRET=nyEX8BZ44KqTXeV2
# DB configuration DEVELOPMENT # DB configuration DEVELOPMENT
API_PORT=8111 #API_PORT=8111
API_RELEASE="Desenvolvimento" #API_RELEASE="Desenvolvimento"
DB_HOST=177.153.50.98 #DB_HOST=177.153.50.98
DB_DRIVER=postgres #DB_DRIVER=postgres
DB_USER=pcastdev #DB_USER=pcastdev
DB_PASSWORD=@407Smc837 #DB_PASSWORD=@407Smc837
DB_NAME=pcastdev #DB_NAME=pcastdev
DB_PORT=5432 #DB_PORT=5432
# DB configuration HOMOLOGAÇÃO # DB configuration HOMOLOGAÇÃO
#API_PORT=8111 #API_PORT=8111
#API_RELEASE="Homologação" #API_RELEASE="Homologação"
#DB_HOST=177.153.50.98 #DB_HOST=191.252.214.157
#DB_DRIVER=postgres #DB_DRIVER=postgres
#DB_USER=pcasthomolog #DB_USER=pcasthomolog
#DB_PASSWORD=@407Smc837 #DB_PASSWORD=@407Smc837
@ -22,11 +22,11 @@ DB_PORT=5432
#DB_PORT=5432 #DB_PORT=5432
# DB configuration PRODUÇÃO # DB configuration PRODUÇÃO
#API_PORT=8112 API_PORT=8112
#API_RELEASE="" API_RELEASE=""
#DB_HOST=177.153.50.98 DB_HOST=177.153.50.98
#DB_DRIVER=postgres DB_DRIVER=postgres
#DB_USER=pcast DB_USER=pcast
#DB_PASSWORD=@407Smc837 DB_PASSWORD=@407Smc837
#DB_NAME=pcast DB_NAME=pcast
#DB_PORT=5432 DB_PORT=5432

2
.gitignore vendored
View File

@ -3,6 +3,8 @@
api api
api.exe api.exe
.env
pcast.db pcast.db
api-homolog.log api-homolog.log
.gitignore .gitignore

View File

@ -4,8 +4,10 @@ import (
"api/database" "api/database"
"api/models" "api/models"
"api/utils" "api/utils"
"log"
"os" "os"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
@ -19,6 +21,7 @@ func Login(c *fiber.Ctx) error {
var data map[string]string var data map[string]string
if err := c.BodyParser(&data); err != nil { if err := c.BodyParser(&data); err != nil {
log.Printf("Bad Request on parse: %v\n", err)
return fiber.ErrBadRequest return fiber.ErrBadRequest
} }
@ -27,11 +30,30 @@ func Login(c *fiber.Ctx) error {
database.DB.Where("email = ?", data["email"]).First(&user) database.DB.Where("email = ?", data["email"]).First(&user)
if user.Id == 0 { if user.Id == 0 {
return fiber.ErrNotFound return c.JSON(fiber.Map{
"message": "Usuário não encontrado",
"userId": 0,
"userType": "",
"userName": "",
"token": ""})
} }
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil { if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
return fiber.ErrUnauthorized return c.JSON(fiber.Map{
"message": "Senha inválida",
"userId": 0,
"userType": "",
"userName": "",
"token": ""})
}
if user.Blocked == "S" {
return c.JSON(fiber.Map{
"message": "Usuário bloqueado",
"userId": 0,
"userType": "",
"userName": "",
"token": ""})
} }
type customClaims struct { type customClaims struct {
@ -55,6 +77,7 @@ func Login(c *fiber.Ctx) error {
} }
return c.JSON(fiber.Map{ return c.JSON(fiber.Map{
"message": "",
"userId": user.Id, "userId": user.Id,
"userType": user.UserType, "userType": user.UserType,
"userName": user.Name, "userName": user.Name,
@ -67,44 +90,54 @@ func AddUser(c *fiber.Ctx) error {
var data map[string]string var data map[string]string
if err := c.BodyParser(&data); err != nil { if err := c.BodyParser(&data); err != nil {
return fiber.ErrBadRequest return c.JSON(fiber.Map{
"message": "Dados inválidos"})
} }
// If I don't receive an auth field in the request, I need to verify if the sender is logged if data["name"] == "" || data["email"] == "" || data["password"] == "" || data["channel"] == "" || data["usertype"] == "" || data["companyname"] == "" {
if data["auth"] == "" { return c.JSON(fiber.Map{
_, err := utils.ProcessToken(c) "message": "Dados inválidos"})
if err != nil {
return fiber.ErrUnauthorized
}
}
if data["name"] == "" || data["email"] == "" || data["password"] == "" || data["channel"] == "" {
return fiber.ErrBadRequest
} }
passwd, _ := utils.HashPassword(data["password"]) passwd, _ := utils.HashPassword(data["password"])
user := models.User{ var user models.User
database.DB.Where("email = ?", data["email"]).First(&user)
if user.Id != 0 {
return c.JSON(fiber.Map{
"message": "Usuário já cadastrado"})
}
database.DB.Where("channel = ?", strings.ToLower(data["channel"])).First(&user)
if user.Id != 0 {
return c.JSON(fiber.Map{
"message": "Canal já em uso"})
}
user = models.User{
Name: data["name"], Name: data["name"],
Email: data["email"], Email: data["email"],
CompanyName: data["companyname"], CompanyName: data["companyname"],
Password: passwd, Password: passwd,
Channel: data["channel"], Channel: strings.ToLower(data["channel"]),
UserType: data["usertype"], UserType: data["usertype"],
Blocked: "N", Blocked: "N",
Cancelled: "N", Cancelled: "N",
CreatedBy: data["creator"], CreatedBy: data["createdby"],
} }
database.DB.Create(&user) database.DB.Create(&user)
if user.Id == 0 { if user.Id == 0 {
return fiber.ErrNotAcceptable return c.JSON(fiber.Map{
"message": "Erro ao criar usuário"})
} }
return c.JSON(fiber.Map{ return c.JSON(user)
"user": user,
})
} }
// GetOwnUser - Returns the current user // GetOwnUser - Returns the current user
@ -146,3 +179,15 @@ func GetAllUsers(c *fiber.Ctx) error {
return c.JSON(users) return c.JSON(users)
} }
func WixIntegration(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return fiber.ErrBadRequest
}
utils.PrettyPrintJson(data)
return c.JSON(data)
}

View File

@ -57,7 +57,6 @@ func AddEvent(c *fiber.Ctx) error {
Name: data["name"], Name: data["name"],
Description: data["description"], Description: data["description"],
UserId: user.Id, UserId: user.Id,
Channel: user.Channel,
ExpectedDate: startdt, ExpectedDate: startdt,
EventType: data["eventtype"], EventType: data["eventtype"],
} }
@ -89,3 +88,29 @@ func GetAllEvents(c *fiber.Ctx) error {
return c.JSON(events) return c.JSON(events)
} }
// GetEventsByUser - Returns all events from a user
func GetEventsByUser(c *fiber.Ctx) error {
var events []models.Event
var user models.User
_, err := utils.ProcessToken(c)
if err != nil {
return fiber.ErrUnauthorized
}
database.DB.Where("id = ?", c.Params("id")).First(&user)
if user.Id == 0 {
return fiber.ErrUnauthorized
}
database.DB.Where("user_id = ?", user.Id).Find(&events)
if len(events) == 0 {
return fiber.ErrNotFound
}
return c.JSON(events)
}

View File

@ -8,8 +8,8 @@ import (
func Version(c *fiber.Ctx) error { func Version(c *fiber.Ctx) error {
if globals.API_RELEASE == "" { if globals.API_RELEASE == "" {
return c.JSON(globals.API_VERSION) return c.SendString(globals.API_VERSION)
} else { } else {
return c.JSON(globals.API_VERSION + "-" + globals.API_RELEASE) return c.SendString(globals.API_VERSION + "-" + globals.API_RELEASE)
} }
} }

View File

@ -1,75 +1,73 @@
package controllers package controllers
import ( import (
"fmt" "api/models"
"api/utils"
"log" "log"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
type Pub struct {
Server string `json:"server_id"`
Protocol string `json:"protocol"`
Url string `json:"url"`
AppName string `json:"app_name"`
Channel string `json:"stream_name"`
UrlParam string `json:"url_param"`
RemoteAddress string `json:"remotet_addr"`
HasInSession bool `json:"has_in_session"`
HasOutSession bool `json:"has_out_session"`
}
type Update struct {
Server string `json:"server_id"`
Groups []Group `json:"groups"`
}
type Group struct {
Channel string `json:"stream_name"`
AudioCodec string `json:"audio_codec"`
VideoCodec string `json:"video_codec"`
VideoWidth int `json:"video_width"`
VideoHeight int `json:"video_height"`
UpdPub UpdPub `json:"pub"`
Subs string `json:"subs"`
UpdPull UpdPub `json:"pull"`
}
type UpdPub struct {
Protocol string `json:"protocol"`
SessionId string `json:"session_id"`
RemoteAddress string `json:"remote_addr"`
StartTime string `json:"start_time"`
ReadBytesSum int `json:"read_bytes_sum"`
WroteBytesSum int `json:"wrote_bytes_sum"`
Bitrate int `json:"bitrate"`
ReadBitrate int `json:"read_bitrate"`
WriteBitrate int `json:"write_bitrate"`
}
func ServerStart(c *fiber.Ctx) error { func ServerStart(c *fiber.Ctx) error {
fmt.Println("Server started") // Creates a server struct
log.Println(string(c.Body())) s := new(models.LalServer)
// Parse the body of the request to the server struct
if err := c.BodyParser(s); err != nil {
log.Printf("Error Start: %s\n", err)
return err
}
log.Printf("Server started")
// Marshal the server struct to JSON
utils.PrettyPrintJson(s)
return c.SendString("Server started: " + string(c.Body())) return c.SendString("Server started: " + string(c.Body()))
} }
func OnUpdate(c *fiber.Ctx) error { func OnUpdate(c *fiber.Ctx) error {
p := new(Update) p := new(models.Update)
if err := c.BodyParser(p); err != nil { if err := c.BodyParser(p); err != nil {
log.Printf("Error Update: %s\n", err) log.Printf("Error Update: %s\n", err)
return err return err
} }
log.Printf("Update")
utils.PrettyPrintJson(p)
if len(p.Groups) > 0 { if len(p.Groups) > 0 {
for _, g := range p.Groups { for _, g := range p.Groups {
log.Printf("Update %s %s [(%dx%d) %d]\n", g.Channel, g.UpdPub.StartTime, g.VideoWidth, g.VideoHeight, g.UpdPub.ReadBytesSum) log.Printf("Update %s %s [(%dx%d) %d]\n", g.Channel, g.UpdPub.StartTime, g.VideoWidth, g.VideoHeight, g.UpdPub.ReadBytesSum)
} }
} }
return c.SendString("On_Update: " + string(c.Body())) return c.SendString("On_Update: " + string(c.Body()))
} }
func OnSubStart(c *fiber.Ctx) error {
p := new(models.Update)
if err := c.BodyParser(p); err != nil {
log.Printf("Error SubStart: %s\n", err)
return err
}
log.Printf("SubStart")
utils.PrettyPrintJson(p)
// if len(p.Groups) > 0 {
// for _, g := range p.Groups {
// log.Printf("Update %s %s [(%dx%d) %d]\n", g.Channel, g.UpdPub.StartTime, g.VideoWidth, g.VideoHeight, g.UpdPub.ReadBytesSum)
// }
// }
return c.SendString("On_Substart: " + string(c.Body()))
}
func OnPubStart(c *fiber.Ctx) error { func OnPubStart(c *fiber.Ctx) error {
p := new(Pub) // ================================================================
// Called when a publisher starts streaming - Start of Transmission
// ================================================================
p := new(models.Pub)
if err := c.BodyParser(p); err != nil { if err := c.BodyParser(p); err != nil {
return err return err
} }
@ -78,7 +76,10 @@ func OnPubStart(c *fiber.Ctx) error {
} }
func OnPubStop(c *fiber.Ctx) error { func OnPubStop(c *fiber.Ctx) error {
p := new(Pub) // =============================================================
// Called when a publisher stops streaming - End of Transmission
// =============================================================
p := new(models.Pub)
if err := c.BodyParser(p); err != nil { if err := c.BodyParser(p); err != nil {
return err return err
} }

View File

@ -86,7 +86,7 @@ func ConnectDB() error {
Email: "pcast@pcast.com.br", Email: "pcast@pcast.com.br",
CompanyName: "PCast", CompanyName: "PCast",
Password: passwd, Password: passwd,
Channel: "PCast", Channel: "pcast",
UserType: "A", UserType: "A",
Blocked: "N", Blocked: "N",
Cancelled: "N", Cancelled: "N",

View File

@ -1,6 +1,6 @@
package globals package globals
var ( var (
API_VERSION = "1.0.18" API_VERSION = "1.0.21"
API_RELEASE = "" API_RELEASE = ""
) )

30
index.html Normal file
View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>HLS.js Example</title>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="videoPlayer" controls autoplay></video>
<script>
if (Hls.isSupported()) {
var video = document.getElementById('videoPlayer');
var hls = new Hls();
hls.loadSource('http://localhost:8080/hls/teste/playlist.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
video.play();
});
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = 'http://localhost:8080/hls/teste/playlist.m3u8';
video.addEventListener('loadedmetadata', function () {
video.play();
});
}
</script>
</body>
</html>

View File

@ -6,12 +6,3 @@ http://www.pcastt.com.br, http://pcastt.com.br, https://www.pcastt.com.br, https
reverse_proxy localhost:8111 reverse_proxy localhost:8111
} }
} }
http://www.pcastlive.com.br, http://pcastlive.com.br, https://www.pcastlive.com.br, https://pcastlive.com.br {
root * /root/sites/pcastlive
file_server
handle_path /api/* {
reverse_proxy localhost:8112
}
}

12
infra/mqtt.service Normal file
View File

@ -0,0 +1,12 @@
[Unit]
Description=Mqtt Broker
After=multi-user.target
[Service]
WorkingDirectory=/root/mqtt/cmd
ExecStart=/root/mqtt/cmd/mqtt
Type=simple
[Install]
WantedBy=multi-user.target

View File

@ -1,4 +1,4 @@
service api stop service api stop
cp /home/ftpuser/ftp/files/api /root/api cp /home/ftpuser/ftp/files/api /root/api
chmod 777 /root//api/api chmod 777 /root/api/api
service api start service api start

40
main.go
View File

@ -14,47 +14,53 @@ import (
) )
func main() { func main() {
logFile, err := os.OpenFile("api.log", os.O_CREATE | os.O_APPEND | os.O_RDWR, 0666) logFile, err := os.OpenFile("api.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
if err != nil { if err != nil {
panic(err) panic(err)
} }
mw := io.MultiWriter(os.Stdout, logFile) mw := io.MultiWriter(os.Stdout, logFile)
log.SetOutput(mw) log.SetOutput(mw)
log.Println("Starting API", globals.API_VERSION) log.Println("Starting API", globals.API_VERSION)
log.Println("OS:", os.Getenv("OS")) log.Println("OS:", os.Getenv("OS"))
app := fiber.New(fiber.Config{
StrictRouting: false,
DisableStartupMessage: true,
})
app.Use(cors.New(cors.Config{
AllowCredentials: true,
AllowOrigins: "http://*, https://*",
AllowHeaders: "Origin, Content-Type, Accept, Authorization, Access-Control-Allow-Origin",
AllowMethods: "GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS",
}))
file, err := os.OpenFile("./api-homolog.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) file, err := os.OpenFile("./api-homolog.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil { if err != nil {
log.Fatalf("error opening file: %v", err) log.Fatalf("error opening file: %v", err)
} }
defer file.Close() defer file.Close()
app := fiber.New(fiber.Config{
StrictRouting: false,
DisableStartupMessage: true,
})
app.Use(logger.New(logger.Config{ app.Use(logger.New(logger.Config{
Output: file, Output: file,
})) }))
app.Use(cors.New(cors.Config{
AllowHeaders: "Origin,Content-Type,Accept,Content-Length,Accept-Language,Accept-Encoding,Connection,Access-Control-Allow-Origin",
AllowOrigins: "*",
AllowCredentials: true,
AllowMethods: "GET,POST,HEAD,PUT,DELETE,PATCH,OPTIONS",
}))
if err := database.ConnectDB(); err != nil { if err := database.ConnectDB(); err != nil {
panic("Could not connect to database") panic("Could not connect to database")
} }
routes.Setup(app) routes.Setup(app)
app.Use(func(c *fiber.Ctx) error {
return c.Status(fiber.StatusNotFound).SendString(c.BaseURL()) // => 404 "Not Found"
})
log.Println("Server started in port " + os.Getenv("API_PORT")) log.Println("Server started in port " + os.Getenv("API_PORT"))
app.Listen(":" + os.Getenv("API_PORT")) if erro := app.Listen(":" + os.Getenv("API_PORT")); err != nil {
panic(erro)
}
} }

View File

@ -8,7 +8,6 @@ type Event struct {
Description string `gorm:"not null" json:"description"` Description string `gorm:"not null" json:"description"`
ExpectedDate time.Time `gorm:"not null" json:"startDt"` ExpectedDate time.Time `gorm:"not null" json:"startDt"`
UserId uint `gorm:"size:40;not null" json:"user"` UserId uint `gorm:"size:40;not null" json:"user"`
Channel string `gorm:"size:40;not null" json:"channel"`
EventType string `gorm:"size:1;not null;default:O" json:"eventtype"` // O = Open, C = Closed EventType string `gorm:"size:1;not null;default:O" json:"eventtype"` // O = Open, C = Closed
Transmitted string `gorm:"size:1;not null;default:N" json:"transmitted"` // Y = Already transmitted, N = Not transmitted yet Transmitted string `gorm:"size:1;not null;default:N" json:"transmitted"` // Y = Already transmitted, N = Not transmitted yet
} }

View File

@ -8,6 +8,7 @@ type User struct {
Password []byte `gorm:"size:100;not null;" json:"-"` Password []byte `gorm:"size:100;not null;" json:"-"`
Channel string `gorm:"size:40;not null" json:"channel"` Channel string `gorm:"size:40;not null" json:"channel"`
UserType string `gorm:"size:1;not null;default:U" json:"usertype"` UserType string `gorm:"size:1;not null;default:U" json:"usertype"`
Plan string `gorm:"size:1;not null;default:1" json:"T"`
Blocked string `gorm:"size:1;not null;default:N" json:"blocked"` Blocked string `gorm:"size:1;not null;default:N" json:"blocked"`
Cancelled string `gorm:"size:1;not null;default:N" json:"cancelled"` Cancelled string `gorm:"size:1;not null;default:N" json:"cancelled"`
CreatedBy string `gorm:"size:15;not null;default:Manual" json:"createdby"` CreatedBy string `gorm:"size:15;not null;default:Manual" json:"createdby"`

51
models/webhooks.go Normal file
View File

@ -0,0 +1,51 @@
package models
type LalServer struct {
Server string `json:"server_id"`
BinInfo string `json:"-"`
LalVersion string `json:"lal_version"`
APIVersion string `json:"-"`
NotifyVersion string `json:"-"`
WebUIVersion string `json:"-"`
StartTime string `json:"start_time"`
}
type Pub struct {
Server string `json:"server_id"`
Protocol string `json:"protocol"`
Url string `json:"url"`
AppName string `json:"app_name"`
Channel string `json:"stream_name"`
UrlParam string `json:"url_param"`
RemoteAddress string `json:"remotet_addr"`
HasInSession bool `json:"has_in_session"`
HasOutSession bool `json:"has_out_session"`
}
type Update struct {
LalServer string `json:"server_id"`
Groups []Group `json:"groups"`
}
type Group struct {
Channel string `json:"stream_name"`
AudioCodec string `json:"audio_codec"`
VideoCodec string `json:"video_codec"`
VideoWidth int `json:"video_width"`
VideoHeight int `json:"video_height"`
UpdPub UpdPub `json:"pub"`
Subs string `json:"subs"`
UpdPull UpdPub `json:"pull"`
}
type UpdPub struct {
Protocol string `json:"protocol"`
SessionId string `json:"session_id"`
RemoteAddress string `json:"remote_addr"`
StartTime string `json:"start_time"`
ReadBytesSum int `json:"read_bytes_sum"`
WroteBytesSum int `json:"wrote_bytes_sum"`
Bitrate int `json:"bitrate"`
ReadBitrate int `json:"read_bitrate"`
WriteBitrate int `json:"write_bitrate"`
}

View File

@ -12,6 +12,8 @@ import (
// Setup sets up the routes // Setup sets up the routes
func Setup(app *fiber.App) { func Setup(app *fiber.App) {
app.Post("/integration", controllers.WixIntegration)
app.Get("/version", controllers.Version) app.Get("/version", controllers.Version)
app.Post("/login", controllers.Login) app.Post("/login", controllers.Login)
@ -23,6 +25,7 @@ func Setup(app *fiber.App) {
app.Post("/on_update", controllers.OnUpdate) app.Post("/on_update", controllers.OnUpdate)
app.Post("/on_pub_start", controllers.OnPubStart) app.Post("/on_pub_start", controllers.OnPubStart)
app.Post("/on_pub_stop", controllers.OnPubStop) app.Post("/on_pub_stop", controllers.OnPubStop)
app.Post("/on_sub_start", controllers.OnSubStart)
// Protected routes. Needs login before. // Protected routes. Needs login before.
protected := app.Group("/") protected := app.Group("/")
@ -38,4 +41,6 @@ func Setup(app *fiber.App) {
protected.Post("user", controllers.AddUser) protected.Post("user", controllers.AddUser)
protected.Post("event", controllers.AddEvent) protected.Post("event", controllers.AddEvent)
protected.Get("events", controllers.GetAllEvents)
protected.Get("events/:id", controllers.GetEventsByUser)
} }

View File

@ -1,7 +1,9 @@
package utils package utils
import ( import (
"encoding/json"
"fmt" "fmt"
"log"
"os" "os"
"strings" "strings"
@ -61,3 +63,11 @@ func ProcessToken(c *fiber.Ctx) (interface{}, error) {
func jwtKeyFunc(token *jwt.Token) (interface{}, error) { func jwtKeyFunc(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("API_SECRET")), nil return []byte(os.Getenv("API_SECRET")), nil
} }
func PrettyPrintJson(data interface{}) {
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
fmt.Println("error:", err)
}
log.Println(string(b))
}