Loading go-apps/meep-app-enablement/api/capif-mgmt/swagger.yaml +23 −64 Changes for go-apps/meep-app-enablement/api/capif-mgmt/swagger.yaml: 23 added lines, 64 removed lines. Original line number Diff line number Diff line Loading @@ -1227,13 +1227,9 @@ components: - apiVersion interfaceDescriptions: description: This type represents information about a transport endpoint oneOf: - $ref: '#/components/schemas/EndPointInfo.Uris' - $ref: '#/components/schemas/EndPointInfo.Fqdn' - $ref: '#/components/schemas/EndPointInfo.Addresses' - $ref: '#/components/schemas/EndPointInfo.Alternative' x-etsi-notes: "NOTE:\tExactly one of \"uris\", \"fqdn\", \"addresses\" or\ \ \"alternative\" shall be present." type: array items: $ref: '#/components/schemas/InterfaceDescription' vendorSpecific-urn:etsi:mec:capifext:transport-info : $ref: '#/components/schemas/MecTransportInfoCapifExt' description: "Additional attribute of data type MecTransportInfoCapifExt for MEC-specific CAPIF extensions related to alternative transports." Loading Loading @@ -1331,69 +1327,32 @@ components: - RPC - RPC_STREAMING - WEBSOCKET EndPointInfo.Alternative: title: EndPointInfo.Alternative required: - alternative type: object properties: alternative: type: object description: "Entry point information of the service in a format defined\ \ by an implementation, or in an external specification. See note." description: This type represents information about a transport endpoint. EndPointInfo.Address: title: EndPointInfo.Address required: - host - port InterfaceDescription: type: object description: 3GPP-compliant InterfaceDescription (TS 29.222 Table 8.2.4.2.3-1) properties: host: ipv4Addr: type: string description: Host portion of the address example: "[\"192.0.2.0\"]" port: type: integer description: Port portion of the address description: A IP address and port pair EndPointInfo.Addresses: title: EndPointInfo.Addresses required: - addresses type: object properties: addresses: type: array description: Entry point information of the service as one or more pairs of IP address and port. See note. items: $ref: '#/components/schemas/EndPointInfo.Address' EndPointInfo.Fqdn: title: EndPointInfo.Fqdn required: - fqdn type: object properties: format: ipv4 description: IPv4 address ipv6Addr: type: string format: ipv6 description: IPv6 address fqdn: type: array description: Fully Qualified Domain Name of the service. See note. items: type: string description: 'This type represents information about a transport endpoint. ' EndPointInfo.Uris: title: EndPointInfo.Uris required: - uris type: object properties: uris: type: array description: "Entry point information of the service as string, formatted\ \ according to URI syntax" items: description: Fully Qualified Domain Name port: type: integer description: TCP port number apiPrefix: type: string description: This type represents information about a transport endpoint. description: Optional API prefix path (starts with '/') oneOf: - required: [ipv4Addr] - required: [ipv6Addr] - required: [fqdn] additionalProperties: false responses: "400": description: Bad Request. It is used to indicate that incorrect parameters were Loading go-apps/meep-app-enablement/server/capif-mgmt/model_aef_profile.go +1 −1 Changes for go-apps/meep-app-enablement/server/capif-mgmt/model_aef_profile.go: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ type AefProfile struct { Versions []Version `json:"versions"` // This type represents information about a transport endpoint InterfaceDescriptions *OneOfTransportInfoEndpoint `json:"interfaceDescriptions,omitempty"` InterfaceDescriptions []InterfaceDescription `json:"interfaceDescriptions,omitempty"` VendorSpecificUrnetsimeccapifexttransportInfo *MecTransportInfoCapifExt `json:"vendorSpecific-urn:etsi:mec:capifext:transport-info,omitempty"` } go-apps/meep-app-enablement/server/capif-mgmt/model_endpoint_info.go 0 → 100644 +26 −0 Changes for go-apps/meep-app-enablement/server/capif-mgmt/model_endpoint_info.go: 26 added lines, 0 removed lines. Original line number Diff line number Diff line /* * MEC Service Management API * * The ETSI MEC ISG MEC011 MEC Service Management API described using OpenAPI * * API version: 3.1.1 * Contact: cti_support@etsi.org * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ package server // Address represents a (host, port) pair type Address struct { Host string `json:"host"` Port int `json:"port"` } // EndPointInfo represents transport endpoint information. // Exactly one of uris, fqdn, addresses, or alternative must be present. type EndPointInfo struct { Uris []string `json:"uris,omitempty"` Fqdn []string `json:"fqdn,omitempty"` Addresses []Address `json:"addresses,omitempty"` Alternative interface{} `json:"alternative,omitempty"` // flexible placeholder } go-apps/meep-app-enablement/server/capif-mgmt/model_interface_description.go 0 → 100644 +18 −0 Changes for go-apps/meep-app-enablement/server/capif-mgmt/model_interface_description.go: 18 added lines, 0 removed lines. Original line number Diff line number Diff line /* * MEC Service Management API * * The ETSI MEC ISG MEC011 MEC Service Management API described using OpenAPI * * API version: 3.1.1 * Contact: cti_support@etsi.org * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ package server type InterfaceDescription struct { Ipv4Addr *string `json:"ipv4Addr,omitempty"` Ipv6Addr *string `json:"ipv6Addr,omitempty"` Fqdn *string `json:"fqdn,omitempty"` Port *int `json:"port,omitempty"` ApiPrefix *string `json:"apiPrefix,omitempty"` } go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go +202 −6 Changes for go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go: 202 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" "net" "net/http" "net/url" "strconv" Loading Loading @@ -323,6 +324,11 @@ func appServicesPOST(w http.ResponseWriter, r *http.Request) { errHandlerProblemDetails(w, errStr, http.StatusBadRequest) return } if err := validateInterfaceDescriptions(sInfoPost.AefProfiles[0].InterfaceDescriptions); err != nil { log.Error(err.Error()) errHandlerProblemDetails(w, err.Error(), http.StatusBadRequest) return } if len(sInfoPost.AefProfiles) == 0 || sInfoPost.AefProfiles[0].AefId == "" { errStr := "Mandatory AefProfiles (AefId) not present" log.Error(errStr) Loading Loading @@ -374,7 +380,7 @@ func appServicesPOST(w http.ResponseWriter, r *http.Request) { Type_: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, Protocol: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, Version: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, Endpoint: sInfoPost.AefProfiles[0].InterfaceDescriptions, Endpoint: ConvertInterfaceDescriptionsToEndpoint(sInfoPost.AefProfiles[0].InterfaceDescriptions), Security: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, } Loading Loading @@ -510,7 +516,7 @@ func appServicesByIdPUT(w http.ResponseWriter, r *http.Request) { Type_: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, Protocol: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, Version: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, Endpoint: sInfo.AefProfiles[0].InterfaceDescriptions, Endpoint: ConvertInterfaceDescriptionsToEndpoint(sInfo.AefProfiles[0].InterfaceDescriptions), Security: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, } Loading Loading @@ -669,13 +675,14 @@ func appServicesByIdPATCH(w http.ResponseWriter, r *http.Request) { Category: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.Category, }, } transportInfo_ := TransportInfo{ Id: sInfo.AefProfiles[0].AefId, Name: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Name, Type_: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, Protocol: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, Version: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, Endpoint: sInfo.AefProfiles[0].InterfaceDescriptions, Endpoint: ConvertInterfaceDescriptionsToEndpoint(sInfo.AefProfiles[0].InterfaceDescriptions), Security: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, } // Create Service Loading Loading @@ -1784,7 +1791,7 @@ func getServices(w http.ResponseWriter, r *http.Request, appId string) { aefProfile := AefProfile{ AefId: service.TransportInfo.Id, Versions: []Version{{APIVersion: service.Version}}, InterfaceDescriptions: service.TransportInfo.Endpoint, InterfaceDescriptions: ConvertEndpointToInterfaceDescriptions(service.TransportInfo.Endpoint), VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ Name: service.TransportInfo.Name, Type_: service.TransportInfo.Type_, Loading Loading @@ -1861,7 +1868,7 @@ func getService(w http.ResponseWriter, r *http.Request, appId string, serviceId aefProfile := AefProfile{ AefId: service.TransportInfo.Id, Versions: []Version{{APIVersion: service.Version}}, InterfaceDescriptions: service.TransportInfo.Endpoint, InterfaceDescriptions: ConvertEndpointToInterfaceDescriptions(service.TransportInfo.Endpoint), VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ Name: service.TransportInfo.Name, Type_: service.TransportInfo.Type_, Loading Loading @@ -2091,7 +2098,7 @@ func checkSerAvailNotification(sInfo *ServiceInfo, mep string, changeType CapifE aefProfile := &AefProfile{ AefId: sInfo.TransportInfo.Id, Versions: []Version{{APIVersion: sInfo.Version}}, InterfaceDescriptions: sInfo.TransportInfo.Endpoint, InterfaceDescriptions: ConvertEndpointToInterfaceDescriptions(sInfo.TransportInfo.Endpoint), VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ Name: sInfo.TransportInfo.Name, Type_: sInfo.TransportInfo.Type_, Loading Loading @@ -2312,3 +2319,192 @@ func errHandlerProblemDetails(w http.ResponseWriter, error string, code int) { w.WriteHeader(code) fmt.Fprint(w, jsonResponse) } func validateInterfaceDescriptions(descs []InterfaceDescription) error { for i, desc := range descs { hasAddr := desc.Ipv4Addr != nil || desc.Ipv6Addr != nil hasFqdn := desc.Fqdn != nil if (hasAddr && hasFqdn) || (!hasAddr && !hasFqdn) { return fmt.Errorf("InterfaceDescription[%d]: exactly one of ipv4Addr/ipv6Addr or fqdn must be set", i) } } return nil } func ConvertInterfaceDescriptionsToEndpoint(descs []InterfaceDescription) *OneOfTransportInfoEndpoint { if len(descs) == 0 { return nil } // 1. Try to construct URI(s) when all required fields are available var uris []string allHaveHost := true for _, desc := range descs { var host string switch { case desc.Ipv4Addr != nil: host = *desc.Ipv4Addr case desc.Ipv6Addr != nil: host = "[" + *desc.Ipv6Addr + "]" case desc.Fqdn != nil: host = *desc.Fqdn default: allHaveHost = false } if host == "" { allHaveHost = false continue } uri := "http://" + host if desc.Port != nil { uri += ":" + fmt.Sprintf("%d", *desc.Port) } if desc.ApiPrefix != nil { uri += *desc.ApiPrefix } uris = append(uris, uri) } if allHaveHost && len(uris) > 0 { return &OneOfTransportInfoEndpoint{ EndPointInfoUris: EndPointInfoUris{ Uris: uris, }, } } // 2. Try FQDN (without port) var fqdns []string for _, desc := range descs { if desc.Fqdn != nil && desc.Port == nil { fqdns = append(fqdns, *desc.Fqdn) } } if len(fqdns) > 0 { return &OneOfTransportInfoEndpoint{ EndPointInfoFqdn: EndPointInfoFqdn{ Fqdn: fqdns, }, } } // 3. Fallback to addresses (host + port) var addresses []EndPointInfoAddress for _, desc := range descs { if desc.Port == nil { continue } var host string switch { case desc.Ipv4Addr != nil: host = *desc.Ipv4Addr case desc.Ipv6Addr != nil: host = *desc.Ipv6Addr case desc.Fqdn != nil: host = *desc.Fqdn } if host != "" { addresses = append(addresses, EndPointInfoAddress{ Host: host, Port: int32(*desc.Port), }) } } if len(addresses) > 0 { return &OneOfTransportInfoEndpoint{ EndPointInfoAddresses: EndPointInfoAddresses{ Addresses: addresses, }, } } // 4. None matched: treat as bad input return nil } func ConvertEndpointToInterfaceDescriptions(endpoint *OneOfTransportInfoEndpoint) []InterfaceDescription { if endpoint == nil { return nil } var descs []InterfaceDescription // 1. uris → try to extract apiPrefix and host/port info if len(endpoint.Uris) > 0 { for _, uriStr := range endpoint.Uris { u, err := url.Parse(uriStr) if err != nil || u.Host == "" { continue } host, portStr, _ := net.SplitHostPort(u.Host) var port *int if portStr != "" { p, err := strconv.Atoi(portStr) if err == nil { port = &p } } else { host = u.Host } desc := InterfaceDescription{ ApiPrefix: &u.Path, Port: port, } if ip := net.ParseIP(host); ip != nil { if ip.To4() != nil { desc.Ipv4Addr = &host } else { desc.Ipv6Addr = &host } } else { desc.Fqdn = &host } descs = append(descs, desc) } return descs } // 2. fqdn (no port) if len(endpoint.Fqdn) > 0 { for _, fqdn := range endpoint.Fqdn { desc := InterfaceDescription{ Fqdn: &fqdn, } descs = append(descs, desc) } return descs } // 3. addresses if len(endpoint.Addresses) > 0 { for _, addr := range endpoint.Addresses { port := int(addr.Port) desc := InterfaceDescription{ Port: &port, } if ip := net.ParseIP(addr.Host); ip != nil { if ip.To4() != nil { desc.Ipv4Addr = &addr.Host } else { desc.Ipv6Addr = &addr.Host } } else { desc.Fqdn = &addr.Host } descs = append(descs, desc) } return descs } return nil } Loading
go-apps/meep-app-enablement/api/capif-mgmt/swagger.yaml +23 −64 Changes for go-apps/meep-app-enablement/api/capif-mgmt/swagger.yaml: 23 added lines, 64 removed lines. Original line number Diff line number Diff line Loading @@ -1227,13 +1227,9 @@ components: - apiVersion interfaceDescriptions: description: This type represents information about a transport endpoint oneOf: - $ref: '#/components/schemas/EndPointInfo.Uris' - $ref: '#/components/schemas/EndPointInfo.Fqdn' - $ref: '#/components/schemas/EndPointInfo.Addresses' - $ref: '#/components/schemas/EndPointInfo.Alternative' x-etsi-notes: "NOTE:\tExactly one of \"uris\", \"fqdn\", \"addresses\" or\ \ \"alternative\" shall be present." type: array items: $ref: '#/components/schemas/InterfaceDescription' vendorSpecific-urn:etsi:mec:capifext:transport-info : $ref: '#/components/schemas/MecTransportInfoCapifExt' description: "Additional attribute of data type MecTransportInfoCapifExt for MEC-specific CAPIF extensions related to alternative transports." Loading Loading @@ -1331,69 +1327,32 @@ components: - RPC - RPC_STREAMING - WEBSOCKET EndPointInfo.Alternative: title: EndPointInfo.Alternative required: - alternative type: object properties: alternative: type: object description: "Entry point information of the service in a format defined\ \ by an implementation, or in an external specification. See note." description: This type represents information about a transport endpoint. EndPointInfo.Address: title: EndPointInfo.Address required: - host - port InterfaceDescription: type: object description: 3GPP-compliant InterfaceDescription (TS 29.222 Table 8.2.4.2.3-1) properties: host: ipv4Addr: type: string description: Host portion of the address example: "[\"192.0.2.0\"]" port: type: integer description: Port portion of the address description: A IP address and port pair EndPointInfo.Addresses: title: EndPointInfo.Addresses required: - addresses type: object properties: addresses: type: array description: Entry point information of the service as one or more pairs of IP address and port. See note. items: $ref: '#/components/schemas/EndPointInfo.Address' EndPointInfo.Fqdn: title: EndPointInfo.Fqdn required: - fqdn type: object properties: format: ipv4 description: IPv4 address ipv6Addr: type: string format: ipv6 description: IPv6 address fqdn: type: array description: Fully Qualified Domain Name of the service. See note. items: type: string description: 'This type represents information about a transport endpoint. ' EndPointInfo.Uris: title: EndPointInfo.Uris required: - uris type: object properties: uris: type: array description: "Entry point information of the service as string, formatted\ \ according to URI syntax" items: description: Fully Qualified Domain Name port: type: integer description: TCP port number apiPrefix: type: string description: This type represents information about a transport endpoint. description: Optional API prefix path (starts with '/') oneOf: - required: [ipv4Addr] - required: [ipv6Addr] - required: [fqdn] additionalProperties: false responses: "400": description: Bad Request. It is used to indicate that incorrect parameters were Loading
go-apps/meep-app-enablement/server/capif-mgmt/model_aef_profile.go +1 −1 Changes for go-apps/meep-app-enablement/server/capif-mgmt/model_aef_profile.go: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ type AefProfile struct { Versions []Version `json:"versions"` // This type represents information about a transport endpoint InterfaceDescriptions *OneOfTransportInfoEndpoint `json:"interfaceDescriptions,omitempty"` InterfaceDescriptions []InterfaceDescription `json:"interfaceDescriptions,omitempty"` VendorSpecificUrnetsimeccapifexttransportInfo *MecTransportInfoCapifExt `json:"vendorSpecific-urn:etsi:mec:capifext:transport-info,omitempty"` }
go-apps/meep-app-enablement/server/capif-mgmt/model_endpoint_info.go 0 → 100644 +26 −0 Changes for go-apps/meep-app-enablement/server/capif-mgmt/model_endpoint_info.go: 26 added lines, 0 removed lines. Original line number Diff line number Diff line /* * MEC Service Management API * * The ETSI MEC ISG MEC011 MEC Service Management API described using OpenAPI * * API version: 3.1.1 * Contact: cti_support@etsi.org * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ package server // Address represents a (host, port) pair type Address struct { Host string `json:"host"` Port int `json:"port"` } // EndPointInfo represents transport endpoint information. // Exactly one of uris, fqdn, addresses, or alternative must be present. type EndPointInfo struct { Uris []string `json:"uris,omitempty"` Fqdn []string `json:"fqdn,omitempty"` Addresses []Address `json:"addresses,omitempty"` Alternative interface{} `json:"alternative,omitempty"` // flexible placeholder }
go-apps/meep-app-enablement/server/capif-mgmt/model_interface_description.go 0 → 100644 +18 −0 Changes for go-apps/meep-app-enablement/server/capif-mgmt/model_interface_description.go: 18 added lines, 0 removed lines. Original line number Diff line number Diff line /* * MEC Service Management API * * The ETSI MEC ISG MEC011 MEC Service Management API described using OpenAPI * * API version: 3.1.1 * Contact: cti_support@etsi.org * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) */ package server type InterfaceDescription struct { Ipv4Addr *string `json:"ipv4Addr,omitempty"` Ipv6Addr *string `json:"ipv6Addr,omitempty"` Fqdn *string `json:"fqdn,omitempty"` Port *int `json:"port,omitempty"` ApiPrefix *string `json:"apiPrefix,omitempty"` }
go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go +202 −6 Changes for go-apps/meep-app-enablement/server/capif-mgmt/service-mgmt.go: 202 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" "net" "net/http" "net/url" "strconv" Loading Loading @@ -323,6 +324,11 @@ func appServicesPOST(w http.ResponseWriter, r *http.Request) { errHandlerProblemDetails(w, errStr, http.StatusBadRequest) return } if err := validateInterfaceDescriptions(sInfoPost.AefProfiles[0].InterfaceDescriptions); err != nil { log.Error(err.Error()) errHandlerProblemDetails(w, err.Error(), http.StatusBadRequest) return } if len(sInfoPost.AefProfiles) == 0 || sInfoPost.AefProfiles[0].AefId == "" { errStr := "Mandatory AefProfiles (AefId) not present" log.Error(errStr) Loading Loading @@ -374,7 +380,7 @@ func appServicesPOST(w http.ResponseWriter, r *http.Request) { Type_: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, Protocol: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, Version: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, Endpoint: sInfoPost.AefProfiles[0].InterfaceDescriptions, Endpoint: ConvertInterfaceDescriptionsToEndpoint(sInfoPost.AefProfiles[0].InterfaceDescriptions), Security: sInfoPost.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, } Loading Loading @@ -510,7 +516,7 @@ func appServicesByIdPUT(w http.ResponseWriter, r *http.Request) { Type_: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, Protocol: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, Version: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, Endpoint: sInfo.AefProfiles[0].InterfaceDescriptions, Endpoint: ConvertInterfaceDescriptionsToEndpoint(sInfo.AefProfiles[0].InterfaceDescriptions), Security: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, } Loading Loading @@ -669,13 +675,14 @@ func appServicesByIdPATCH(w http.ResponseWriter, r *http.Request) { Category: sInfo.VendorSpecificUrnetsimeccapifextserviceInfo.Category, }, } transportInfo_ := TransportInfo{ Id: sInfo.AefProfiles[0].AefId, Name: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Name, Type_: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Type_, Protocol: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Protocol, Version: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Version, Endpoint: sInfo.AefProfiles[0].InterfaceDescriptions, Endpoint: ConvertInterfaceDescriptionsToEndpoint(sInfo.AefProfiles[0].InterfaceDescriptions), Security: sInfo.AefProfiles[0].VendorSpecificUrnetsimeccapifexttransportInfo.Security, } // Create Service Loading Loading @@ -1784,7 +1791,7 @@ func getServices(w http.ResponseWriter, r *http.Request, appId string) { aefProfile := AefProfile{ AefId: service.TransportInfo.Id, Versions: []Version{{APIVersion: service.Version}}, InterfaceDescriptions: service.TransportInfo.Endpoint, InterfaceDescriptions: ConvertEndpointToInterfaceDescriptions(service.TransportInfo.Endpoint), VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ Name: service.TransportInfo.Name, Type_: service.TransportInfo.Type_, Loading Loading @@ -1861,7 +1868,7 @@ func getService(w http.ResponseWriter, r *http.Request, appId string, serviceId aefProfile := AefProfile{ AefId: service.TransportInfo.Id, Versions: []Version{{APIVersion: service.Version}}, InterfaceDescriptions: service.TransportInfo.Endpoint, InterfaceDescriptions: ConvertEndpointToInterfaceDescriptions(service.TransportInfo.Endpoint), VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ Name: service.TransportInfo.Name, Type_: service.TransportInfo.Type_, Loading Loading @@ -2091,7 +2098,7 @@ func checkSerAvailNotification(sInfo *ServiceInfo, mep string, changeType CapifE aefProfile := &AefProfile{ AefId: sInfo.TransportInfo.Id, Versions: []Version{{APIVersion: sInfo.Version}}, InterfaceDescriptions: sInfo.TransportInfo.Endpoint, InterfaceDescriptions: ConvertEndpointToInterfaceDescriptions(sInfo.TransportInfo.Endpoint), VendorSpecificUrnetsimeccapifexttransportInfo: &MecTransportInfoCapifExt{ Name: sInfo.TransportInfo.Name, Type_: sInfo.TransportInfo.Type_, Loading Loading @@ -2312,3 +2319,192 @@ func errHandlerProblemDetails(w http.ResponseWriter, error string, code int) { w.WriteHeader(code) fmt.Fprint(w, jsonResponse) } func validateInterfaceDescriptions(descs []InterfaceDescription) error { for i, desc := range descs { hasAddr := desc.Ipv4Addr != nil || desc.Ipv6Addr != nil hasFqdn := desc.Fqdn != nil if (hasAddr && hasFqdn) || (!hasAddr && !hasFqdn) { return fmt.Errorf("InterfaceDescription[%d]: exactly one of ipv4Addr/ipv6Addr or fqdn must be set", i) } } return nil } func ConvertInterfaceDescriptionsToEndpoint(descs []InterfaceDescription) *OneOfTransportInfoEndpoint { if len(descs) == 0 { return nil } // 1. Try to construct URI(s) when all required fields are available var uris []string allHaveHost := true for _, desc := range descs { var host string switch { case desc.Ipv4Addr != nil: host = *desc.Ipv4Addr case desc.Ipv6Addr != nil: host = "[" + *desc.Ipv6Addr + "]" case desc.Fqdn != nil: host = *desc.Fqdn default: allHaveHost = false } if host == "" { allHaveHost = false continue } uri := "http://" + host if desc.Port != nil { uri += ":" + fmt.Sprintf("%d", *desc.Port) } if desc.ApiPrefix != nil { uri += *desc.ApiPrefix } uris = append(uris, uri) } if allHaveHost && len(uris) > 0 { return &OneOfTransportInfoEndpoint{ EndPointInfoUris: EndPointInfoUris{ Uris: uris, }, } } // 2. Try FQDN (without port) var fqdns []string for _, desc := range descs { if desc.Fqdn != nil && desc.Port == nil { fqdns = append(fqdns, *desc.Fqdn) } } if len(fqdns) > 0 { return &OneOfTransportInfoEndpoint{ EndPointInfoFqdn: EndPointInfoFqdn{ Fqdn: fqdns, }, } } // 3. Fallback to addresses (host + port) var addresses []EndPointInfoAddress for _, desc := range descs { if desc.Port == nil { continue } var host string switch { case desc.Ipv4Addr != nil: host = *desc.Ipv4Addr case desc.Ipv6Addr != nil: host = *desc.Ipv6Addr case desc.Fqdn != nil: host = *desc.Fqdn } if host != "" { addresses = append(addresses, EndPointInfoAddress{ Host: host, Port: int32(*desc.Port), }) } } if len(addresses) > 0 { return &OneOfTransportInfoEndpoint{ EndPointInfoAddresses: EndPointInfoAddresses{ Addresses: addresses, }, } } // 4. None matched: treat as bad input return nil } func ConvertEndpointToInterfaceDescriptions(endpoint *OneOfTransportInfoEndpoint) []InterfaceDescription { if endpoint == nil { return nil } var descs []InterfaceDescription // 1. uris → try to extract apiPrefix and host/port info if len(endpoint.Uris) > 0 { for _, uriStr := range endpoint.Uris { u, err := url.Parse(uriStr) if err != nil || u.Host == "" { continue } host, portStr, _ := net.SplitHostPort(u.Host) var port *int if portStr != "" { p, err := strconv.Atoi(portStr) if err == nil { port = &p } } else { host = u.Host } desc := InterfaceDescription{ ApiPrefix: &u.Path, Port: port, } if ip := net.ParseIP(host); ip != nil { if ip.To4() != nil { desc.Ipv4Addr = &host } else { desc.Ipv6Addr = &host } } else { desc.Fqdn = &host } descs = append(descs, desc) } return descs } // 2. fqdn (no port) if len(endpoint.Fqdn) > 0 { for _, fqdn := range endpoint.Fqdn { desc := InterfaceDescription{ Fqdn: &fqdn, } descs = append(descs, desc) } return descs } // 3. addresses if len(endpoint.Addresses) > 0 { for _, addr := range endpoint.Addresses { port := int(addr.Port) desc := InterfaceDescription{ Port: &port, } if ip := net.ParseIP(addr.Host); ip != nil { if ip.To4() != nil { desc.Ipv4Addr = &addr.Host } else { desc.Ipv6Addr = &addr.Host } } else { desc.Fqdn = &addr.Host } descs = append(descs, desc) } return descs } return nil }