Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Revamp - NLMF support
Browse files Browse the repository at this point in the history
Signed-off-by: Mathis Joffre <[email protected]>
  • Loading branch information
Joffref committed Jan 28, 2023
1 parent fb6cb61 commit c679a80
Show file tree
Hide file tree
Showing 42 changed files with 986 additions and 3,718 deletions.
13 changes: 2 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

Under the hood, the SDK exposes through a RESTful API the Network Function you've built, according to the standard. The RESTful API is implemented using [Gin](https://github.com/gin-gonic/gin) framework.

At the moment, the APIs are implemented for the release 15 of the 3GPP specifications (3GPP TS 29.571 version 15.3.0 Release 15).
At the moment, the APIs are implemented for the release 18 of the 3GPP specifications.

## Getting Started

Expand All @@ -41,13 +41,4 @@ Licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

## Roadmap

- [x] Implement all the common Data Types from the [3GPP specifications - 3GPP TS 29.571 version 15.3.0 Release 15](https://www.etsi.org/deliver/etsi_ts/129500_129599/129571/15.03.00_60/ts_129571v150300p.pdf)
- [ ] Provides NAF API
- [ ] Provides NAMF API
- [ ] Provides NAUSF API
- [ ] Provides NNEF API
- [ ] Provides NNRF API
- [ ] Provides NNSSF API
- [ ] Provides NPCF API
- [ ] Provides NSMF API
- [ ] Provides NUDM API
TBD
31 changes: 31 additions & 0 deletions fivegc/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package fivegc

import "net/http"

// ClientConfiguration stores the configuration of the API client
type ClientConfiguration struct {
Host string `json:"host,omitempty"`
Scheme string `json:"scheme,omitempty"`
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
Debug bool `json:"debug,omitempty"`
Servers ServerConfigurations
OperationServers map[string]ServerConfigurations
HTTPClient *http.Client
}

type ServerConfigurations []ServerConfiguration

// ServerConfiguration stores the information about a server
type ServerConfiguration struct {
URL string
Description string
Variables map[string]ServerVariable
}

// ServerVariable stores the information about a server variable
type ServerVariable struct {
Description string
DefaultValue string
EnumValues []string
}
111 changes: 111 additions & 0 deletions fivegc/nlmf/broadcast.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package nlmf

import (
"context"
"github.com/5GCoreNet/5GCoreNetSDK/fivegc"
"github.com/5GCoreNet/5GCoreNetSDK/internal/header"
openapinlmfbroadcastclient "github.com/5GCoreNet/client-openapi/Nlmf_Broadcast"
openapinlmfbroadcastserver "github.com/5GCoreNet/server-openapi/Nlmf_Broadcast"
"github.com/gin-gonic/gin"
)

type Broadcast interface {
// Error returns a problem details, it is used to handle errors when unmarshalling the request.
Error(ctx context.Context, err error) openapinlmfbroadcastserver.ProblemDetails
// CipherKeyData returns a cipher response data, a problem details, a redirect response and a status code.
CipherKeyData(context.Context, openapinlmfbroadcastserver.CipherRequestData) (openapinlmfbroadcastserver.CipherResponseData, openapinlmfbroadcastserver.ProblemDetails, fivegc.RedirectResponse, fivegc.StatusCode)
}

func attachBroadcastHandler(router *gin.RouterGroup, b Broadcast) {
group := router.Group("/nlmf-broadcast/v1")
{
group.POST("/cipher-key-data", func(c *gin.Context) {
var req openapinlmfbroadcastserver.CipherRequestData
if err := c.ShouldBindJSON(&req); err != nil {
problemDetails := b.Error(c, err)
c.JSON(int(problemDetails.Status), problemDetails)
return
}
res, problemDetails, redirectResponse, status := b.CipherKeyData(c, req)
switch status {
case fivegc.StatusOK:
c.JSON(status.ToInt(), res)
case fivegc.StatusTemporaryRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
case fivegc.StatusPermanentRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
default:
c.JSON(status.ToInt(), problemDetails)
}
return
})
}
}

// BroadcastClient is a client for the Nlmf_Broadcast service.
type BroadcastClient struct {
client *openapinlmfbroadcastclient.APIClient
}

// NewBroadcastClient creates a new client for the Nlmf_Broadcast service.
func NewBroadcastClient(cfg fivegc.ClientConfiguration) *BroadcastClient {
openapiCfg := &openapinlmfbroadcastclient.Configuration{
Host: cfg.Host,
Scheme: cfg.Scheme,
DefaultHeader: cfg.DefaultHeader,
UserAgent: cfg.UserAgent,
Debug: cfg.Debug,
Servers: []openapinlmfbroadcastclient.ServerConfiguration{},
OperationServers: make(map[string]openapinlmfbroadcastclient.ServerConfigurations),
HTTPClient: cfg.HTTPClient,
}
for _, server := range cfg.Servers {
openapiServer := openapinlmfbroadcastclient.ServerConfiguration{
URL: server.URL,
Description: server.Description,
Variables: make(map[string]openapinlmfbroadcastclient.ServerVariable),
}
for name, variable := range server.Variables {
openapiServer.Variables[name] = openapinlmfbroadcastclient.ServerVariable{
Description: variable.Description,
DefaultValue: variable.DefaultValue,
EnumValues: variable.EnumValues,
}
}
openapiCfg.Servers = append(openapiCfg.Servers, openapiServer)
}
for name, servers := range cfg.OperationServers {
openapiServers := make(openapinlmfbroadcastclient.ServerConfigurations, len(servers))
for i, server := range servers {
openapiServers[i] = openapinlmfbroadcastclient.ServerConfiguration{
URL: server.URL,
Description: server.Description,
Variables: make(map[string]openapinlmfbroadcastclient.ServerVariable),
}
for name, variable := range server.Variables {
openapiServers[i].Variables[name] = openapinlmfbroadcastclient.ServerVariable{
Description: variable.Description,
DefaultValue: variable.DefaultValue,
EnumValues: variable.EnumValues,
}
}
}
openapiCfg.OperationServers[name] = openapiServers
}
return &BroadcastClient{
client: openapinlmfbroadcastclient.NewAPIClient(openapiCfg),
}
}

// CipheringKeyData returns a cipher request.
func (c *BroadcastClient) CipheringKeyData(ctx context.Context) openapinlmfbroadcastclient.ApiCipheringKeyDataRequest {
return c.client.RequestCipheringKeyDataApi.CipheringKeyData(ctx)
}

// CipheringKeyDataExecute executes a cipher request.
func (c *BroadcastClient) CipheringKeyDataExecute(r openapinlmfbroadcastclient.ApiCipheringKeyDataRequest) (*openapinlmfbroadcastclient.CipherResponseData, error) {
resp, _, err := r.Execute()
return resp, err
}
181 changes: 181 additions & 0 deletions fivegc/nlmf/location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package nlmf

import (
"context"
"github.com/5GCoreNet/5GCoreNetSDK/fivegc"
"github.com/5GCoreNet/5GCoreNetSDK/internal/header"
openapinlmflocationclient "github.com/5GCoreNet/client-openapi/Nlmf_Location"
openapinlmflocationserver "github.com/5GCoreNet/server-openapi/Nlmf_Location"
"github.com/gin-gonic/gin"
"net/http"
)

type Location interface {
// Error returns a problem details, it is used to handle errors when unmarshalling the request.
Error(ctx context.Context, err error) openapinlmflocationserver.ProblemDetails
// CancelLocation cancels a location request.
CancelLocation(context.Context, openapinlmflocationserver.CancelLocData) (openapinlmflocationserver.ProblemDetails, fivegc.RedirectResponse, fivegc.StatusCode)
// DetermineLocation determines the location of a UE.
DetermineLocation(context.Context, openapinlmflocationserver.InputData) (openapinlmflocationserver.LocationData, openapinlmflocationserver.ProblemDetails, fivegc.RedirectResponse, fivegc.StatusCode)
// LocationContextTransfer transfers the location context of a UE.
LocationContextTransfer(context.Context, openapinlmflocationserver.LocContextData) (openapinlmflocationserver.ProblemDetails, fivegc.RedirectResponse, fivegc.StatusCode)
}

func attachLocationHandler(router *gin.RouterGroup, l Location) {
group := router.Group("/nlmf-loc/v1")
{
group.POST("/cancel-location", func(c *gin.Context) {
var req openapinlmflocationserver.CancelLocData
if err := c.ShouldBindJSON(&req); err != nil {
problemDetails := l.Error(c, err)
c.JSON(int(problemDetails.Status), problemDetails)
return
}
problemDetails, redirectResponse, status := l.CancelLocation(c, req)
switch status {
case fivegc.StatusNoContent:
c.JSON(status.ToInt(), nil)
case fivegc.StatusTemporaryRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
case fivegc.StatusPermanentRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
default:
c.JSON(status.ToInt(), problemDetails)
}
return
})
group.POST("/determine-location", func(c *gin.Context) {
var req openapinlmflocationserver.InputData
if err := c.ShouldBindJSON(&req); err != nil {
problemDetails := l.Error(c, err)
c.JSON(int(problemDetails.Status), problemDetails)
return
}
res, problemDetails, redirectResponse, status := l.DetermineLocation(c, req)
switch status {
case fivegc.StatusOK:
c.JSON(status.ToInt(), res)
case fivegc.StatusNoContent:
c.JSON(status.ToInt(), nil)
case fivegc.StatusTemporaryRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
case fivegc.StatusPermanentRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
default:
c.JSON(status.ToInt(), problemDetails)
}
return
})
group.POST("/location-context-transfer", func(c *gin.Context) {
var req openapinlmflocationserver.LocContextData
if err := c.ShouldBindJSON(&req); err != nil {
problemDetails := l.Error(c, err)
c.JSON(int(problemDetails.Status), problemDetails)
return
}
problemDetails, redirectResponse, status := l.LocationContextTransfer(c, req)
switch status {
case fivegc.StatusNoContent:
c.JSON(status.ToInt(), nil)
case fivegc.StatusTemporaryRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
case fivegc.StatusPermanentRedirect:
header.BindRedirectHeader(c, redirectResponse.RedirectHeader)
c.JSON(status.ToInt(), redirectResponse)
default:
c.JSON(status.ToInt(), problemDetails)
}
return
})
}
}

// LocationClient is a client for the Nlmf_location service.
type LocationClient struct {
client *openapinlmflocationclient.APIClient
}

// NewLocationClient creates a new client for the Nlmf_location service.
func NewLocationClient(cfg fivegc.ClientConfiguration) *LocationClient {
openapiCfg := &openapinlmflocationclient.Configuration{
Host: cfg.Host,
Scheme: cfg.Scheme,
DefaultHeader: cfg.DefaultHeader,
UserAgent: cfg.UserAgent,
Debug: cfg.Debug,
Servers: []openapinlmflocationclient.ServerConfiguration{},
OperationServers: make(map[string]openapinlmflocationclient.ServerConfigurations),
HTTPClient: cfg.HTTPClient,
}
for _, server := range cfg.Servers {
openapiServer := openapinlmflocationclient.ServerConfiguration{
URL: server.URL,
Description: server.Description,
Variables: make(map[string]openapinlmflocationclient.ServerVariable),
}
for name, variable := range server.Variables {
openapiServer.Variables[name] = openapinlmflocationclient.ServerVariable{
Description: variable.Description,
DefaultValue: variable.DefaultValue,
EnumValues: variable.EnumValues,
}
}
openapiCfg.Servers = append(openapiCfg.Servers, openapiServer)
}
for name, servers := range cfg.OperationServers {
openapiServers := make(openapinlmflocationclient.ServerConfigurations, len(servers))
for i, server := range servers {
openapiServers[i] = openapinlmflocationclient.ServerConfiguration{
URL: server.URL,
Description: server.Description,
Variables: make(map[string]openapinlmflocationclient.ServerVariable),
}
for name, variable := range server.Variables {
openapiServers[i].Variables[name] = openapinlmflocationclient.ServerVariable{
Description: variable.Description,
DefaultValue: variable.DefaultValue,
EnumValues: variable.EnumValues,
}
}
}
openapiCfg.OperationServers[name] = openapiServers
}
return &LocationClient{
client: openapinlmflocationclient.NewAPIClient(openapiCfg),
}
}

// LocationContextTransfer returns location context transfer request
func (l LocationClient) LocationContextTransfer(ctx context.Context) openapinlmflocationclient.ApiLocationContextTransferRequest {
return l.client.LocationContextTransferApi.LocationContextTransfer(ctx)
}

// LocationContextTransferExecute executes the location context transfer request
func (l LocationClient) LocationContextTransferExecute(r openapinlmflocationclient.ApiLocationContextTransferRequest) (*http.Response, error) {
return r.Execute()
}

// DetermineLocation returns determine location request
func (l LocationClient) DetermineLocation(ctx context.Context) openapinlmflocationclient.ApiDetermineLocationRequest {
return l.client.DetermineLocationApi.DetermineLocation(ctx)
}

// DetermineLocationExecute executes the determine location request
func (l LocationClient) DetermineLocationExecute(r openapinlmflocationclient.ApiDetermineLocationRequest) (*openapinlmflocationclient.LocationData, *http.Response, error) {
return r.Execute()
}

// CancelLocation returns cancel location request
func (l LocationClient) CancelLocation(ctx context.Context) openapinlmflocationclient.ApiCancelLocationRequest {
return l.client.CancelLocationApi.CancelLocation(ctx)
}

// CancelLocationExecute executes the cancel location request
func (l LocationClient) CancelLocationExecute(r openapinlmflocationclient.ApiCancelLocationRequest) (*http.Response, error) {
return r.Execute()
}
Loading

0 comments on commit c679a80

Please sign in to comment.