Endpoints NOS
This commit is contained in:
23
docs/sim-nos/Select Page.yml
Normal file
23
docs/sim-nos/Select Page.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
info:
|
||||||
|
name: Select Page
|
||||||
|
type: http
|
||||||
|
seq: 6
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: "{{baseurl}}/selectPage"
|
||||||
|
params:
|
||||||
|
- name: iccid
|
||||||
|
value: "8935103196306448300"
|
||||||
|
type: query
|
||||||
|
disabled: true
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: ""
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
25
docs/sim-nos/Select.yml
Normal file
25
docs/sim-nos/Select.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
info:
|
||||||
|
name: Select
|
||||||
|
type: http
|
||||||
|
seq: 5
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: "{{baseurl}}/select?iccid=8935103196306448300"
|
||||||
|
params:
|
||||||
|
- name: iccid
|
||||||
|
value: "8935103196306448300"
|
||||||
|
type: query
|
||||||
|
body:
|
||||||
|
type: json
|
||||||
|
data: |-
|
||||||
|
{
|
||||||
|
"iccid": "8933201125068890066"
|
||||||
|
}
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
name: local
|
name: local
|
||||||
color: "#2E8A54"
|
color: "#2E8A54"
|
||||||
variables:
|
variables:
|
||||||
- name: baseulr
|
- name: baseurl
|
||||||
value: http://localhost:3000
|
value: http://localhost:3001
|
||||||
|
- secret: true
|
||||||
|
name: token
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
NOS_BASE_URL=localhost
|
NOS_BASE_URL=localhost
|
||||||
|
APP_PORT=3001
|
||||||
|
APP_HOST="0.0.0.0"
|
||||||
|
|
||||||
ENVIORMENT=development
|
ENVIORMENT=development
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { ConsumeMessage } from "amqplib";
|
import { ConsumeMessage } from "amqplib";
|
||||||
|
import { Request, Response } from "express"
|
||||||
import { SimNosUsecases } from "./SimNOS.usecases";
|
import { SimNosUsecases } from "./SimNOS.usecases";
|
||||||
import { EventBus } from "sim-shared/domain/EventBus.port.js";
|
import { EventBus } from "sim-shared/domain/EventBus.port.js";
|
||||||
import { Result } from "sim-shared/domain/Result.js";
|
import { Result } from "sim-shared/domain/Result.js";
|
||||||
import { SimEvents } from "sim-shared/domain/SimEvents.js";
|
import { SimEvents } from "sim-shared/domain/SimEvents.js";
|
||||||
import { error } from "node:console";
|
import { iccidValidator } from "./httpValidators";
|
||||||
|
|
||||||
export class SimNosController {
|
export class SimNosController {
|
||||||
|
|
||||||
@@ -107,4 +108,73 @@ export class SimNosController {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select especificamente por REST para evitar pasar por las colas.
|
||||||
|
* La respuesta es instantanea no se tiene que registrar como operación.
|
||||||
|
*/
|
||||||
|
public selectREST() {
|
||||||
|
return async (req: Request, res: Response) => {
|
||||||
|
const { query } = req
|
||||||
|
const body = { iccid: query.iccid as string }
|
||||||
|
console.log("Evento select", body)
|
||||||
|
const validateBody = iccidValidator.validate(body);
|
||||||
|
|
||||||
|
if (validateBody.error != undefined) {
|
||||||
|
res.status(402).json(validateBody)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iccid: string | string[] = body.iccid
|
||||||
|
|
||||||
|
console.log("ICCID", iccid)
|
||||||
|
|
||||||
|
if (Array.isArray(iccid)) {
|
||||||
|
const usecaseRes = this.uscases.selectMany({ iccid })
|
||||||
|
} else {
|
||||||
|
const usecaseRes = await this.uscases.selectOne({ iccid })
|
||||||
|
console.log(usecaseRes)
|
||||||
|
if (usecaseRes.error != undefined) {
|
||||||
|
res.status(500).json(usecaseRes)
|
||||||
|
} else {
|
||||||
|
res.send(usecaseRes.data)
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json(validateBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public selectPageREST() {
|
||||||
|
return async (req: Request, res: Response) => {
|
||||||
|
const { query } = req
|
||||||
|
const body = {
|
||||||
|
iccid: query.iccid as string
|
||||||
|
}
|
||||||
|
console.log("Evento page", body)
|
||||||
|
/*
|
||||||
|
const validateBody = iccidValidator.validate(body);
|
||||||
|
|
||||||
|
if (validateBody.error != undefined) {
|
||||||
|
res.status(402).json(validateBody)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
const iccid: string | string[] = body.iccid
|
||||||
|
|
||||||
|
console.log("ICCID", iccid)
|
||||||
|
|
||||||
|
const usecaseRes = await this.uscases.selectPage({ iccid })
|
||||||
|
|
||||||
|
if (usecaseRes.error != undefined) {
|
||||||
|
res.status(500).json(usecaseRes)
|
||||||
|
} else {
|
||||||
|
res.status(200).send(usecaseRes.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ ok: "true" })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,4 +56,23 @@ export class SimNosUsecases {
|
|||||||
throw new Error("No hay termination para NOS")
|
throw new Error("No hay termination para NOS")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async selectOne(args: {
|
||||||
|
iccid: string
|
||||||
|
}) {
|
||||||
|
const res = await this.nosRepository.getLineInfo(args.iccid)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
public async selectPage(args: {
|
||||||
|
|
||||||
|
}) {
|
||||||
|
const res = await this.nosRepository.getLinePage(args)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
public selectMany(args: {
|
||||||
|
iccid: string[]
|
||||||
|
}) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
packages/sim-consumidor-nos/aplication/httpValidators.ts
Normal file
39
packages/sim-consumidor-nos/aplication/httpValidators.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { BodyValidator, Validator } from "sim-shared/aplication/BodyValidator.js";
|
||||||
|
|
||||||
|
const iccidNotNull = <Validator<{ iccid: unknown }>>{
|
||||||
|
field: "iccid",
|
||||||
|
errorMsg: "El iccid no está definido",
|
||||||
|
validationFunc: (a: { iccid: unknown }) => {
|
||||||
|
return (a.iccid != null && a.iccid != undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const iccidValueOrArray = <Validator<{ iccid: unknown }>>{
|
||||||
|
field: "iccid",
|
||||||
|
errorMsg: "El iccid debe de ser un único valor o una lista",
|
||||||
|
validationFunc: (a: { iccid: unknown }) => {
|
||||||
|
return (typeof a.iccid == "string" || Array.isArray(a.iccid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const iccidLongitudValidator = <Validator<{ iccid: string | string[] }>>{
|
||||||
|
field: "iccid",
|
||||||
|
errorMsg: "La longitud del iccid/s es incorrecta debera ser de 19 caracteres",
|
||||||
|
validationFunc: (a: { iccid: string | string[] }) => {
|
||||||
|
if (Array.isArray(a.iccid)) {
|
||||||
|
const res = (a.iccid as string[]).filter(e => e.length != 19)
|
||||||
|
if (res.length > 0) return false;
|
||||||
|
} else {
|
||||||
|
return (a.iccid as string).length == 19
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export const iccidValidator = new BodyValidator<{ iccid: string | string[] }>(
|
||||||
|
[
|
||||||
|
iccidNotNull,
|
||||||
|
iccidValueOrArray,
|
||||||
|
iccidLongitudValidator,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
@@ -30,6 +30,9 @@ export const env = {
|
|||||||
RABBITMQ_RETRY_INTERVAL: process.env.RABBITMQ_INTERVAL,
|
RABBITMQ_RETRY_INTERVAL: process.env.RABBITMQ_INTERVAL,
|
||||||
RABBITMQ_VHOST: String(process.env.RABBITMQ_VHOST),
|
RABBITMQ_VHOST: String(process.env.RABBITMQ_VHOST),
|
||||||
|
|
||||||
|
APP_PORT: Number(process.env.APP_PORT),
|
||||||
|
APP_HOST: String(process.env.APP_HOST),
|
||||||
|
|
||||||
// ESPECIFICO NOS
|
// ESPECIFICO NOS
|
||||||
NOS_BASE_URL: String(process.env.NOS_BASE_URL),
|
NOS_BASE_URL: String(process.env.NOS_BASE_URL),
|
||||||
NOS_ACCESS_TOKEN: String(process.env.NOS_ACCESS_TOKEN)
|
NOS_ACCESS_TOKEN: String(process.env.NOS_ACCESS_TOKEN)
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ export namespace NosApi {
|
|||||||
export type LineDataResponseError = ErrorResponse
|
export type LineDataResponseError = ErrorResponse
|
||||||
export type LineDataResponse = LineDataResponseOK | LineDataResponseError
|
export type LineDataResponse = LineDataResponseOK | LineDataResponseError
|
||||||
|
|
||||||
|
export type PageDataResponseOk = OkResponse<LineData[]>
|
||||||
|
export type PageDataResponseError = OkResponse<LineData[]>
|
||||||
|
export type PageResponse = PageDataResponseOk | PageDataResponseError
|
||||||
|
|
||||||
export type LineData = {
|
export type LineData = {
|
||||||
physicalId: string
|
physicalId: string
|
||||||
subscriberId: string
|
subscriberId: string
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
|
import express from "express"
|
||||||
|
import cors from 'cors';
|
||||||
import { startRMQClient } from "#config/eventBus.config.js"
|
import { startRMQClient } from "#config/eventBus.config.js"
|
||||||
import { SimNosRouter } from "aplication/SimNOS.router.js"
|
import { SimNosRouter } from "aplication/SimNOS.router.js"
|
||||||
import { SimNosController } from "./aplication/SimNOS.controller.js"
|
import { SimNosController } from "./aplication/SimNOS.controller.js"
|
||||||
import { SimNosUsecases } from "aplication/SimNOS.usecases.js"
|
import { SimNosUsecases } from "aplication/SimNOS.usecases.js"
|
||||||
import { NosHttpClient } from "infrastructure/NosHttpClient.js"
|
import { NosHttpClient } from "infrastructure/NosHttpClient.js"
|
||||||
import { env } from "#config/env/env.js"
|
import { env } from "#config/env/env.js"
|
||||||
|
import { NosRepository } from "infrastructure/NosRepository.js"
|
||||||
|
|
||||||
const RMQ_QUEUE = "sim.nos"
|
const RMQ_QUEUE = "sim.nos"
|
||||||
const NOS_BASE_URL = env.NOS_BASE_URL
|
const NOS_BASE_URL = env.NOS_BASE_URL
|
||||||
|
const PORT = env.APP_PORT
|
||||||
|
const HOSTNAME = env.APP_HOST
|
||||||
|
|
||||||
async function startWorker() {
|
async function startWorker() {
|
||||||
// Instancia de dependencias
|
// Instancia de dependencias
|
||||||
@@ -17,21 +21,47 @@ async function startWorker() {
|
|||||||
NOS_BASE_URL
|
NOS_BASE_URL
|
||||||
)
|
)
|
||||||
|
|
||||||
const simUsecases = new SimNosUsecases(
|
const nosRepository = new NosRepository(
|
||||||
nosHttpClient
|
nosHttpClient
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const simUsecases = new SimNosUsecases(
|
||||||
|
nosHttpClient,
|
||||||
|
nosRepository
|
||||||
|
)
|
||||||
|
|
||||||
const simController = new SimNosController(
|
const simController = new SimNosController(
|
||||||
simUsecases
|
simUsecases,
|
||||||
|
rmqClient
|
||||||
)
|
)
|
||||||
|
|
||||||
const simRouter = new SimNosRouter(
|
const simRouter = new SimNosRouter(
|
||||||
simController,
|
simController,
|
||||||
rmqClient
|
rmqClient
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// RMQ
|
||||||
rmqClient.consume(RMQ_QUEUE, simRouter.route)
|
rmqClient.consume(RMQ_QUEUE, simRouter.route)
|
||||||
|
.then(() => console.log("Cliente rmq creado con exito"))
|
||||||
|
.catch(e => console.error("Error conectando con RABBITMQ", e))
|
||||||
|
|
||||||
|
// Express
|
||||||
|
const app = express()
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
app.get("/select", simController.selectREST())
|
||||||
|
app.get("/selectPage", simController.selectPageREST())
|
||||||
|
|
||||||
|
app.listen(PORT, HOSTNAME, (e) => {
|
||||||
|
if (e == undefined) {
|
||||||
|
console.log("[o] Servidor iniciado en el puerto %d", PORT)
|
||||||
|
} else {
|
||||||
|
console.error("Error express ", e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startWorker()
|
startWorker()
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ export class NosRepository {
|
|||||||
if (axios.isAxiosError(e)) {
|
if (axios.isAxiosError(e)) {
|
||||||
const error = e as AxiosError
|
const error = e as AxiosError
|
||||||
return {
|
return {
|
||||||
error: error.code + " : " + JSON.stringify(error.response)
|
error: error.code + " : " + String(error.response?.statusText)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
error: JSON.stringify(e)
|
error: String(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,59 @@ export class NosRepository {
|
|||||||
|
|
||||||
public async getLineInfo(iccid: string): Promise<Result<string, NosApi.LineData>> {
|
public async getLineInfo(iccid: string): Promise<Result<string, NosApi.LineData>> {
|
||||||
const PATH = "/subscribers/" + iccid
|
const PATH = "/subscribers/" + iccid
|
||||||
|
console.log("PAth", PATH)
|
||||||
|
const lineRequest = this.httpClient.get<NosApi.LineDataResponseOK>(PATH)
|
||||||
|
const lineResponse = await this.manageNosRequest<string, NosApi.LineDataResponseOK>(lineRequest)
|
||||||
|
|
||||||
|
if (lineResponse.error != undefined) {
|
||||||
|
return lineResponse
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
data: lineResponse.data.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getLinePage(args: {
|
||||||
|
limit?: number,
|
||||||
|
offset?: number,
|
||||||
|
filter?: string,
|
||||||
|
orderBy?: string
|
||||||
|
}): Promise<Result<string, any>> {
|
||||||
|
const PATH = "/subscribers"
|
||||||
|
|
||||||
|
const LIMIT = 100
|
||||||
|
const options = {
|
||||||
|
limit: LIMIT,
|
||||||
|
offset: 0,
|
||||||
|
filter: args.filter,
|
||||||
|
orderBy: args.orderBy
|
||||||
|
}
|
||||||
|
|
||||||
|
const pageRequest = this.httpClient.get(PATH, {
|
||||||
|
params: options
|
||||||
|
})
|
||||||
|
|
||||||
|
const pageResponse = await this.manageNosRequest<string, any>(pageRequest)
|
||||||
|
if (pageResponse.error != undefined) {
|
||||||
|
return pageResponse
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
data: pageResponse.data.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getLinesInfo(iccid: string[]) /*Promise<Result<string, NosApi.LineData>>*/ {
|
||||||
|
throw new Error("NOS no permite buscar iccid en bulk, se puede hacer un apaño pero está en proceso")
|
||||||
|
const PATH = "/subscribers"
|
||||||
|
const LIMIT = 100
|
||||||
|
|
||||||
|
const steps = Math.ceil(iccid.length / LIMIT)
|
||||||
|
const options = {
|
||||||
|
limit: LIMIT,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
|
||||||
const req = this.httpClient.post<NosApi.LineDataResponseOK>(PATH)
|
const req = this.httpClient.post<NosApi.LineDataResponseOK>(PATH)
|
||||||
const resp = await this.manageNosRequest<string, NosApi.LineDataResponseOK>(req)
|
const resp = await this.manageNosRequest<string, NosApi.LineDataResponseOK>(req)
|
||||||
@@ -47,6 +100,7 @@ export class NosRepository {
|
|||||||
return resp
|
return resp
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
//@ts-expect-error
|
||||||
data: resp.data.content
|
data: resp.data.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
packages/sim-consumidor-nos/readme.md
Normal file
11
packages/sim-consumidor-nos/readme.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# NOS
|
||||||
|
|
||||||
|
## Particularidades de las operaciones de NOS
|
||||||
|
|
||||||
|
- Documentación de la API: [DOC](https://pelion-help.iot-x.com/nos/en/Content/API/APIReference/API%20Reference.htm?tocpath=_____7)
|
||||||
|
- No se necesita la pre-activación de las SIM.
|
||||||
|
- La suspensión y reactivación se llama "bar" y "unbar".
|
||||||
|
- El token de Authentication dura exactamente 1 año, solo se puede refrescar
|
||||||
|
desde la web.
|
||||||
|
- En la documentación la URL de la API es <https://nos-api.iot-x.com> pero la
|
||||||
|
de producción es <https://nosconnectcenter-api.iot-x.com>.
|
||||||
@@ -19,7 +19,6 @@ rabbitmqEventBus.connect()
|
|||||||
console.error("[!] El cliente RMQ no se ha podido iniciar", e)
|
console.error("[!] El cliente RMQ no se ha podido iniciar", e)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
|
|
||||||
@@ -39,4 +38,5 @@ app.get("/health", (req, res) => {
|
|||||||
app.listen(PORT, HOSTNAME, () => {
|
app.listen(PORT, HOSTNAME, () => {
|
||||||
console.log("[o] Servidor iniciado en el puerto %d", PORT)
|
console.log("[o] Servidor iniciado en el puerto %d", PORT)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default {}
|
export default {}
|
||||||
|
|||||||
Reference in New Issue
Block a user