From 20351efe574cf8914367a2c0b4266abdc2c7b01b Mon Sep 17 00:00:00 2001 From: ivanjoz Date: Sat, 25 May 2024 15:33:07 -0500 Subject: [PATCH] websocket comunication and rtc offer sending --- backend/aws/dynamodb.go | 446 ++++++++++++++++++++++++++++ backend/core/helpers.go | 109 +------ backend/core/responses.go | 6 + backend/core/security.go | 4 + backend/core/types.go | 6 + backend/go.mod | 21 +- backend/go.sum | 43 +-- backend/handlers/main.go | 4 +- backend/handlers/webrtc.go | 8 + backend/main-handlers.go | 25 +- backend/main.go | 111 +++++-- cloud/main.go | 1 + frontend/package-lock.json | 8 +- frontend/package.json | 2 +- frontend/src/services/connection.ts | 89 +++++- 15 files changed, 694 insertions(+), 189 deletions(-) create mode 100644 backend/aws/dynamodb.go create mode 100644 backend/handlers/webrtc.go diff --git a/backend/aws/dynamodb.go b/backend/aws/dynamodb.go new file mode 100644 index 0000000..9b7bac4 --- /dev/null +++ b/backend/aws/dynamodb.go @@ -0,0 +1,446 @@ +package aws + +import ( + "app/core" + "context" + "encoding/json" + "errors" + "fmt" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue" + "github.com/aws/aws-sdk-go-v2/service/dynamodb" + "github.com/aws/aws-sdk-go-v2/service/dynamodb/types" +) + +type DynamoTableRecords[T any] struct { + PK string + TableName string + UseCompression bool + Account uint8 + GetIndexKeys func(record T, idx uint8) string +} + +type DynamoQueryParam struct { + Index string + GreaterThan string + LesserThan string + BeginsWith string + Projection string + Equals string + BetweenStart string + BetweenEnd string + ScanIndexForward bool + Limit int32 +} + +func (params DynamoTableRecords[T]) MakeItem(record *T, accion uint8) (*map[string]types.AttributeValue, error) { + + item := map[string]types.AttributeValue{ + "pk": &types.AttributeValueMemberS{Value: params.PK}, + } + + sk := params.GetIndexKeys(*record, 0) + if len(sk) == 0 { + return nil, errors.New("no se ha especificado un [sk] que debe ser el index = 0 obligatorio") + } + item["sk"] = &types.AttributeValueMemberS{Value: sk} + + // Itera sobre los indices y si los encuentra los agrega + for i := 1; i <= 4; i++ { + indexValue := params.GetIndexKeys(*record, uint8(i)) + + if len(indexValue) > 0 { + item["ix"+strconv.Itoa(i)] = &types.AttributeValueMemberS{Value: indexValue} + } + } + + recordBytes, err := json.Marshal(record) + if err != nil { + return nil, errors.New("error al serializar el registro Dynamodb") + } + recordJson := string(recordBytes) + + if params.UseCompression && accion == 1 { + compressed := core.CompressZstd(&recordJson) + // Lo almacena como un array de bytes (binarios) + item["data"] = &types.AttributeValueMemberB{Value: compressed} + } else { + item["json"] = &types.AttributeValueMemberS{Value: recordJson} + } + + return &item, nil +} + +// PUT ITEM +func (params DynamoTableRecords[T]) PutItem(record *T, accion uint8) error { + + Item, err := params.MakeItem(record, accion) + if err != nil { + return err + } + + client := dynamodb.NewFromConfig(core.GetAwsConfig()) + putRequest := dynamodb.PutItemInput{ + TableName: core.PtrString(params.TableName), + Item: *Item, + ReturnConsumedCapacity: "TOTAL", + } + + output, err := client.PutItem(context.TODO(), &putRequest) + if err != nil { + core.Log("error al enviar item", err) + return err + } + core.Log("Put Item. Capacidad Consumida:: ", *output.ConsumedCapacity.CapacityUnits) + return nil +} + +// BASH PUT o BASH DELETE +func (params DynamoTableRecords[T]) DynamoAccionToItems(recordsToSend []T, accion uint8) error { + core.Log("Enviando registros a Tabla DynamoDB:: ", params.TableName) + dynamoItems := []*map[string]types.AttributeValue{} + + for i := range recordsToSend { + item, err := params.MakeItem(&recordsToSend[i], accion) + if err != nil { + return err + } + dynamoItems = append(dynamoItems, item) + } + + // Crea grupos de envío de 25 items + group1 := []*map[string]types.AttributeValue{} + recordsGroups := [][]*map[string]types.AttributeValue{group1} + + for _, record := range dynamoItems { + group := &recordsGroups[len(recordsGroups)-1] + if len(*group) >= 25 { + recordsGroups = append(recordsGroups, []*map[string]types.AttributeValue{}) + group = &recordsGroups[len(recordsGroups)-1] + } + *group = append(*group, record) + } + + client := dynamodb.NewFromConfig(core.GetAwsConfig()) + + for _, records := range recordsGroups { + + writeRequests := []types.WriteRequest{} + + for _, record := range records { + if accion == 1 { // Put items + writeRequests = append(writeRequests, types.WriteRequest{ + PutRequest: &types.PutRequest{Item: *record}, + }) + } else if accion == 3 { // Delete items + sk := (*record)["sk"] + if sk == nil { + core.Log("No se encontró el sk para el delete item") + continue + } + writeRequests = append(writeRequests, types.WriteRequest{ + DeleteRequest: &types.DeleteRequest{ + Key: map[string]types.AttributeValue{ + "pk": (*record)["pk"], "sk": sk, + }, + }, + }) + } + } + + // Itera sobre los grupos y realiza el envio + requestItems := map[string][]types.WriteRequest{} + requestItems[params.TableName] = writeRequests + + output, err := client.BatchWriteItem(context.TODO(), &dynamodb.BatchWriteItemInput{ + RequestItems: requestItems, + }) + + if err != nil { + return errors.New("Error en el guardado en Dynamodb: " + err.Error()) + } + + core.Print(output.ConsumedCapacity) + } + + return nil +} + +func (params DynamoTableRecords[T]) DynamoPutItems(recordsToSend []T) error { + err := params.DynamoAccionToItems(recordsToSend, 1) + return err +} + +func (params DynamoTableRecords[T]) DynamoDeleteItems(recordsToSend []T) error { + err := params.DynamoAccionToItems(recordsToSend, 3) + return err +} + +func parseDynamoDBItem[T any](dynamoItem DynamoDBItem) (*T, error) { + jsonContent := "" + + if len(dynamoItem.Json) > 0 { + jsonContent = dynamoItem.Json + } else if len(dynamoItem.Data) > 0 { + jsonContent = core.DecompressZstd(&dynamoItem.Data) + } else { + jsonContentBytes, _ := json.Marshal(dynamoItem) + jsonContent = string(jsonContentBytes) + } + + record := new(T) + err := json.Unmarshal([]byte(jsonContent), record) + if err != nil { + fmt.Println(dynamoItem.Json) + core.Log("Error al deserializar Dynamodb: " + err.Error()) + return nil, err + } + + return record, nil +} + +// GET ITEM +func (params *DynamoTableRecords[T]) GetItem(sk string) (*T, error) { + + core.Log("Enviando registros a Tabla DynamoDB:: ", params.TableName) + client := dynamodb.NewFromConfig(core.GetAwsConfig()) + + getRequest := dynamodb.GetItemInput{ + TableName: core.PtrString(params.TableName), + Key: map[string]types.AttributeValue{ + "pk": &types.AttributeValueMemberS{Value: params.PK}, + "sk": &types.AttributeValueMemberS{Value: sk}, + }, + } + + output, err := client.GetItem(context.TODO(), &getRequest) + if err != nil { + core.Log("Error al obtener item", err) + return nil, err + } + + if output.Item == nil || len(output.Item) == 0 { + return nil, nil + } + + dynamoItem := DynamoDBItem{} + err = attributevalue.UnmarshalMap(output.Item, &dynamoItem) + if err != nil { + core.Log("Error al interpretar item Dynamodb: " + err.Error()) + return nil, err + } + + record, err := parseDynamoDBItem[T](dynamoItem) + return record, err +} + +func GetDynamoDBTables() error { + + client := dynamodb.NewFromConfig(core.GetAwsConfig()) + + output, err := client.ListTables(context.TODO(), &dynamodb.ListTablesInput{}) + if err != nil { + return errors.New("error al listar DynamoDB: " + err.Error()) + } + + core.Print(output.TableNames) + + return nil +} + +type DynamoDBItem struct { + PK string `json:"pk" dynamodbav:"pk"` + SK string `json:"sk" dynamodbav:"sk"` + Ix1 string `json:"ix1" dynamodbav:"ix1"` + Ix2 string `json:"ix2" dynamodbav:"ix2"` + Json string `json:"json" dynamodbav:"json"` + Data []byte `json:"data" dynamodbav:"data"` +} + +type dynamoQueryInput struct { + input dynamodb.QueryInput + expression string +} + +func (e DynamoTableRecords[T]) QueryBatch(querys []DynamoQueryParam) ([]T, error) { + + queryInputs := []dynamoQueryInput{} + TableName := core.PtrString(core.Env.DYNAMO_TABLE) + + for _, query := range querys { + // Crea la query según el tipo de lógica + queryInput := &dynamodb.QueryInput{ + TableName: TableName, + ScanIndexForward: &query.ScanIndexForward, + ReturnConsumedCapacity: "TOTAL", + } + + if query.Limit > 0 { + queryInput.Limit = &query.Limit + } + + if query.Index != "sk" { + queryInput.IndexName = core.PtrString(query.Index) + } + + expression := "pk = :pk and " + attributes := map[string]string{":pk": e.PK} + + if len(query.BetweenStart) > 0 { + expression += "$index BETWEEN :value1 AND :value2" + attributes[":value1"] = query.BetweenStart + attributes[":value2"] = query.BetweenEnd + } else if len(query.BeginsWith) > 0 { + expression += "begins_with($index, :value)" + attributes[":value"] = query.BeginsWith + } else if len(query.GreaterThan) > 0 { + expression += "$index >= :value" + attributes[":value"] = query.GreaterThan + } else if len(query.LesserThan) > 0 { + expression += "$index <= :value" + attributes[":value"] = query.LesserThan + } else if len(query.Equals) > 0 { + expression += "$index = :value" + attributes[":value"] = query.Equals + } + + expression = strings.Replace(expression, "$index", query.Index, 1) + queryInput.KeyConditionExpression = &expression + + expressionAttributes, _ := attributevalue.MarshalMap(attributes) + expressionParsed := expression + for attKey, attValue := range attributes { + expressionParsed = strings.Replace(expressionParsed, attKey, attValue, 1) + } + + queryInput.ExpressionAttributeValues = expressionAttributes + if len(query.Projection) > 0 { + queryInput.ProjectionExpression = &query.Projection + } + + dynamoInput := dynamoQueryInput{input: *queryInput, expression: expressionParsed} + queryInputs = append(queryInputs, dynamoInput) + } + + core.Log("estamo aqui...") + + client := dynamodb.NewFromConfig(core.GetAwsConfig()) + records := []T{} + + // Itera por cada query input + for _, dynamoQuery := range queryInputs { + + queryInput := dynamoQuery.input + queryCount := 0 + lastEvaluatedKey := map[string]types.AttributeValue{} + + for { + queryCount++ + if queryCount > 100 { + break + } + + if len(lastEvaluatedKey) > 0 { + queryInput.ExclusiveStartKey = lastEvaluatedKey + } + + output, err := client.Query(context.TODO(), &queryInput) + if err != nil { + core.Log("Error al ejecutar la DynamoDB") + panic(err) + } + + items := []DynamoDBItem{} + err = attributevalue.UnmarshalListOfMaps(output.Items, &items) + if err != nil { + core.Log("Error al deserializar Dynamodb: " + err.Error()) + return nil, err + } + + for _, dynamoItem := range items { + record, _ := parseDynamoDBItem[T](dynamoItem) + if record != nil { + records = append(records, *record) + } + } + + capacity := float64(0) + if output.ConsumedCapacity.CapacityUnits != nil { + capacity = *output.ConsumedCapacity.CapacityUnits + } + + core.Log("Recibidos ", len(items), " registros:: ", dynamoQuery.expression) + core.Log("Consumed Capacity::", capacity, " | Last key: ", output.LastEvaluatedKey) + + if len(output.LastEvaluatedKey) > 0 { + lastEvaluatedKey = output.LastEvaluatedKey + } else { + break + } + } + } + + return records, nil +} + +type CounterRecord struct { + SK string `json:"sk"` + Counter int64 `json:"counter"` + Updated int64 `json:"updated"` +} + +func MakeCounterTable() DynamoTableRecords[CounterRecord] { + return DynamoTableRecords[CounterRecord]{ + TableName: core.Env.DYNAMO_TABLE, + PK: "counter", + UseCompression: false, + GetIndexKeys: func(e CounterRecord, idx uint8) string { + switch idx { + case 0: + return core.Concatn(e.SK) + } + return "" + }, + } +} + +func GetDynamoCounter(sk string, minValue_ ...int64) (int64, error) { + minValue := int64(0) + if len(minValue_) == 1 { + minValue = minValue_[0] + } + + dynamoTable := MakeCounterTable() + record, err := dynamoTable.GetItem(sk) + + if err != nil { + return 0, errors.New("Error al obtener el counter: " + err.Error()) + } + + counter := int64(0) + if record == nil { + counter = 1 + } else { + counter = record.Counter + 1 + } + + if counter < minValue { + counter = minValue + } + + newRecord := CounterRecord{ + Counter: counter, + SK: sk, + Updated: time.Now().Unix(), + } + + err = dynamoTable.PutItem(&newRecord, 1) + if err != nil { + return 0, errors.New("Error al actualizar el counter: " + err.Error()) + } + + return counter, nil +} diff --git a/backend/core/helpers.go b/backend/core/helpers.go index a68b7f9..0fc6176 100644 --- a/backend/core/helpers.go +++ b/backend/core/helpers.go @@ -10,7 +10,6 @@ import ( "encoding/base32" "encoding/base64" "encoding/binary" - "encoding/gob" "encoding/json" "errors" "fmt" @@ -33,10 +32,7 @@ import ( "github.com/klauspost/compress/zstd" "github.com/kr/pretty" "github.com/martinlindhe/base36" - "github.com/mashingan/smapping" "github.com/mitchellh/hashstructure/v2" - "github.com/rodaine/table" - "github.com/vmihailenco/msgpack/v5" "golang.org/x/exp/constraints" ) @@ -424,31 +420,6 @@ func PtrString(v string) *string { return &v } -func MsgPEncode(msg any) ([]byte, error) { - var buffer bytes.Buffer - msgEncoder := msgpack.NewEncoder(&buffer) - msgEncoder.SetCustomStructTag("ms") - msgEncoder.SetOmitEmpty(true) - msgEncoder.UseCompactInts(true) - msgEncoder.UseCompactFloats(true) - err := msgEncoder.Encode(msg) - - return buffer.Bytes(), err -} - -func MsgPDecode(msgBytes []byte, msg any) error { - buffer := bytes.NewBuffer(msgBytes) - msgDecoder := msgpack.NewDecoder(buffer) - msgDecoder.SetCustomStructTag("ms") - - err := msgDecoder.Decode(msg) - if err != nil { - Log("Error decoding MsgPack: ", err) - return err - } - return nil -} - func Err(content ...any) error { errMessage := Concatx(" ", content) Log(errMessage) @@ -713,7 +684,7 @@ func DecompressBrotli(content *[]byte) string { return string(contentUncompressed) } -func DecompressGzip(content *[]byte) string { +func DecompressGzipBytes(content *[]byte) []byte { // Create a reader from the compressed data reader := bytes.NewReader(*content) @@ -721,7 +692,7 @@ func DecompressGzip(content *[]byte) string { gzipReader, err := gzip.NewReader(reader) if err != nil { fmt.Println("Error al crear reader: " + err.Error()) - return "" + return []byte{} } defer gzipReader.Close() @@ -729,10 +700,14 @@ func DecompressGzip(content *[]byte) string { decompressedData, err := io.ReadAll(gzipReader) if err != nil { fmt.Println("Error al descomprimir: " + err.Error()) - return "" + return []byte{} } - return string(decompressedData) + return decompressedData +} + +func DecompressGzip(content *[]byte) string { + return string(DecompressGzipBytes(content)) } func DecompressBrotli64(content *string) string { @@ -1187,62 +1162,6 @@ func IF(ok bool, exec func()) { } } -func PrintTable[T any](records []T, maxLenSlice, maxLenContent int, columns ...string) { - if maxLenSlice > 0 && len(records) > maxLenSlice { - records = records[0:maxLenSlice] - } - - // Log("registros mapeados:: ", len(records)) - // Print(records) - recordsMapped := []map[string]any{} - avoidKeys := map[string]bool{} - includedColumns := map[string]bool{} - for _, e := range columns { - includedColumns[e] = true - } - - for _, e := range records { - rec := smapping.MapFields(e) - for key, value := range rec { - if _, ok := avoidKeys[key]; ok { - delete(rec, key) - continue - } - if len(columns) > 0 { - if _, ok := includedColumns[key]; !ok { - delete(rec, key) - continue - } - } - valueString := fmt.Sprintf("%v", value) - if maxLenContent > 0 && len(valueString) > maxLenContent { - valueString = valueString[0:maxLenContent] - rec[key] = valueString - } - includedColumns[key] = true - } - recordsMapped = append(recordsMapped, rec) - } - - columnsAll := []any{} - columnsAllString := []string{} - for e := range includedColumns { - columnsAll = append(columnsAll, e) - columnsAllString = append(columnsAllString, e) - } - - newTable := table.New(columnsAll...) - for _, e := range recordsMapped { - row := []any{} - for _, col := range columnsAllString { - row = append(row, e[col]) - } - // Log("agregando: ", row) - newTable.AddRow(row...) - } - newTable.Print() -} - func GetHoursMinutes() string { currentTime := time.Now() for i := -1; i < 2; i++ { @@ -1368,18 +1287,6 @@ func MakeRandomBase36String(length int) string { return string(bytes) } -func GobEncode(records any) ([]byte, error) { - var buffer bytes.Buffer - encoder := gob.NewEncoder(&buffer) - - err := encoder.Encode(records) - if err != nil { - return []byte{}, err - } - - return buffer.Bytes(), nil -} - func Concat62(values ...any) string { valuesStrings := []string{} for _, va := range values { diff --git a/backend/core/responses.go b/backend/core/responses.go index ba3d4b3..e4e8a74 100644 --- a/backend/core/responses.go +++ b/backend/core/responses.go @@ -30,12 +30,15 @@ type HandlerArgs struct { QueryString string Method string Route string + ClientID string Authorization string MergedID int32 ResponseBody *string ResponseError string ReqParams string Usuario IUsuario + EventType string + IsWebSocket bool } func PrintMemUsage() { @@ -804,6 +807,9 @@ func (req *HandlerArgs) MakeResponsePlain(body *string) HandlerResponse { } func SendLocalResponse(args HandlerArgs, response HandlerResponse) { + if args.IsWebSocket { + return + } respWriter := *args.ResponseWriter respWriter.Header().Set("Access-Control-Allow-Origin", "*") diff --git a/backend/core/security.go b/backend/core/security.go index 84fcd31..8d347fa 100644 --- a/backend/core/security.go +++ b/backend/core/security.go @@ -167,6 +167,10 @@ type IUsuario struct { var Usuario IUsuario func CheckUser(req *HandlerArgs, access int) IUsuario { + if req.IsWebSocket { + return Usuario + } + userToken := req.Headers["authorization"] if len(userToken) < 8 { userToken = req.Headers["Authorization"] diff --git a/backend/core/types.go b/backend/core/types.go index 410cd46..ce406e1 100644 --- a/backend/core/types.go +++ b/backend/core/types.go @@ -107,6 +107,12 @@ type FuncResponse struct { ContentJson string `json:",omitempty"` } +type WsMessage struct { + Accion string `json:"a"` + Body string `json:"b"` + ClientID string `json:"c"` +} + type AppRouterType map[string]func(args *HandlerArgs) HandlerResponse type Int int diff --git a/backend/go.mod b/backend/go.mod index 3fa790d..9906b3c 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,16 +5,14 @@ go 1.22.0 require ( github.com/andybalholm/brotli v1.1.0 github.com/aws/aws-lambda-go v1.32.0 - github.com/aws/aws-sdk-go-v2 v1.25.2 + github.com/aws/aws-sdk-go-v2 v1.27.0 github.com/aws/aws-sdk-go-v2/config v1.27.4 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.6 github.com/aws/aws-sdk-go-v2/service/s3 v1.51.1 github.com/fatih/color v1.15.0 github.com/klauspost/compress v1.17.2 github.com/martinlindhe/base36 v1.1.1 - github.com/mashingan/smapping v0.1.19 github.com/mileusna/useragent v1.3.3 - github.com/rodaine/table v1.1.0 github.com/rs/cors v1.8.2 ) @@ -22,34 +20,39 @@ require ( github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.4 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.20.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.8 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.2 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.20.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.28.1 // indirect - github.com/aws/smithy-go v1.20.1 // indirect + github.com/aws/smithy-go v1.20.2 // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/stretchr/testify v1.8.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.13.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) require ( github.com/DmitriyVTitov/size v1.5.0 + github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.13.19 + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.32.5 github.com/kr/pretty v0.3.1 github.com/mitchellh/hashstructure/v2 v2.0.2 - github.com/vmihailenco/msgpack/v5 v5.4.1 golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sync v0.5.0 ) diff --git a/backend/go.sum b/backend/go.sum index 1e3c2c9..851aac9 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -4,30 +4,38 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/aws/aws-lambda-go v1.32.0 h1:i8MflawW1hoyYp85GMH7LhvAs4cqzL7LOS6fSv8l2KM= github.com/aws/aws-lambda-go v1.32.0/go.mod h1:IF5Q7wj4VyZyUFnZ54IQqeWtctHQ9tz+KhcbDenr220= -github.com/aws/aws-sdk-go-v2 v1.25.2 h1:/uiG1avJRgLGiQM9X3qJM8+Qa6KRGK5rRPuXE0HUM+w= -github.com/aws/aws-sdk-go-v2 v1.25.2/go.mod h1:Evoc5AsmtveRt1komDwIsjHFyrP5tDuF1D1U+6z6pNo= +github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= +github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo= github.com/aws/aws-sdk-go-v2/config v1.27.4 h1:AhfWb5ZwimdsYTgP7Od8E9L1u4sKmDW2ZVeLcf2O42M= github.com/aws/aws-sdk-go-v2/config v1.27.4/go.mod h1:zq2FFXK3A416kiukwpsd+rD4ny6JC7QSkp4QdN1Mp2g= github.com/aws/aws-sdk-go-v2/credentials v1.17.4 h1:h5Vztbd8qLppiPwX+y0Q6WiwMZgpd9keKe2EAENgAuI= github.com/aws/aws-sdk-go-v2/credentials v1.17.4/go.mod h1:+30tpwrkOgvkJL1rUZuRLoxcJwtI/OkeBLYnHxJtVe0= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.13.19 h1:Y9GflNZ9Ty+qjyY7Oral0gcaeI5NiPNHX23vXCiXfe8= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.13.19/go.mod h1:RACJwWn6am6SvBqlCM9/DKHaR+79Q6/yMx3QCjuq8nw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2 h1:AK0J8iYBFeUk2Ax7O8YpLtFsfhdOByh2QIkHmigpRYk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.2/go.mod h1:iRlGzMix0SExQEviAyptRWRGdYNo3+ufW/lCzvKVTUc= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.6 h1:prcsGA3onmpc7ea1W/m+SMj4uOn5vZ63uJp805UhJJs= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.6/go.mod h1:7eQrvATnVFDY0WfMYhfKkSQ1YtZlClT71fAAlsA1s34= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2 h1:bNo4LagzUKbjdxE0tIcR9pMzLR2U/Tgie1Hq1HQ3iH8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.2/go.mod h1:wRQv0nN6v9wDXuWThpovGQjqF1HFdcgWjporw14lS8k= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2 h1:EtOU5jsPdIQNP+6Q2C5e3d65NKT1PeCiQk+9OdzO12Q= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.2/go.mod h1:tyF5sKccmDz0Bv4NrstEr+/9YkSPJHrcO7UsUKf7pWM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.2 h1:en92G0Z7xlksoOylkUhuBSfJgijC7rHVLRdnIlHEs0E= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.2/go.mod h1:HgtQ/wN5G+8QSlK62lbOtNwQ3wTSByJ4wH2rCkPt+AE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.32.5 h1:HLbOhDOP/191cJLS829oCL8sn9tXF6qhAjh1emp8TEE= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.32.5/go.mod h1:uNhUf9Z3MT6Ex+u0ADa8r3MKK5zjuActEfXQPo4YqEI= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.20.8 h1:PapW7iWHqua6Gk+qRjgXpM3fNqUxY3N+1WURHPcmKhc= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.20.8/go.mod h1:IL6qnQxrc/qIjwzeg7USP3P7ySEehOPpXJslRbXNYJ4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.2 h1:zSdTXYLwuXDNPUS+V41i1SFDXG7V0ITp0D9UT9Cvl18= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.2/go.mod h1:v8m8k+qVy95nYi7d56uP1QImleIIY25BPiNJYzPBdFE= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.8 h1:yEeIld7Fh/2iM4pYeQw8a3kH6OYcyIn6lwKlUFiVk7Y= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.9.8/go.mod h1:lZJMX2Z5/rQ6OlSbBnW1WWScK6ngLt43xtqM8voMm2w= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2 h1:5ffmXjPtwRExp1zc7gENLgCPyHFbhEPwVTkTiH9niSk= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.2/go.mod h1:Ru7vg1iQ7cR4i7SZ/JTLYN9kaXtbL69UdgG0OQWQxW0= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.2 h1:1oY1AVEisRI4HNuFoLdRUB0hC63ylDAN6Me3MrfclEg= @@ -40,8 +48,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1 h1:9/GylMS45hGGFCcMrUZDVayQ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.1/go.mod h1:YjAPFn4kGFqKC54VsHs5fn5B6d+PCY2tziEa3U/GB5Y= github.com/aws/aws-sdk-go-v2/service/sts v1.28.1 h1:3I2cBEYgKhrWlwyZgfpSO2BpaMY1LHPqXYk/QGlu2ew= github.com/aws/aws-sdk-go-v2/service/sts v1.28.1/go.mod h1:uQ7YYKZt3adCRrdCBREm1CD3efFLOUNH77MrUCvx5oA= -github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= -github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -52,6 +60,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -64,15 +74,11 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/martinlindhe/base36 v1.1.1 h1:1F1MZ5MGghBXDZ2KJ3QfxmiydlWOGB8HCEtkap5NkVg= github.com/martinlindhe/base36 v1.1.1/go.mod h1:vMS8PaZ5e/jV9LwFKlm0YLnXl/hpOihiBxKkIoc3g08= -github.com/mashingan/smapping v0.1.19 h1:SsEtuPn2UcM1croIupPtGLgWgpYRuS0rSQMvKD9g2BQ= -github.com/mashingan/smapping v0.1.19/go.mod h1:FjfiwFxGOuNxL/OT1WcrNAwTPx0YJeg5JiXwBB1nyig= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mileusna/useragent v1.3.3 h1:hrIVmPevJY3ICS1Ob4yjqJToQiv2eD9iHaJBjxMihWY= github.com/mileusna/useragent v1.3.3/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= @@ -80,8 +86,6 @@ github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/z github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rodaine/table v1.1.0 h1:/fUlCSdjamMY8VifdQRIu3VWZXYLY7QHFkVorS8NTr4= -github.com/rodaine/table v1.1.0/go.mod h1:Qu3q5wi1jTQD6B6HsP6szie/S4w1QUQ8pq22pz9iL8g= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= @@ -89,18 +93,15 @@ github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= -github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/backend/handlers/main.go b/backend/handlers/main.go index 751d7cf..9ac49ef 100644 --- a/backend/handlers/main.go +++ b/backend/handlers/main.go @@ -2,4 +2,6 @@ package handlers import "app/core" -var ModuleHandlers = core.AppRouterType{} +var ModuleHandlers = core.AppRouterType{ + "PostRtcOffer": PostRtcOffer, +} diff --git a/backend/handlers/webrtc.go b/backend/handlers/webrtc.go new file mode 100644 index 0000000..34c50a6 --- /dev/null +++ b/backend/handlers/webrtc.go @@ -0,0 +1,8 @@ +package handlers + +import "app/core" + +func PostRtcOffer(args *core.HandlerArgs) core.HandlerResponse { + + return core.HandlerResponse{} +} diff --git a/backend/main-handlers.go b/backend/main-handlers.go index 220aa4e..d29738f 100644 --- a/backend/main-handlers.go +++ b/backend/main-handlers.go @@ -10,7 +10,6 @@ import ( "strings" "time" - "github.com/aws/aws-lambda-go/events" "golang.org/x/sync/errgroup" ) @@ -37,10 +36,8 @@ func makeAppHandlers() *core.AppRouterType { func mainHandler(args core.HandlerArgs) core.MainResponse { // coloca algunas variables de entorno que pueden ser utilizadas por otros handlers args.Authorization = core.MapGetKeys(args.Headers, "Authorization", "authorization") - req_encoding := core.MapGetKeys(args.Headers, "Accept-Encoding", "accept-encoding") core.StartTime = (time.Now()).UnixMilli() - - core.Env.REQ_ENCODING = req_encoding + core.Env.REQ_ENCODING = core.MapGetKeys(args.Headers, "Accept-Encoding", "accept-encoding") core.Env.REQ_PARAMS = core.MapGetKeys(args.Headers, "x-api-key", "X-Api-Key") core.Env.REQ_USER_AGENT = core.MapGetKeys(args.Headers, "User-Agent", "user-agent") core.Env.REQ_ID = core.IntToBase64(time.Now().UnixMilli(), 6) @@ -62,7 +59,11 @@ func mainHandler(args core.HandlerArgs) core.MainResponse { } path := strings.Join(pathSegments, "/") - funcPath := args.Method + "." + path + funcPath := path + if len(args.Method) > 0 { + funcPath = args.Method + "." + path + } + core.Env.HANDLER_PARH = funcPath mergedRoutes := []core.MergedRoute{} @@ -151,6 +152,8 @@ func mainHandler(args core.HandlerArgs) core.MainResponse { // revisa si hay una función que satisfaga la lambda requerida } else if len(handlerResponse.Error) == 0 { core.Env.REQ_PATH = funcPath + core.Log("Buscando path solicitado::", funcPath) + handlerFunc, ok := appHandlers[funcPath] if !ok { core.Log("no hay una lambda para el path solicitado::", funcPath) @@ -195,15 +198,3 @@ func prepareResponse(args core.HandlerArgs, handlerResponse *core.HandlerRespons } return response } - -// Handler principal (para lambda y para local) -func wssHandler(args core.HandlerArgs) core.MainResponse { - - fmt.Println("Respondiendo status 200 Connected") - return core.MainResponse{ - LambdaResponse: &events.APIGatewayV2HTTPResponse{ - StatusCode: 200, - Body: "Connected", - }, - } -} diff --git a/backend/main.go b/backend/main.go index 889e207..1980b01 100644 --- a/backend/main.go +++ b/backend/main.go @@ -12,8 +12,11 @@ import ( "runtime/debug" "strings" + "unicode/utf8" + "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" + "github.com/gorilla/websocket" "github.com/rs/cors" ) @@ -39,18 +42,22 @@ func LambdaHandler(_ context.Context, request *core.APIGatewayV2HTTPRequest) (*e } args := core.HandlerArgs{ - Body: &request.Body, - Query: request.QueryStringParameters, - Headers: request.Headers, - Route: route, - Method: request.RequestContext.HTTP.Method, + Body: &request.Body, + Query: request.QueryStringParameters, + Headers: request.Headers, + Route: route, + Method: request.RequestContext.HTTP.Method, + EventType: request.RequestContext.EventType, } wssEvents := []string{"CONNECT", "DISCONNECT", "MESSAGE"} - fmt.Println("Event type: ", request.RequestContext.EventType) + fmt.Println("Event type: ", args.EventType) response := core.MainResponse{} - if core.Contains(wssEvents, request.RequestContext.EventType) { - response = wssHandler(args) + if core.Contains(wssEvents, args.EventType) { + if args.EventType == "MESSAGE" { + args.Body = &request.Body + } + response = WssHandler(args) } else { response = mainHandler(args) } @@ -66,7 +73,6 @@ func LambdaHandler(_ context.Context, request *core.APIGatewayV2HTTPRequest) (*e } func LocalHandler(w http.ResponseWriter, request *http.Request) { - core.Log("hola aquí!!") clearEnvVariables() core.Env.REQ_IP = request.RemoteAddr @@ -80,13 +86,6 @@ func LocalHandler(w http.ResponseWriter, request *http.Request) { ResponseWriter: &w, } - blen := core.If(len(body) > 500, 500, len(body)) - if blen > 0 { - core.Log("*body enviado (LOCAL): ", body[0:(blen-1)]) - } else { - core.Log("no se encontró body") - } - // Convierte los query params en un map[string]: stirng queryString := request.URL.Query() args.Query = make(map[string]string) @@ -107,6 +106,68 @@ func LocalHandler(w http.ResponseWriter, request *http.Request) { mainHandler(args) } +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func LocalWssHandler(w http.ResponseWriter, r *http.Request) { + // Upgrade initial GET request to a websocket + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Fatal(err) + } + // Make sure we close the connection when the function returns + defer ws.Close() + core.Log("Client connected") + + for { + // Read in a new message as JSON and map it to a Message object + _, message, err := ws.ReadMessage() + if err != nil { + log.Printf("error: %v", err) + break + } + // Print the message to the console + core.Log("Is UTF-8:", utf8.Valid(message)) + if !utf8.Valid(message) { + message = core.DecompressGzipBytes(&message) + } + core.Log("Recibido: ", string(message)) + args := ParseWssMessage(message) + args.IsWebSocket = true + mainHandler(args) + } +} + +func ParseWssMessage(messageRaw []byte) core.HandlerArgs { + message := core.WsMessage{} + err := json.Unmarshal(messageRaw, &message) + if err != nil { + core.Log("Error al interpretar el mensaje:", err) + } + return core.HandlerArgs{ + Body: &message.Body, + Route: message.Accion, + ClientID: message.ClientID, + } +} + +// Handler principal (para lambda y para local) +func WssHandler(args core.HandlerArgs) core.MainResponse { + + fmt.Println("Respondiendo status 200 Connected") + return core.MainResponse{ + LambdaResponse: &events.APIGatewayV2HTTPResponse{ + StatusCode: 200, + Body: "Connected", + }, + } +} + func OnPanic(panicMessage interface{}) { core.Logx(5, "Error 500 (Panic): ", panicMessage) core.Log(string(debug.Stack())) @@ -130,19 +191,27 @@ func main() { } } - // Si se está desarrollando en local + // For local development if core.Env.IS_LOCAL { - core.Log("Ejecutando en local. http://localhost" + serverPort) - cors := cors.New(cors.Options{ AllowedOrigins: []string{"*"}, AllowedMethods: []string{http.MethodPost, http.MethodPut, http.MethodGet}, AllowedHeaders: []string{"*"}, AllowCredentials: false, }) - // Inicia el servidor con la configuración CORS - http.ListenAndServe(serverPort, cors.Handler(http.HandlerFunc(LocalHandler))) + mux := http.NewServeMux() + // HTTP server + core.Log("Ejecutando HTTP server: localhost" + serverPort) + mux.Handle("/", cors.Handler(http.HandlerFunc(LocalHandler))) + // WebSocket server + mux.HandleFunc("/ws", LocalWssHandler) + + // Start the server with the ServeMux + err := http.ListenAndServe(serverPort, mux) + if err != nil { + log.Fatal("Server start error: ", err) + } } else { // Si se está en Lamnda logger := log.New(os.Stdout, "", log.LstdFlags|log.Llongfile) diff --git a/cloud/main.go b/cloud/main.go index 9789ab5..42d40a1 100644 --- a/cloud/main.go +++ b/cloud/main.go @@ -202,6 +202,7 @@ func DeployIfraestructure(params DeployParams) { "$LAMBDA_NAME": params.STACK_NAME + "-backend", "$LAMBDA_IAM_ROLE": params.LAMBDA_IAM_ROLE, "$S3_COMPILED_PATH": S3_COMPILED_PATH, + "$DYNAMODB_TABLE": params.STACK_NAME + "-db", } for key, value := range variables { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6e98e46..cb4718a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,7 @@ "dependencies": { "@solidjs/meta": "^0.29.3", "@solidjs/router": "^0.13.3", - "@solidjs/start": "^1.0.0-rc.1", + "@solidjs/start": "^1.0.0", "dexie": "^4.0.5", "solid-js": "^1.8.17", "vinxi": "^0.3.11" @@ -1926,9 +1926,9 @@ } }, "node_modules/@solidjs/start": { - "version": "1.0.0-rc.1", - "resolved": "https://registry.npmjs.org/@solidjs/start/-/start-1.0.0-rc.1.tgz", - "integrity": "sha512-82VzbFDunj7rZsRQl/p5JXFQRtp4OdPtE5KLspck7amLYjVeRLdkveCNLOko5mcwLsft2hSHgN698KUbaW3rRA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@solidjs/start/-/start-1.0.0.tgz", + "integrity": "sha512-N+Zlb5hrYkOcYecBfKOtJ3jW1DRVNRJnHDsiljSbWefgdncJTvmcnVBr8rjqp898bDHyDo0c7iFdGrhKFEv06A==", "dependencies": { "@vinxi/plugin-directives": "^0.3.1", "@vinxi/server-components": "^0.3.3", diff --git a/frontend/package.json b/frontend/package.json index f955dc4..87f08a7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,7 +10,7 @@ "dependencies": { "@solidjs/meta": "^0.29.3", "@solidjs/router": "^0.13.3", - "@solidjs/start": "^1.0.0-rc.1", + "@solidjs/start": "^1.0.0", "dexie": "^4.0.5", "solid-js": "^1.8.17", "vinxi": "^0.3.11" diff --git a/frontend/src/services/connection.ts b/frontend/src/services/connection.ts index a39ccc2..2d7da47 100644 --- a/frontend/src/services/connection.ts +++ b/frontend/src/services/connection.ts @@ -126,27 +126,88 @@ export class WebRTCManager { export const webRTCManager = new WebRTCManager() -export const Connect = async ()=> { - const clientID = await getClientID() - console.log("offer string::", webRTCManager.getOffer()) +export class ConnectionManager { + + clientID: string + offerString: string + onOpenPromise: Promise + ws: WebSocket - console.log("client id obtenido::", clientID) - const ws = new WebSocket('wss://pv5s7gfoge.execute-api.us-east-1.amazonaws.com/p/') + constructor(){ + this.ws = new WebSocket('ws://127.0.0.1:3589/ws') + + this.onOpenPromise = Promise.all([ + new Promise((resolve) => { + this.ws.onopen = async () => { + console.log('WebSocket is connected') + resolve() + } + }), + new Promise((resolve) => { + getClientID().then(id => { + this.clientID = id + console.log('Client-ID obtenido::', this.clientID) + resolve() + }) + }), + ]).then(() => { + delete this.onOpenPromise + }) - ws.onopen = () => { - console.log('WebSocket is connected') - ws.send('Hello Server!') + this.ws.onmessage = (event) => { + console.log(`Received: ${event.data}`) + } + + this.ws.onerror = (error) => { + console.log(error) + console.log(`WebSocket error: ${error}`) + } + + this.ws.onclose = () => { + console.log('WebSocket connection closed') + } } - ws.onmessage = (event) => { - console.log(`Received: ${event.data}`) + async sendMessage(accion: string, messageBody: string){ + if(this.onOpenPromise){ await this.onOpenPromise } + console.log('Client-ID a enviar::', this.clientID) + const message = { a: accion, b: messageBody, c: this.clientID } + const array8int = await compressStringWithGzip(JSON.stringify(message)) + this.ws.send(array8int) } - ws.onerror = (error) => { - console.log(`WebSocket error: ${error}`) + async sendOffer(){ + const offerString = await webRTCManager.getOffer() + await this.sendMessage("PostRtcOffer",offerString) } +} + +export const Connect = async ()=> { + const connectionManager = new ConnectionManager() + await connectionManager.sendMessage("SendHello","Hello Server") + await connectionManager.sendOffer() +} - ws.onclose = () => { - console.log('WebSocket connection closed') +export const compressStringWithGzip = async (inputString: string): Promise => { + const encoder = new TextEncoder() + const data = encoder.encode(inputString) + + const compressionStream = new window.CompressionStream('gzip') + const writer = compressionStream.writable.getWriter() + + writer.write(data) + writer.close() + + const reader = compressionStream.readable.getReader() + const chunks = [] + + while (true) { + const { value, done } = await reader.read() + if (done) break + chunks.push(value) } + + const compressedData = new Blob(chunks, { type: 'application/gzip' }) + const compressedArray = await compressedData.arrayBuffer() + return new Uint8Array(compressedArray) } \ No newline at end of file