commit
0d166f2d13
3
backend/services/controller/.gitignore
vendored
3
backend/services/controller/.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
/.env.local
|
||||
run.prod.sh
|
||||
run.prod.sh
|
||||
/tmp
|
||||
|
|
@ -11,9 +11,13 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/gomodule/redigo v1.8.4 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googollee/go-socket.io v1.7.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
|
|
|
|||
|
|
@ -5,16 +5,23 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
|
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/eclipse/paho.golang v0.10.0 h1:oUGPjRwWcZQRgDD9wVDV7y7i7yBSxts3vcvcNJo8B4Q=
|
||||
github.com/eclipse/paho.golang v0.10.0/go.mod h1:rhrV37IEwauUyx8FHrvmXOKo+QRKng5ncoN1vJiJMcs=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.8.4 h1:Z5JUg94HMTR1XpwBaSH4vq3+PNSIykBLxMdglbw10gg=
|
||||
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googollee/go-socket.io v1.7.0 h1:ODcQSAvVIPvKozXtUGuJDV3pLwdpBLDs1Uoq/QHIlY8=
|
||||
github.com/googollee/go-socket.io v1.7.0/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
|
|
@ -34,6 +41,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
|
||||
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
|
@ -71,6 +79,8 @@ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175
|
|||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ type Api struct {
|
|||
QMutex *sync.Mutex
|
||||
}
|
||||
|
||||
const (
|
||||
NormalUser = iota
|
||||
AdminUser
|
||||
)
|
||||
|
||||
func NewApi(port string, db db.Database, b mtp.Broker, msgQueue map[string](chan usp_msg.Msg), m *sync.Mutex) Api {
|
||||
return Api{
|
||||
Port: port,
|
||||
|
|
@ -36,25 +41,40 @@ func NewApi(port string, db db.Database, b mtp.Broker, msgQueue map[string](chan
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: restructure http api calls for mqtt, to use golang generics and avoid code repetition
|
||||
//TODO: standardize timeouts through code
|
||||
//TODO: fix api methods
|
||||
|
||||
func StartApi(a Api) {
|
||||
r := mux.NewRouter()
|
||||
authentication := r.PathPrefix("/api/auth").Subrouter()
|
||||
authentication.HandleFunc("/login", a.generateToken).Methods("PUT")
|
||||
//authentication.HandleFunc("/register", a.registerUser).Methods("POST")
|
||||
authentication.HandleFunc("/register", a.registerUser).Methods("POST")
|
||||
// Keep the line above commented to avoid people get unintended admin privileges.
|
||||
// Uncomment it only once for you to get admin privileges and create new users.
|
||||
//authentication.HandleFunc("/admin/register", a.registerAdminUser).Methods("POST")
|
||||
iot := r.PathPrefix("/api/device").Subrouter()
|
||||
iot.HandleFunc("", a.retrieveDevices).Methods("GET")
|
||||
iot.HandleFunc("/{sn}/get", a.deviceGetMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/add", a.deviceCreateMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/del", a.deviceDeleteMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/set", a.deviceUpdateMsg).Methods("PUT")
|
||||
//TODO: Create operation action handler
|
||||
iot.HandleFunc("/device/{sn}/act", a.deviceUpdateMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/parameters", a.deviceGetSupportedParametersMsg).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/instances", a.deviceGetParameterInstances).Methods("PUT")
|
||||
iot.HandleFunc("/{sn}/update", a.deviceFwUpdate).Methods("PUT")
|
||||
|
||||
// Middleware for requests which requires user to be authenticated
|
||||
iot.Use(func(handler http.Handler) http.Handler {
|
||||
return middleware.Middleware(handler)
|
||||
})
|
||||
|
||||
users := r.PathPrefix("/api/users").Subrouter()
|
||||
users.HandleFunc("", a.retrieveUsers).Methods("GET")
|
||||
|
||||
users.Use(func(handler http.Handler) http.Handler {
|
||||
return middleware.Middleware(handler)
|
||||
})
|
||||
|
||||
// Verifies CORS configs for requests
|
||||
corsOpts := cors.GetCorsConfig()
|
||||
|
||||
|
|
@ -91,6 +111,225 @@ func (a *Api) retrieveDevices(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
func (a *Api) retrieveUsers(w http.ResponseWriter, r *http.Request) {
|
||||
users, err := a.Db.FindAllUsers()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for _, x := range users {
|
||||
delete(x, "password")
|
||||
}
|
||||
|
||||
err = json.NewEncoder(w).Encode(users)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Check which fw image is activated
|
||||
func checkAvaiableFwPartition(reqPathResult []*usp_msg.GetResp_RequestedPathResult) int {
|
||||
for _, x := range reqPathResult {
|
||||
partitionsNumber := len(x.ResolvedPathResults)
|
||||
if partitionsNumber > 1 {
|
||||
log.Printf("Device has %d firmware partitions", partitionsNumber)
|
||||
}
|
||||
for i, y := range x.ResolvedPathResults {
|
||||
if y.ResultParams["Status"] == "Available" {
|
||||
log.Printf("Partition %d is avaiable", i)
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (a *Api) deviceFwUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
sn := vars["sn"]
|
||||
a.deviceExists(sn, w)
|
||||
|
||||
msg := utils.NewGetMsg(usp_msg.Get{
|
||||
ParamPaths: []string{"Device.DeviceInfo.FirmwareImage.*.Status"},
|
||||
MaxDepth: 1,
|
||||
})
|
||||
encodedMsg, err := proto.Marshal(&msg)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
record := utils.NewUspRecord(encodedMsg, sn)
|
||||
tr369Message, err := proto.Marshal(&record)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to encode tr369 record:", err)
|
||||
}
|
||||
|
||||
a.MsgQueue[msg.Header.MsgId] = make(chan usp_msg.Msg)
|
||||
a.Broker.Publish(tr369Message, "oktopus/v1/agent/"+sn, "oktopus/v1/api/"+sn)
|
||||
|
||||
var getMsgAnswer *usp_msg.GetResp
|
||||
|
||||
select {
|
||||
case msg := <-a.MsgQueue[msg.Header.MsgId]:
|
||||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
getMsgAnswer = msg.Body.GetResponse().GetGetResp()
|
||||
case <-time.After(time.Second * 30):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
return
|
||||
}
|
||||
|
||||
// Check which fw image is activated
|
||||
partition := checkAvaiableFwPartition(getMsgAnswer.ReqPathResults)
|
||||
if partition < 0 {
|
||||
log.Println("Error to get device available firmware partition, probably it has only one partition")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
json.NewEncoder(w).Encode("Server don't have the hability to update device with only one partition")
|
||||
return
|
||||
//TODO: update device with only one partition
|
||||
}
|
||||
|
||||
var receiver = usp_msg.Operate{
|
||||
Command: "Device.DeviceInfo.FirmwareImage.1.Download()",
|
||||
CommandKey: "Download()",
|
||||
SendResp: true,
|
||||
InputArgs: map[string]string{
|
||||
"URL": "http://cronos.intelbras.com.br/download/PON/121AC/beta/121AC-2.3-230620-77753201df4f1e2c607a7236746c8491.tar", //TODO: use dynamic url
|
||||
"AutoActivate": "true",
|
||||
//"Username": "",
|
||||
//"Password": "",
|
||||
"FileSize": "0", //TODO: send firmware length
|
||||
//"CheckSumAlgorithm": "",
|
||||
//"CheckSum": "",
|
||||
},
|
||||
}
|
||||
|
||||
msg = utils.NewOperateMsg(receiver)
|
||||
encodedMsg, err = proto.Marshal(&msg)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
record = utils.NewUspRecord(encodedMsg, sn)
|
||||
tr369Message, err = proto.Marshal(&record)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to encode tr369 record:", err)
|
||||
}
|
||||
|
||||
a.MsgQueue[msg.Header.MsgId] = make(chan usp_msg.Msg)
|
||||
a.Broker.Publish(tr369Message, "oktopus/v1/agent/"+sn, "oktopus/v1/api/"+sn)
|
||||
|
||||
select {
|
||||
case msg := <-a.MsgQueue[msg.Header.MsgId]:
|
||||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetSetResp())
|
||||
return
|
||||
case <-time.After(time.Second * 28):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Api) deviceGetParameterInstances(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
sn := vars["sn"]
|
||||
a.deviceExists(sn, w)
|
||||
|
||||
var receiver usp_msg.GetInstances
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&receiver)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
msg := utils.NewGetParametersInstancesMsg(receiver)
|
||||
encodedMsg, err := proto.Marshal(&msg)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
record := utils.NewUspRecord(encodedMsg, sn)
|
||||
tr369Message, err := proto.Marshal(&record)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to encode tr369 record:", err)
|
||||
}
|
||||
|
||||
//a.Broker.Request(tr369Message, usp_msg.Header_GET, "oktopus/v1/agent/"+sn, "oktopus/v1/get/"+sn)
|
||||
a.MsgQueue[msg.Header.MsgId] = make(chan usp_msg.Msg)
|
||||
a.Broker.Publish(tr369Message, "oktopus/v1/agent/"+sn, "oktopus/v1/api/"+sn)
|
||||
|
||||
select {
|
||||
case msg := <-a.MsgQueue[msg.Header.MsgId]:
|
||||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetGetInstancesResp())
|
||||
return
|
||||
case <-time.After(time.Second * 28):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Api) deviceGetSupportedParametersMsg(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
sn := vars["sn"]
|
||||
a.deviceExists(sn, w)
|
||||
|
||||
var receiver usp_msg.GetSupportedDM
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&receiver)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
msg := utils.NewGetSupportedParametersMsg(receiver)
|
||||
encodedMsg, err := proto.Marshal(&msg)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
record := utils.NewUspRecord(encodedMsg, sn)
|
||||
tr369Message, err := proto.Marshal(&record)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to encode tr369 record:", err)
|
||||
}
|
||||
|
||||
//a.Broker.Request(tr369Message, usp_msg.Header_GET, "oktopus/v1/agent/"+sn, "oktopus/v1/get/"+sn)
|
||||
a.MsgQueue[msg.Header.MsgId] = make(chan usp_msg.Msg)
|
||||
a.Broker.Publish(tr369Message, "oktopus/v1/agent/"+sn, "oktopus/v1/api/"+sn)
|
||||
|
||||
select {
|
||||
case msg := <-a.MsgQueue[msg.Header.MsgId]:
|
||||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetGetSupportedDmResp())
|
||||
return
|
||||
case <-time.After(time.Second * 28):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Api) deviceCreateMsg(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
sn := vars["sn"]
|
||||
|
|
@ -128,7 +367,7 @@ func (a *Api) deviceCreateMsg(w http.ResponseWriter, r *http.Request) {
|
|||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetAddResp())
|
||||
return
|
||||
case <-time.After(time.Second * 5):
|
||||
case <-time.After(time.Second * 28):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
|
|
@ -173,7 +412,7 @@ func (a *Api) deviceGetMsg(w http.ResponseWriter, r *http.Request) {
|
|||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetGetResp())
|
||||
return
|
||||
case <-time.After(time.Second * 5):
|
||||
case <-time.After(time.Second * 30):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
|
|
@ -218,7 +457,7 @@ func (a *Api) deviceDeleteMsg(w http.ResponseWriter, r *http.Request) {
|
|||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetDeleteResp())
|
||||
return
|
||||
case <-time.After(time.Second * 5):
|
||||
case <-time.After(time.Second * 28):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
|
|
@ -263,7 +502,7 @@ func (a *Api) deviceUpdateMsg(w http.ResponseWriter, r *http.Request) {
|
|||
log.Printf("Received Msg: %s", msg.Header.MsgId)
|
||||
json.NewEncoder(w).Encode(msg.Body.GetResponse().GetSetResp())
|
||||
return
|
||||
case <-time.After(time.Second * 5):
|
||||
case <-time.After(time.Second * 28):
|
||||
log.Printf("Request %s Timed Out", msg.Header.MsgId)
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
json.NewEncoder(w).Encode("Request Timed Out")
|
||||
|
|
@ -285,6 +524,47 @@ func (a *Api) deviceExists(sn string, w http.ResponseWriter) {
|
|||
}
|
||||
|
||||
func (a *Api) registerUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
tokenString := r.Header.Get("Authorization")
|
||||
if tokenString == "" {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
email, err := auth.ValidateToken(tokenString)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
//Check if user which is requesting creation has the necessary privileges
|
||||
rUser, err := a.Db.FindUser(email)
|
||||
if rUser.Level != AdminUser {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var user db.User
|
||||
err = json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user.Level = NormalUser
|
||||
|
||||
if err := user.HashPassword(user.Password); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.Db.RegisterUser(user); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Api) registerAdminUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var user db.User
|
||||
err := json.NewDecoder(r.Body).Decode(&user)
|
||||
if err != nil {
|
||||
|
|
@ -292,6 +572,8 @@ func (a *Api) registerUser(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
user.Level = AdminUser
|
||||
|
||||
if err := user.HashPassword(user.Password); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import (
|
|||
type User struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Level int `json:"level"`
|
||||
}
|
||||
|
||||
func (d *Database) RegisterUser(user User) error {
|
||||
|
|
@ -25,6 +26,18 @@ func (d *Database) RegisterUser(user User) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (d *Database) FindAllUsers() ([]map[string]interface{}, error) {
|
||||
var result []map[string]interface{}
|
||||
cursor, err := d.users.Find(d.ctx, bson.D{{}})
|
||||
if err != nil {
|
||||
return []map[string]interface{}{}, err
|
||||
}
|
||||
if err = cursor.All(d.ctx, &result); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (d *Database) FindUser(email string) (User, error) {
|
||||
var result User
|
||||
err := d.users.FindOne(d.ctx, bson.D{{"email", email}}).Decode(&result)
|
||||
|
|
|
|||
|
|
@ -140,6 +140,12 @@ func (m *Mqtt) startClient(devices, controller, disconnect, apiMsg chan *paho.Pu
|
|||
clientConfig := paho.ClientConfig{
|
||||
Conn: conn,
|
||||
Router: singleHandler,
|
||||
OnServerDisconnect: func(disconnect *paho.Disconnect) {
|
||||
log.Println("disconnected from mqtt server, reason code: ", disconnect.ReasonCode)
|
||||
},
|
||||
OnClientError: func(err error) {
|
||||
log.Println(err)
|
||||
},
|
||||
}
|
||||
|
||||
return paho.NewClient(clientConfig)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"net"
|
||||
)
|
||||
|
||||
//Status are saved at database as numbers
|
||||
// Status are saved at database as numbers
|
||||
const (
|
||||
Online = iota
|
||||
Associating
|
||||
|
|
@ -115,3 +115,57 @@ func NewSetMsg(updateStuff usp_msg.Set) usp_msg.Msg {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewGetSupportedParametersMsg(getStuff usp_msg.GetSupportedDM) usp_msg.Msg {
|
||||
return usp_msg.Msg{
|
||||
Header: &usp_msg.Header{
|
||||
MsgId: uuid.NewString(),
|
||||
MsgType: usp_msg.Header_GET_SUPPORTED_DM,
|
||||
},
|
||||
Body: &usp_msg.Body{
|
||||
MsgBody: &usp_msg.Body_Request{
|
||||
Request: &usp_msg.Request{
|
||||
ReqType: &usp_msg.Request_GetSupportedDm{
|
||||
GetSupportedDm: &getStuff,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewGetParametersInstancesMsg(getStuff usp_msg.GetInstances) usp_msg.Msg {
|
||||
return usp_msg.Msg{
|
||||
Header: &usp_msg.Header{
|
||||
MsgId: uuid.NewString(),
|
||||
MsgType: usp_msg.Header_GET_INSTANCES,
|
||||
},
|
||||
Body: &usp_msg.Body{
|
||||
MsgBody: &usp_msg.Body_Request{
|
||||
Request: &usp_msg.Request{
|
||||
ReqType: &usp_msg.Request_GetInstances{
|
||||
GetInstances: &getStuff,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewOperateMsg(getStuff usp_msg.Operate) usp_msg.Msg {
|
||||
return usp_msg.Msg{
|
||||
Header: &usp_msg.Header{
|
||||
MsgId: uuid.NewString(),
|
||||
MsgType: usp_msg.Header_OPERATE,
|
||||
},
|
||||
Body: &usp_msg.Body{
|
||||
MsgBody: &usp_msg.Body_Request{
|
||||
Request: &usp_msg.Request{
|
||||
ReqType: &usp_msg.Request_Operate{
|
||||
Operate: &getStuff,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
86
backend/services/controller/internal/ws/ws.go
Normal file
86
backend/services/controller/internal/ws/ws.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package ws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
socketio "github.com/googollee/go-socket.io"
|
||||
"github.com/googollee/go-socket.io/engineio"
|
||||
"github.com/googollee/go-socket.io/engineio/transport"
|
||||
"github.com/googollee/go-socket.io/engineio/transport/polling"
|
||||
"github.com/googollee/go-socket.io/engineio/transport/websocket"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/leandrofars/oktopus/internal/api/cors"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Ws() {
|
||||
server := socketio.NewServer(&engineio.Options{
|
||||
PingTimeout: 5 * time.Second,
|
||||
PingInterval: 10 * time.Second,
|
||||
Transports: []transport.Transport{
|
||||
&polling.Transport{
|
||||
Client: &http.Client{
|
||||
Timeout: time.Minute,
|
||||
},
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
&websocket.Transport{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
server.OnConnect("/", func(s socketio.Conn) error {
|
||||
s.SetContext("")
|
||||
fmt.Println("connected:", s.ID())
|
||||
return nil
|
||||
})
|
||||
|
||||
server.OnEvent("/", "offer", func(s socketio.Conn, msg string) string {
|
||||
log.Printf("offer: %s", msg)
|
||||
|
||||
return "test"
|
||||
})
|
||||
|
||||
server.OnError("/", func(s socketio.Conn, e error) {
|
||||
fmt.Println("error:", e)
|
||||
})
|
||||
|
||||
server.OnDisconnect("/", func(s socketio.Conn, reason string) {
|
||||
fmt.Println("closed", reason)
|
||||
})
|
||||
|
||||
go func() {
|
||||
if err := server.Serve(); err != nil {
|
||||
log.Fatalf("socketio listen error: %s\n", err)
|
||||
}
|
||||
}()
|
||||
|
||||
const wsPort = "5000"
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.Handle("/socket.io/", server)
|
||||
|
||||
//r.Use(func(handler http.Handler) http.Handler {
|
||||
// return middleware.Middleware(handler)
|
||||
//})
|
||||
|
||||
corsOpts := cors.GetCorsConfig()
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: "0.0.0.0:" + wsPort,
|
||||
Handler: corsOpts.Handler(r), // Pass our instance of gorilla/mux in.
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}()
|
||||
log.Printf("Running websocket at port %s", wsPort)
|
||||
}
|
||||
1
backend/services/socketio/.gitignore
vendored
Normal file
1
backend/services/socketio/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
||||
783
backend/services/socketio/package-lock.json
generated
Normal file
783
backend/services/socketio/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,783 @@
|
|||
{
|
||||
"name": "socketio",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@koa/cors": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@koa/cors/-/cors-4.0.0.tgz",
|
||||
"integrity": "sha512-Y4RrbvGTlAaa04DBoPBWJqDR5gPj32OOz827ULXfgB1F7piD1MB/zwn8JR2LAnvdILhxUbXbkXGWuNVsFuVFCQ==",
|
||||
"requires": {
|
||||
"vary": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
|
||||
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
|
||||
},
|
||||
"@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
|
||||
},
|
||||
"@types/cors": {
|
||||
"version": "2.8.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
|
||||
"integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz",
|
||||
"integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
||||
"requires": {
|
||||
"mime-types": "~2.1.34",
|
||||
"negotiator": "0.6.3"
|
||||
}
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
|
||||
},
|
||||
"body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
|
||||
},
|
||||
"cache-content-type": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz",
|
||||
"integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==",
|
||||
"requires": {
|
||||
"mime-types": "^2.1.18",
|
||||
"ylru": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"co": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
|
||||
"integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"requires": {
|
||||
"safe-buffer": "5.2.1"
|
||||
}
|
||||
},
|
||||
"content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
|
||||
},
|
||||
"cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"cookies": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz",
|
||||
"integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==",
|
||||
"requires": {
|
||||
"depd": "~2.0.0",
|
||||
"keygrip": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"requires": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"deep-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
||||
"integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw=="
|
||||
},
|
||||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
|
||||
},
|
||||
"depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
|
||||
},
|
||||
"destroy": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
|
||||
},
|
||||
"engine.io": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.4.2.tgz",
|
||||
"integrity": "sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==",
|
||||
"requires": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.4.1",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.0.3",
|
||||
"ws": "~8.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"cookie": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
|
||||
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"engine.io-parser": {
|
||||
"version": "5.0.7",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz",
|
||||
"integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ=="
|
||||
},
|
||||
"escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
|
||||
},
|
||||
"express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"statuses": "2.0.1",
|
||||
"unpipe": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
|
||||
},
|
||||
"fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
|
||||
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-symbols": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"has-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"http-assert": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
|
||||
"integrity": "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==",
|
||||
"requires": {
|
||||
"deep-equal": "~1.0.1",
|
||||
"http-errors": "~1.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
|
||||
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"toidentifier": "1.0.1"
|
||||
}
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"requires": {
|
||||
"depd": "2.0.0",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"toidentifier": "1.0.1"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
|
||||
},
|
||||
"is-generator-function": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
|
||||
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
|
||||
"requires": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"keygrip": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
|
||||
"integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==",
|
||||
"requires": {
|
||||
"tsscmp": "1.0.6"
|
||||
}
|
||||
},
|
||||
"koa": {
|
||||
"version": "2.14.2",
|
||||
"resolved": "https://registry.npmjs.org/koa/-/koa-2.14.2.tgz",
|
||||
"integrity": "sha512-VFI2bpJaodz6P7x2uyLiX6RLYpZmOJqNmoCst/Yyd7hQlszyPwG/I9CQJ63nOtKSxpt5M7NH67V6nJL2BwCl7g==",
|
||||
"requires": {
|
||||
"accepts": "^1.3.5",
|
||||
"cache-content-type": "^1.0.0",
|
||||
"content-disposition": "~0.5.2",
|
||||
"content-type": "^1.0.4",
|
||||
"cookies": "~0.8.0",
|
||||
"debug": "^4.3.2",
|
||||
"delegates": "^1.0.0",
|
||||
"depd": "^2.0.0",
|
||||
"destroy": "^1.0.4",
|
||||
"encodeurl": "^1.0.2",
|
||||
"escape-html": "^1.0.3",
|
||||
"fresh": "~0.5.2",
|
||||
"http-assert": "^1.3.0",
|
||||
"http-errors": "^1.6.3",
|
||||
"is-generator-function": "^1.0.7",
|
||||
"koa-compose": "^4.1.0",
|
||||
"koa-convert": "^2.0.0",
|
||||
"on-finished": "^2.3.0",
|
||||
"only": "~0.0.2",
|
||||
"parseurl": "^1.3.2",
|
||||
"statuses": "^1.5.0",
|
||||
"type-is": "^1.6.16",
|
||||
"vary": "^1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
|
||||
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"koa-compose": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz",
|
||||
"integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw=="
|
||||
},
|
||||
"koa-convert": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-2.0.0.tgz",
|
||||
"integrity": "sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==",
|
||||
"requires": {
|
||||
"co": "^4.6.0",
|
||||
"koa-compose": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"requires": {
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"requires": {
|
||||
"ee-first": "1.1.1"
|
||||
}
|
||||
},
|
||||
"only": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz",
|
||||
"integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ=="
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"requires": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
}
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"requires": {
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"requires": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"requires": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
}
|
||||
},
|
||||
"setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"socket.io": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.6.2.tgz",
|
||||
"integrity": "sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==",
|
||||
"requires": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.4.2",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"socket.io-adapter": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz",
|
||||
"integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==",
|
||||
"requires": {
|
||||
"ws": "~8.11.0"
|
||||
}
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"requires": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
||||
},
|
||||
"toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
|
||||
},
|
||||
"tsscmp": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
|
||||
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
|
||||
},
|
||||
"utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
|
||||
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg=="
|
||||
},
|
||||
"ylru": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ylru/-/ylru-1.3.2.tgz",
|
||||
"integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
20
backend/services/socketio/package.json
Normal file
20
backend/services/socketio/package.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "socketio",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node server.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@koa/cors": "^4.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.18.2",
|
||||
"koa": "^2.14.2",
|
||||
"socket.io": "^4.6.2"
|
||||
}
|
||||
}
|
||||
67
backend/services/socketio/server.js
Normal file
67
backend/services/socketio/server.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
const express = require('express');
|
||||
const app = express();
|
||||
const PORT = 5000;
|
||||
|
||||
const http = require('http').Server(app);
|
||||
const cors = require('cors');
|
||||
|
||||
const io = require('socket.io')(http, {
|
||||
cors: {
|
||||
origin: "http://localhost:3000"
|
||||
}
|
||||
});
|
||||
|
||||
app.use(cors());
|
||||
|
||||
let users = []
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
console.log(`🚀: ${socket.id} user just connected!`);
|
||||
|
||||
socket.on("callUser", ({ userToCall, signalData, from }) => {
|
||||
console.log("user to call:",userToCall)
|
||||
let index = users.findIndex(x =>{
|
||||
return x.name === userToCall
|
||||
})
|
||||
console.log(index)
|
||||
if (index >= 0){
|
||||
console.log("calling user named "+ users[index].name+" and id "+users[index].id)
|
||||
io.to(users[index].id).emit("callUser", { signal: signalData, from });
|
||||
}else{
|
||||
console.log("There is no user named "+userToCall+" or he/she is offline")
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("answerCall", (data) => {
|
||||
io.to(data.to).emit("callAccepted", data.signal);
|
||||
});
|
||||
|
||||
socket.on("newuser", (data) => {
|
||||
let index = users.findIndex(x =>{ x.name === data.name})
|
||||
if (index >=0){
|
||||
console.log("user already exists, but got connected with other id")
|
||||
}else{
|
||||
users.push(data)
|
||||
}
|
||||
console.log(data)
|
||||
console.log("total users: ", users)
|
||||
io.emit('users', users)
|
||||
})
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('🔥: A user disconnected');
|
||||
let index = users.findIndex(x => x.id === socket.id)
|
||||
if (index >= 0){
|
||||
let deletedEl = users.splice(index, 1)
|
||||
console.log("users deleted", deletedEl)
|
||||
console.log("users after disconection: ", users)
|
||||
io.emit('users', users)
|
||||
}else{
|
||||
console.log("couldn't find user with socket id:", socket.id)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
http.listen(PORT, () => {
|
||||
console.log(`Server listening on ${PORT}`);
|
||||
});
|
||||
|
|
@ -77,7 +77,7 @@ http {
|
|||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
location /api {
|
||||
location /api {
|
||||
proxy_pass http://127.0.0.1:8001;
|
||||
proxy_read_timeout 60;
|
||||
proxy_connect_timeout 60;
|
||||
|
|
@ -90,6 +90,19 @@ http {
|
|||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
location /socket.io {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_read_timeout 60;
|
||||
proxy_connect_timeout 60;
|
||||
proxy_redirect off;
|
||||
|
||||
# Allow the use of websockets
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# ----------------------------- Local Environment ---------------------------- #
|
||||
|
||||
NEXT_PUBLIC_REST_ENPOINT="http://localhost:8000"
|
||||
|
||||
NEXT_PUBLIC_REST_ENPOINT="http://localhost:8000/api"
|
||||
NEXT_PUBLIC_WS_ENPOINT="http://localhost:5000/"
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
|
|
@ -9,4 +9,4 @@ NEXT_PUBLIC_REST_ENPOINT="http://localhost:8000"
|
|||
|
||||
#NEXT_PUBLIC_REST_ENPOINT="https://d9962fd9-2464-4a30-9a86-a15a04b57ad0.mock.pstmn.io"
|
||||
|
||||
# ---------------------------------------------------------------------------- #
|
||||
# ---------------------------------------------------------------------------- #
|
||||
|
|
|
|||
2477
frontend/package-lock.json
generated
2477
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
|
@ -32,7 +32,10 @@
|
|||
"react": "18.2.0",
|
||||
"react-apexcharts": "1.4.0",
|
||||
"react-dom": "18.2.0",
|
||||
"simple-peer": "^9.11.1",
|
||||
"simplebar-react": "^3.2.1",
|
||||
"socket.io-client": "^4.6.2",
|
||||
"styled-components": "^6.0.0-rc.3",
|
||||
"yup": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"short_name": "Devias Kit",
|
||||
"name": "Devias Kit",
|
||||
"short_name": "Oktopus TR-369",
|
||||
"name": "Oktopus",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ export const AuthProvider = (props) => {
|
|||
|
||||
try {
|
||||
window.sessionStorage.setItem('authenticated', 'true');
|
||||
window.sessionStorage.setItem('email',email)
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
|
@ -163,7 +164,7 @@ export const AuthProvider = (props) => {
|
|||
id: '5e86809283e28b96d2d38537',
|
||||
avatar: '/assets/avatars/default-avatar.png',
|
||||
name: 'Oktopus',
|
||||
email: 'anika.visser@devias.io',
|
||||
email: email,
|
||||
token: token
|
||||
};
|
||||
|
||||
|
|
|
|||
162
frontend/src/contexts/socketio-context.js
Normal file
162
frontend/src/contexts/socketio-context.js
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
import { createContext, useContext, useEffect, useState, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import io from 'socket.io-client';
|
||||
import { useAuth } from 'src/hooks/use-auth';
|
||||
import Peer from "simple-peer";
|
||||
|
||||
|
||||
// The role of this context is to propagate socketio io state through app tree
|
||||
export const WsContext = createContext({ undefined });
|
||||
|
||||
export const WsProvider = (props) => {
|
||||
const { children } = props;
|
||||
const [users, setUsers] = useState(null)
|
||||
const [callAccepted, setCallAccepted] = useState(false);
|
||||
const [callEnded, setCallEnded] = useState(false);
|
||||
const [stream, setStream] = useState();
|
||||
const [name, setName] = useState("");
|
||||
const [call, setCall] = useState({});
|
||||
|
||||
const myVideo = useRef();
|
||||
const userVideo = useRef();
|
||||
const connectionRef = useRef();
|
||||
const auth = useAuth()
|
||||
const socket = io(process.env.NEXT_PUBLIC_WS_ENPOINT)
|
||||
|
||||
const initialize = async () => {
|
||||
// Prevent from calling twice in development mode with React.StrictMode enable
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[IO] Connect => A new connection has been established')
|
||||
|
||||
socket.on("users", (data) => {
|
||||
setUsers(data)
|
||||
console.log("data received from users event: ", data)
|
||||
})
|
||||
|
||||
socket.emit("newuser",{
|
||||
id: socket.id,
|
||||
name: window.sessionStorage.getItem("email")
|
||||
})
|
||||
|
||||
socket.on("callUser", ({ from, name: callerName, signal }) => {
|
||||
console.log("you're receiving call brow")
|
||||
setCall({ isReceivingCall: true, from, name: callerName, signal });
|
||||
});
|
||||
|
||||
socket.on('disconnect', function(){
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
};
|
||||
|
||||
const answerCall = () => {
|
||||
setCallAccepted(true);
|
||||
|
||||
const peer = new Peer({
|
||||
initiator: false,
|
||||
trickle: false,
|
||||
stream: stream,
|
||||
config: {
|
||||
iceServers: [
|
||||
{url:'stun:stun.l.google.com:19302'},
|
||||
{url:'stun:stun1.l.google.com:19302'},
|
||||
]
|
||||
},
|
||||
});
|
||||
|
||||
peer.on("signal", (data) => {
|
||||
socket.emit("answerCall", { signal: data, to: call.from });
|
||||
});
|
||||
|
||||
peer.on("stream", (currentStream) => {
|
||||
userVideo.current.srcObject = currentStream;
|
||||
});
|
||||
|
||||
peer.signal(call.signal);
|
||||
|
||||
connectionRef.current = peer;
|
||||
};
|
||||
|
||||
|
||||
const callUser = (id) => {
|
||||
|
||||
console.log("calling user ",id)
|
||||
const peer = new Peer({ initiator: true, trickle: false, stream:stream, config: {
|
||||
iceServers: [
|
||||
{url:'stun:stun.l.google.com:19302'},
|
||||
{url:'stun:stun1.l.google.com:19302'},
|
||||
{url:'stun:stun2.l.google.com:19302'},
|
||||
{url:'stun:stun3.l.google.com:19302'},
|
||||
{url:'stun:stun4.l.google.com:19302'},
|
||||
]
|
||||
}, });
|
||||
|
||||
peer.on("signal", (data) => {
|
||||
socket.emit("callUser", {
|
||||
userToCall: id,
|
||||
signalData: data,
|
||||
from: window.sessionStorage.getItem("email"),
|
||||
});
|
||||
});
|
||||
|
||||
peer.on("stream", (currentStream) => {
|
||||
userVideo.current.srcObject = currentStream;
|
||||
});
|
||||
|
||||
socket.on("callAccepted", (signal) => {
|
||||
setCallAccepted(true);
|
||||
|
||||
peer.signal(signal);
|
||||
});
|
||||
|
||||
connectionRef.current = peer;
|
||||
};
|
||||
|
||||
const leaveCall = () => {
|
||||
setCallEnded(true);
|
||||
|
||||
connectionRef.current.destroy();
|
||||
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if(auth.isAuthenticated){
|
||||
initialize();
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[auth.isAuthenticated]
|
||||
);
|
||||
|
||||
return (
|
||||
<WsContext.Provider
|
||||
value={{
|
||||
users,
|
||||
call,
|
||||
callAccepted,
|
||||
myVideo,
|
||||
userVideo,
|
||||
stream,
|
||||
callEnded,
|
||||
callUser,
|
||||
leaveCall,
|
||||
answerCall,
|
||||
setStream
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</WsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
WsProvider.propTypes = {
|
||||
children: PropTypes.node
|
||||
};
|
||||
|
||||
export const WsConsumer = WsContext.Consumer;
|
||||
|
||||
export const useWsContext = () => useContext(WsContext);
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
import ChartBarIcon from '@heroicons/react/24/solid/ChartBarIcon';
|
||||
import CogIcon from '@heroicons/react/24/solid/CogIcon';
|
||||
import LockClosedIcon from '@heroicons/react/24/solid/LockClosedIcon';
|
||||
import ShoppingBagIcon from '@heroicons/react/24/solid/ShoppingBagIcon';
|
||||
import UserIcon from '@heroicons/react/24/solid/UserIcon';
|
||||
import UserPlusIcon from '@heroicons/react/24/solid/UserPlusIcon';
|
||||
import UsersIcon from '@heroicons/react/24/solid/UsersIcon';
|
||||
import ChatBubbleLeftRightIcon from '@heroicons/react/24/solid/ChatBubbleLeftRightIcon'
|
||||
import MapIcon from '@heroicons/react/24/solid/MapIcon'
|
||||
import CpuChip from '@heroicons/react/24/solid/CpuChipIcon';
|
||||
import XCircleIcon from '@heroicons/react/24/solid/XCircleIcon';
|
||||
import { SvgIcon } from '@mui/material';
|
||||
|
||||
export const items = [
|
||||
|
|
@ -28,6 +24,24 @@ export const items = [
|
|||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Chat (beta)',
|
||||
path: '/chat',
|
||||
icon: (
|
||||
<SvgIcon fontSize="small">
|
||||
<ChatBubbleLeftRightIcon/>
|
||||
</SvgIcon>
|
||||
)
|
||||
},
|
||||
// {
|
||||
// title: 'Map',
|
||||
// path: '/',
|
||||
// icon: (
|
||||
// <SvgIcon fontSize="small">
|
||||
// <MapIcon/>
|
||||
// </SvgIcon>
|
||||
// )
|
||||
// },
|
||||
{
|
||||
title: 'Settings',
|
||||
path: '/settings',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import BellIcon from '@heroicons/react/24/solid/BellIcon';
|
||||
import UsersIcon from '@heroicons/react/24/solid/UsersIcon';
|
||||
import PhoneIcon from '@heroicons/react/24/solid/PhoneIcon';
|
||||
import Bars3Icon from '@heroicons/react/24/solid/Bars3Icon';
|
||||
import MagnifyingGlassIcon from '@heroicons/react/24/solid/MagnifyingGlassIcon';
|
||||
import {
|
||||
|
|
@ -11,12 +12,21 @@ import {
|
|||
Stack,
|
||||
SvgIcon,
|
||||
Tooltip,
|
||||
useMediaQuery
|
||||
useMediaQuery,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
Button
|
||||
} from '@mui/material';
|
||||
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
||||
import { alpha } from '@mui/material/styles';
|
||||
import { usePopover } from 'src/hooks/use-popover';
|
||||
import { AccountPopover } from './account-popover';
|
||||
import { useAuth } from 'src/hooks/use-auth';
|
||||
import { WsContext } from 'src/contexts/socketio-context';
|
||||
import { useContext, useEffect } from 'react';
|
||||
|
||||
const SIDE_NAV_WIDTH = 280;
|
||||
const TOP_NAV_HEIGHT = 64;
|
||||
|
|
@ -26,6 +36,7 @@ export const TopNav = (props) => {
|
|||
const lgUp = useMediaQuery((theme) => theme.breakpoints.up('lg'));
|
||||
const accountPopover = usePopover();
|
||||
const auth = useAuth();
|
||||
const { answerCall, call, callAccepted } = useContext(WsContext);
|
||||
|
||||
return ( auth.user &&
|
||||
<>
|
||||
|
|
@ -67,13 +78,13 @@ export const TopNav = (props) => {
|
|||
</SvgIcon>
|
||||
</IconButton>
|
||||
)}
|
||||
<Tooltip title="Search">
|
||||
{/* <Tooltip title="Search">
|
||||
<IconButton>
|
||||
<SvgIcon fontSize="small">
|
||||
<MagnifyingGlassIcon />
|
||||
</SvgIcon>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Tooltip> */}
|
||||
</Stack>
|
||||
<Stack
|
||||
alignItems="center"
|
||||
|
|
@ -113,6 +124,57 @@ export const TopNav = (props) => {
|
|||
</Stack>
|
||||
</Stack>
|
||||
</Box>
|
||||
{call.isReceivingCall && !callAccepted &&
|
||||
<Dialog
|
||||
fullWidth={ true }
|
||||
maxWidth={"sm"}
|
||||
open={true}
|
||||
//scroll={scroll}
|
||||
aria-labelledby="scroll-dialog-title"
|
||||
aria-describedby="scroll-dialog-description"
|
||||
>
|
||||
<DialogContent dividers={scroll === 'paper'}>
|
||||
<Box display="flex" alignItems="center" justifyContent={'center'}>
|
||||
<Box sx={{margin:"30px",textAlign:'center'}}>
|
||||
<Avatar
|
||||
sx={{
|
||||
height: 150,
|
||||
width: 150,
|
||||
}}
|
||||
src={"/assets/avatars/default-avatar.png"}
|
||||
/>
|
||||
<Box flexGrow={1} >{call.from}</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="center" justifyContent={'center'}>
|
||||
<IconButton>
|
||||
<Tooltip title="Refuse" placement="left" onClick={()=>{}}>
|
||||
<SvgIcon
|
||||
sx={{cursor:'pointer'}}
|
||||
style={{transform: "scale(1.5,1.5)"}}
|
||||
>
|
||||
<PhoneIcon
|
||||
color={"#CB1E02"}
|
||||
/>
|
||||
</SvgIcon>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
<div style={{width:'15%'}}></div>
|
||||
<IconButton>
|
||||
<Tooltip title="Accept" placement="right" onClick={()=>{}}>
|
||||
<SvgIcon
|
||||
sx={{cursor:'pointer'}}
|
||||
style={{transform: "scale(1.5,1.5) scale(-1,1)"}}
|
||||
>
|
||||
<PhoneIcon
|
||||
color={"#17A000"}
|
||||
/>
|
||||
</SvgIcon>
|
||||
</Tooltip>
|
||||
</IconButton>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
</Dialog>}
|
||||
<AccountPopover
|
||||
anchorEl={accountPopover.anchorRef.current}
|
||||
open={accountPopover.open}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const Page = () => (
|
|||
<>
|
||||
<Head>
|
||||
<title>
|
||||
404 | Devias Kit
|
||||
404 | Oktopus TR-369
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { useNProgress } from 'src/hooks/use-nprogress';
|
|||
import { createTheme } from 'src/theme';
|
||||
import { createEmotionCache } from 'src/utils/create-emotion-cache';
|
||||
import 'simplebar-react/dist/simplebar.min.css';
|
||||
import { WsProvider } from 'src/contexts/socketio-context';
|
||||
|
||||
const clientSideEmotionCache = createEmotionCache();
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ const App = (props) => {
|
|||
<CacheProvider value={emotionCache}>
|
||||
<Head>
|
||||
<title>
|
||||
Devias Kit
|
||||
Oktopus
|
||||
</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
|
|
@ -36,16 +37,18 @@ const App = (props) => {
|
|||
</Head>
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<AuthProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<AuthConsumer>
|
||||
{
|
||||
(auth) => auth.isLoading
|
||||
? <SplashScreen />
|
||||
: getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
</AuthConsumer>
|
||||
</ThemeProvider>
|
||||
<WsProvider>
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<AuthConsumer>
|
||||
{
|
||||
(auth) => auth.isLoading
|
||||
? <SplashScreen />
|
||||
: getLayout(<Component {...pageProps} />)
|
||||
}
|
||||
</AuthConsumer>
|
||||
</ThemeProvider>
|
||||
</WsProvider>
|
||||
</AuthProvider>
|
||||
</LocalizationProvider>
|
||||
</CacheProvider>
|
||||
|
|
|
|||
154
frontend/src/pages/chat.js
Normal file
154
frontend/src/pages/chat.js
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import React, { useEffect, useState, useContext } from "react";
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import PhoneIcon from "@heroicons/react/24/solid/PhoneIcon";
|
||||
import PhoneXMarkIcon from "@heroicons/react/24/solid/PhoneXMarkIcon"
|
||||
import {
|
||||
Card,
|
||||
Box,
|
||||
CardContent,
|
||||
Container,
|
||||
SvgIcon,
|
||||
CircularProgress,
|
||||
Avatar,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
import { WsContext } from "src/contexts/socketio-context";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const Page = () => {
|
||||
|
||||
//const [isConnected, setIsConnected] = useState(socket.connected);
|
||||
const [users, setUsers] = useState([])
|
||||
//const [onlineUsers, setOnlineUsers] = useState([])
|
||||
|
||||
const ws = useContext(WsContext)
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(()=>{
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var requestOptions = {
|
||||
method: 'GET',
|
||||
headers: myHeaders,
|
||||
redirect: 'follow'
|
||||
};
|
||||
|
||||
fetch(`${process.env.NEXT_PUBLIC_REST_ENPOINT}/users`,requestOptions)
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
// let teste = JSON.stringify(JSON.parse(result), null, 2)
|
||||
setUsers(result)
|
||||
})
|
||||
.catch(error => console.log('error', error));
|
||||
},[])
|
||||
|
||||
const renderUsers = () => {
|
||||
console.log("users: ", users)
|
||||
console.log("wsUsers: ", ws.users)
|
||||
if(users.length == 0){
|
||||
console.log("users is empty")
|
||||
return (
|
||||
<div style={{display:'flex', justifyContent:'center'}} height={'100%'} >
|
||||
<CircularProgress color="inherit" width='100%'/>
|
||||
</div>
|
||||
)
|
||||
}else {
|
||||
return (
|
||||
<Card sx={{
|
||||
display: 'flex',
|
||||
justifyContent:'center',
|
||||
}}>
|
||||
<CardContent>
|
||||
|
||||
<Container sx={{display:'flex',justifyContent:'center'}}>
|
||||
{users.map((x)=> {
|
||||
|
||||
let color = "#CB1E02"
|
||||
let status = "offline"
|
||||
|
||||
if (ws.users.findIndex(y => y.name === x.email) >= 0){
|
||||
console.log("user: "+x.email+" is online")
|
||||
//color = "#11ADFB"
|
||||
color = "#17A000"
|
||||
status = "online"
|
||||
}
|
||||
|
||||
if (x.email !== window.sessionStorage.getItem("email")){
|
||||
return (
|
||||
<Box sx={{margin:"30px",textAlign:'center'}} key={x.email}>
|
||||
<Avatar
|
||||
sx={{
|
||||
height: 150,
|
||||
width: 150,
|
||||
border: '3px solid '+color
|
||||
}}
|
||||
src={"/assets/avatars/default-avatar.png"}
|
||||
/>
|
||||
<div style={{marginTop:'10px'}}>
|
||||
</div>
|
||||
{status === "online" ?
|
||||
<Tooltip title="Call" placement="right" onClick={()=>{
|
||||
router.push({
|
||||
pathname:"chat/room",
|
||||
query: {user: x.email}
|
||||
})
|
||||
}}>
|
||||
<SvgIcon
|
||||
sx={{cursor:'pointer'}}
|
||||
>
|
||||
<PhoneIcon
|
||||
color={color}
|
||||
/>
|
||||
</SvgIcon>
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip title="Offline" placement="right">
|
||||
<SvgIcon
|
||||
sx={{cursor:'default'}}
|
||||
>
|
||||
<PhoneXMarkIcon
|
||||
color={color}
|
||||
/>
|
||||
</SvgIcon>
|
||||
</Tooltip>
|
||||
}
|
||||
<p style={{marginTop:'-2.5px'}}>{x.email}</p>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</Container>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return(ws.users ?
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
py: 10,
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="md">
|
||||
{renderUsers()}
|
||||
</Container>
|
||||
</Box>
|
||||
:
|
||||
<CircularProgress color="inherit" />
|
||||
)
|
||||
}
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
70
frontend/src/pages/chat/room.js
Normal file
70
frontend/src/pages/chat/room.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import React, { useEffect, useState, useContext } from "react";
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import {
|
||||
Card,
|
||||
Box,
|
||||
CardContent,
|
||||
Container,
|
||||
SvgIcon,
|
||||
CircularProgress,
|
||||
Avatar,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
import { WsContext } from "src/contexts/socketio-context";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const Page = (props) => {
|
||||
|
||||
const { callUser, callAccepted, myVideo, userVideo, callEnded, stream, call, setStream } =
|
||||
useContext(WsContext);
|
||||
const router = useRouter()
|
||||
|
||||
const stopCamera = () => {
|
||||
// stream.getTracks().forEach(function(track) {
|
||||
// track.stop();
|
||||
// });
|
||||
//console.log(stream)
|
||||
window.location.reload() //TODO: find better way to stop recording user
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
callUser(router.query.user)
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({ video: true, audio: true })
|
||||
.then((currentStream) => {
|
||||
setStream(currentStream);
|
||||
if (myVideo.current) {
|
||||
myVideo.current.srcObject = currentStream;
|
||||
}
|
||||
})
|
||||
.catch((err)=>{
|
||||
console.log('You cannot place/ receive a call without granting video and audio permissions! Please change your settings to use Oktopus calls.')
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
return(stopCamera)
|
||||
},[])
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
{ myVideo &&
|
||||
<video
|
||||
className="userVideo"
|
||||
playsInline
|
||||
muted
|
||||
ref={myVideo}
|
||||
autoPlay />
|
||||
}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
80
frontend/src/pages/devices/[...id].js
Normal file
80
frontend/src/pages/devices/[...id].js
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import Head from 'next/head';
|
||||
import { Box, Stack, Typography, Container, Unstable_Grid2 as Grid,
|
||||
Tab,
|
||||
Tabs,
|
||||
SvgIcon } from '@mui/material';
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import { useRouter } from 'next/router';
|
||||
import { DevicesRPC } from 'src/sections/devices/devices-rpc';
|
||||
import { DevicesDiscovery } from 'src/sections/devices/devices-discovery';
|
||||
import EnvelopeIcon from '@heroicons/react/24/outline/EnvelopeIcon';
|
||||
import MagnifyingGlassIcon from '@heroicons/react/24/solid/MagnifyingGlassIcon';
|
||||
import WifiIcon from '@heroicons/react/24/solid/WifiIcon';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const Page = () => {
|
||||
const router = useRouter()
|
||||
|
||||
const deviceID = router.query.id[0]
|
||||
const section = router.query.id[1]
|
||||
|
||||
const sectionHandler = () => {
|
||||
switch(section){
|
||||
case "msg":
|
||||
return <DevicesRPC/>
|
||||
case "discovery":
|
||||
return <DevicesDiscovery/>
|
||||
default:
|
||||
return <p>Hello World</p>
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
console.log("deviceid:",deviceID)
|
||||
})
|
||||
|
||||
return(
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
py: 0,
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="lg" >
|
||||
<Stack spacing={3} >
|
||||
<Box sx={{
|
||||
display:'flex',
|
||||
justifyContent:'center'
|
||||
}}
|
||||
mb={3}>
|
||||
<Tabs value={router.query.id[1]} aria-label="icon label tabs example">
|
||||
<Tab icon={<SvgIcon><WifiIcon/></SvgIcon>} iconPosition={"end"} label="Wi-Fi" />
|
||||
<Tab value={"discovery"} onClick={()=>{router.push(`/devices/${deviceID}/discovery`)}} icon={<SvgIcon><MagnifyingGlassIcon/></SvgIcon>} iconPosition={"end"} label="Discover Parameters" />
|
||||
<Tab value={"msg"} onClick={()=>{router.push(`/devices/${deviceID}/msg`)}} icon={<SvgIcon><EnvelopeIcon/></SvgIcon>} iconPosition={"end"} label="Remote Messages" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
{
|
||||
sectionHandler()
|
||||
}
|
||||
</Stack>
|
||||
</Container>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
import Head from 'next/head';
|
||||
import { Box, Stack, Typography, Container, Unstable_Grid2 as Grid } from '@mui/material';
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
import { useRouter } from 'next/router';
|
||||
import { DevicesRPC } from 'src/sections/devices/devices-rpc';
|
||||
|
||||
const Page = () => {
|
||||
const router = useRouter()
|
||||
const { id } = router.query
|
||||
|
||||
|
||||
return(
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
Oktopus | TR-369
|
||||
</title>
|
||||
</Head>
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
py: 0,
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="lg" >
|
||||
<Stack spacing={3} >
|
||||
<Typography variant="h4">
|
||||
RPC
|
||||
</Typography>
|
||||
{/*<SettingsNotifications />*/}
|
||||
< DevicesRPC />
|
||||
</Stack>
|
||||
</Container>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
{page}
|
||||
</DashboardLayout>
|
||||
);
|
||||
|
||||
export default Page;
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import Head from 'next/head';
|
||||
import React, { useState } from 'react';
|
||||
import { subDays, subHours } from 'date-fns';
|
||||
import { Box, Container, Unstable_Grid2 as Grid } from '@mui/material';
|
||||
import { Layout as DashboardLayout } from 'src/layouts/dashboard/layout';
|
||||
|
|
@ -13,7 +14,9 @@ import { OverviewTraffic } from 'src/sections/overview/overview-traffic';
|
|||
|
||||
const now = new Date();
|
||||
|
||||
const Page = () => (
|
||||
const Page = () => {
|
||||
|
||||
return(
|
||||
<>
|
||||
<Head>
|
||||
<title>
|
||||
|
|
@ -109,8 +112,8 @@ const Page = () => (
|
|||
</Grid>
|
||||
</Container>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
</>)
|
||||
};
|
||||
|
||||
Page.getLayout = (page) => (
|
||||
<DashboardLayout>
|
||||
|
|
|
|||
169
frontend/src/sections/devices/devices-discovery.js
Normal file
169
frontend/src/sections/devices/devices-discovery.js
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
SvgIcon,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Collapse,
|
||||
Box,
|
||||
Tabs,
|
||||
Tab
|
||||
} from '@mui/material';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
|
||||
export const DevicesDiscovery = () => {
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const [deviceParameters, setDeviceParameters] = useState(null)
|
||||
|
||||
const initialize = async (raw) => {
|
||||
let content = await getDeviceParameters(raw)
|
||||
setDeviceParameters(content)
|
||||
}
|
||||
|
||||
const getDeviceParameters = async (raw) =>{
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append("Content-Type", "application/json");
|
||||
myHeaders.append("Authorization", localStorage.getItem("token"));
|
||||
|
||||
var requestOptions = {
|
||||
method: 'PUT',
|
||||
headers: myHeaders,
|
||||
redirect: 'follow',
|
||||
body: raw
|
||||
};
|
||||
|
||||
let result = await (await fetch(`${process.env.NEXT_PUBLIC_REST_ENPOINT}/device/${router.query.id[0]}/parameters`, requestOptions))
|
||||
if (result.status != 200) {
|
||||
throw new Error('Please check your email and password');
|
||||
}else{
|
||||
return result.json()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(()=> {
|
||||
|
||||
initialize(
|
||||
JSON.stringify({
|
||||
"obj_paths": ["Device."],
|
||||
"first_level_only" : false,
|
||||
"return_commands" : false,
|
||||
"return_events" : false,
|
||||
"return_params" : true
|
||||
})
|
||||
);
|
||||
},[])
|
||||
|
||||
//Together with showParameters, this function renders all the device parameters the device supports
|
||||
//but you must set req with first_level_only property to false
|
||||
// const showPathParameters = (pathParamsList) => {
|
||||
// return pathParamsList.map((x,i)=>{
|
||||
// return(
|
||||
// <List component="div" disablePadding dense={true}>
|
||||
// <ListItem
|
||||
// key={i}
|
||||
// divider={true}
|
||||
// sx={{
|
||||
// boxShadow: 'rgba(149, 157, 165, 0.2) 0px 0px 5px;',
|
||||
// pl: 4
|
||||
// }}
|
||||
// >
|
||||
// <ListItemText
|
||||
// primary={x.param_name}
|
||||
// />
|
||||
// </ListItem>
|
||||
// </List>
|
||||
// )
|
||||
// })
|
||||
// }
|
||||
|
||||
// const updateDeviceParameters = async (param,) => {
|
||||
|
||||
// let raw = JSON.stringify({
|
||||
// "obj_paths": [param],
|
||||
// "first_level_only" : true,
|
||||
// "return_commands" : false,
|
||||
// "return_events" : false,
|
||||
// "return_params" : true
|
||||
// })
|
||||
|
||||
// let content = await getDeviceParameters(raw)
|
||||
|
||||
// console.log(content)
|
||||
|
||||
// setDeviceParameters(prevState => {
|
||||
// return {...prevState, req_obj_results: [
|
||||
// {
|
||||
// supported_objs:[ ...prevState.req_obj_results[0].
|
||||
// supported_objs][index]
|
||||
// .supported_params:[]
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
const showParameters = () => {
|
||||
console.log(deviceParameters)
|
||||
return deviceParameters.req_obj_results[0].supported_objs.map((x,i)=> {
|
||||
return (
|
||||
<List dense={true}>
|
||||
<ListItem
|
||||
key={x.supported_obj_path}
|
||||
divider={true}
|
||||
// secondaryAction={
|
||||
// <IconButton /*onClick={()=>updateDeviceParameters(x.supported_obj_path, index)}*/>
|
||||
// <SvgIcon>
|
||||
// <PlusCircleIcon></PlusCircleIcon>
|
||||
// </SvgIcon>
|
||||
// </IconButton>
|
||||
// }
|
||||
sx={{
|
||||
boxShadow: 'rgba(149, 157, 165, 0.2) 0px 0px 5px;'
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={<b>{x.supported_obj_path}</b>}
|
||||
sx={{fontWeight:'bold'}}
|
||||
/>
|
||||
</ListItem>
|
||||
{ x.supported_params &&
|
||||
x.supported_params.map((y)=>{
|
||||
return <List component="div" disablePadding dense={true}>
|
||||
<ListItem
|
||||
key={i}
|
||||
divider={true}
|
||||
sx={{
|
||||
boxShadow: 'rgba(149, 157, 165, 0.2) 0px 0px 5px;',
|
||||
pl: 4
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={y.param_name}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
})
|
||||
}
|
||||
</List>)
|
||||
})
|
||||
}
|
||||
|
||||
return ( deviceParameters ?
|
||||
<Card>
|
||||
<CardContent>
|
||||
{showParameters()}
|
||||
</CardContent>
|
||||
</Card>
|
||||
:
|
||||
<Box sx={{display:'flex',justifyContent:'center'}}>
|
||||
<CircularProgress color="inherit" />
|
||||
</Box>
|
||||
)
|
||||
};
|
||||
|
|
@ -84,7 +84,7 @@ const handleOpen = () => {
|
|||
}
|
||||
|
||||
|
||||
fetch(`${process.env.NEXT_PUBLIC_REST_ENPOINT}/device/${router.query.id}/${method}`, requestOptions)
|
||||
fetch(`${process.env.NEXT_PUBLIC_REST_ENPOINT}/device/${router.query.id[0]}/${method}`, requestOptions)
|
||||
.then(response => response.text())
|
||||
.then(result => {
|
||||
setOpen(false)
|
||||
|
|
@ -257,7 +257,7 @@ const handleOpen = () => {
|
|||
//ref={descriptionElementRef}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<pre>
|
||||
<pre style={{color: 'black'}}>
|
||||
{content}
|
||||
</pre>
|
||||
</DialogContentText>
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ export const OverviewLatestOrders = (props) => {
|
|||
sx={{cursor:'pointer'}}
|
||||
onClick={()=>{
|
||||
if (order.Status !== 2){
|
||||
router.push("devices/"+order.SN)
|
||||
router.push("devices/"+order.SN+"/discovery")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user