better logs
This commit is contained in:
parent
25fe0ac9d2
commit
7365c9cb86
8 changed files with 116 additions and 32 deletions
17
src/auth.ts
17
src/auth.ts
|
|
@ -1,11 +1,14 @@
|
||||||
import { ServerOptions } from "../proto/autogenerated/ts/express_server";
|
import { ServerOptions } from "../proto/autogenerated/ts/express_server";
|
||||||
import { AdminContext } from "../proto/autogenerated/ts/types";
|
import { AdminContext } from "../proto/autogenerated/ts/types";
|
||||||
import Main from './services/main'
|
import Main from './services/main'
|
||||||
|
import { getLogger } from './services/helpers/logger'
|
||||||
const serverOptions = (mainHandler: Main): ServerOptions => {
|
const serverOptions = (mainHandler: Main): ServerOptions => {
|
||||||
|
const log = getLogger({})
|
||||||
return {
|
return {
|
||||||
|
logger: { log, error: err => log("ERROR", err) },
|
||||||
AdminAuthGuard: adminAuth,
|
AdminAuthGuard: adminAuth,
|
||||||
AppAuthGuard: async (authHeader) => { return { app_id: mainHandler.applicationManager.DecodeAppToken(authHeader) } },
|
AppAuthGuard: async (authHeader) => { return { app_id: mainHandler.applicationManager.DecodeAppToken(stripBearer(authHeader)) } },
|
||||||
UserAuthGuard: async (authHeader) => { return { user_id: mainHandler.userManager.DecodeUserToken(authHeader) } },
|
UserAuthGuard: async (authHeader) => { return { user_id: mainHandler.userManager.DecodeUserToken(stripBearer(authHeader)) } },
|
||||||
GuestAuthGuard: async (_) => ({}),
|
GuestAuthGuard: async (_) => ({}),
|
||||||
encryptCallback: async (_, b) => b,
|
encryptCallback: async (_, b) => b,
|
||||||
decryptCallback: async (_, b) => b,
|
decryptCallback: async (_, b) => b,
|
||||||
|
|
@ -13,6 +16,16 @@ const serverOptions = (mainHandler: Main): ServerOptions => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stripBearer = (header?: string) => {
|
||||||
|
if (!header) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if (header.startsWith("Bearer ")) {
|
||||||
|
return header.substring("Bearer ".length)
|
||||||
|
}
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
const adminAuth = async (header: string | undefined): Promise<AdminContext> => {
|
const adminAuth = async (header: string | undefined): Promise<AdminContext> => {
|
||||||
const AdminToken = process.env.ADMIN_TOKEN
|
const AdminToken = process.env.ADMIN_TOKEN
|
||||||
if (!AdminToken) {
|
if (!AdminToken) {
|
||||||
|
|
|
||||||
43
src/services/helpers/logger.ts
Normal file
43
src/services/helpers/logger.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import fs from 'fs'
|
||||||
|
type LoggerParams = { appName?: string, userId?: string }
|
||||||
|
export type PubLogger = (...message: (string | number | object)[]) => void
|
||||||
|
type Writer = (message: string) => void
|
||||||
|
try {
|
||||||
|
fs.mkdirSync("logs")
|
||||||
|
} catch { }
|
||||||
|
const z = (n: number) => n < 10 ? `0${n}` : `${n}`
|
||||||
|
const openWriter = (fileName: string): Writer => {
|
||||||
|
const logStream = fs.createWriteStream(`logs/${fileName}`, { flags: 'a' });
|
||||||
|
return (message) => {
|
||||||
|
logStream.write(message + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rootWriter = openWriter("ROOT.log")
|
||||||
|
export const getLogger = (params: LoggerParams): PubLogger => {
|
||||||
|
const writers: Writer[] = []
|
||||||
|
if (params.appName) {
|
||||||
|
writers.push(openWriter(`apps/${params.appName}.log`))
|
||||||
|
}
|
||||||
|
if (params.userId) {
|
||||||
|
writers.push(openWriter(`users/${params.userId}.log`))
|
||||||
|
}
|
||||||
|
if (writers.length === 0) {
|
||||||
|
writers.push(rootWriter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (...message) => {
|
||||||
|
const now = new Date()
|
||||||
|
const timestamp = `${now.getFullYear()}-${z(now.getMonth())}-${z(now.getDate())} ${z(now.getHours())}:${z(now.getMinutes())}:${z(now.getSeconds())}`
|
||||||
|
const toLog = [timestamp]
|
||||||
|
if (params.appName) {
|
||||||
|
toLog.push(params.appName)
|
||||||
|
}
|
||||||
|
if (params.userId) {
|
||||||
|
toLog.push(params.userId)
|
||||||
|
}
|
||||||
|
const parsed = message.map(m => typeof m === 'object' ? JSON.stringify(m) : m)
|
||||||
|
const final = `${toLog.join(" ")} >> ${parsed.join(" ")}`
|
||||||
|
console.log(final)
|
||||||
|
writers.forEach(w => w(final))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import { AddInvoiceReq } from './addInvoiceReq.js';
|
||||||
import { PayInvoiceReq } from './payInvoiceReq.js';
|
import { PayInvoiceReq } from './payInvoiceReq.js';
|
||||||
import { SendCoinsReq } from './sendCoinsReq.js';
|
import { SendCoinsReq } from './sendCoinsReq.js';
|
||||||
import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice } from './settings.js';
|
import { LndSettings, AddressPaidCb, InvoicePaidCb, NodeInfo, Invoice, DecodedInvoice, PaidInvoice } from './settings.js';
|
||||||
|
import { getLogger } from '../helpers/logger.js';
|
||||||
const DeadLineMetadata = (deadline = 10 * 1000) => ({ deadline: Date.now() + deadline })
|
const DeadLineMetadata = (deadline = 10 * 1000) => ({ deadline: Date.now() + deadline })
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
|
|
@ -26,6 +27,7 @@ export default class {
|
||||||
abortController = new AbortController()
|
abortController = new AbortController()
|
||||||
addressPaidCb: AddressPaidCb
|
addressPaidCb: AddressPaidCb
|
||||||
invoicePaidCb: InvoicePaidCb
|
invoicePaidCb: InvoicePaidCb
|
||||||
|
log = getLogger({})
|
||||||
constructor(settings: LndSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) {
|
constructor(settings: LndSettings, addressPaidCb: AddressPaidCb, invoicePaidCb: InvoicePaidCb) {
|
||||||
this.settings = settings
|
this.settings = settings
|
||||||
this.addressPaidCb = addressPaidCb
|
this.addressPaidCb = addressPaidCb
|
||||||
|
|
@ -84,19 +86,21 @@ export default class {
|
||||||
startHeight: this.latestKnownBlockHeigh,
|
startHeight: this.latestKnownBlockHeigh,
|
||||||
}, { abort: this.abortController.signal })
|
}, { abort: this.abortController.signal })
|
||||||
stream.responses.onMessage(tx => {
|
stream.responses.onMessage(tx => {
|
||||||
|
|
||||||
if (tx.blockHeight > this.latestKnownBlockHeigh) {
|
if (tx.blockHeight > this.latestKnownBlockHeigh) {
|
||||||
this.latestKnownBlockHeigh = tx.blockHeight
|
this.latestKnownBlockHeigh = tx.blockHeight
|
||||||
}
|
}
|
||||||
if (tx.numConfirmations > 0) {
|
if (tx.numConfirmations > 0) {
|
||||||
tx.outputDetails.forEach(output => {
|
tx.outputDetails.forEach(output => {
|
||||||
if (output.isOurAddress) {
|
if (output.isOurAddress) {
|
||||||
|
this.log("received chan TX", Number(output.amount), "sats")
|
||||||
this.addressPaidCb({ hash: tx.txHash, index: Number(output.outputIndex) }, output.address, Number(output.amount))
|
this.addressPaidCb({ hash: tx.txHash, index: Number(output.outputIndex) }, output.address, Number(output.amount))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
stream.responses.onError(error => {
|
stream.responses.onError(error => {
|
||||||
// TODO...
|
this.log("Error with invoice stream")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,12 +111,13 @@ export default class {
|
||||||
}, { abort: this.abortController.signal })
|
}, { abort: this.abortController.signal })
|
||||||
stream.responses.onMessage(invoice => {
|
stream.responses.onMessage(invoice => {
|
||||||
if (invoice.state === Invoice_InvoiceState.SETTLED) {
|
if (invoice.state === Invoice_InvoiceState.SETTLED) {
|
||||||
|
this.log("An invoice was paid for", Number(invoice.amtPaidSat), "sats")
|
||||||
this.latestKnownSettleIndex = Number(invoice.settleIndex)
|
this.latestKnownSettleIndex = Number(invoice.settleIndex)
|
||||||
this.invoicePaidCb(invoice.paymentRequest, Number(invoice.amtPaidSat))
|
this.invoicePaidCb(invoice.paymentRequest, Number(invoice.amtPaidSat))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
stream.responses.onError(error => {
|
stream.responses.onError(error => {
|
||||||
// TODO...
|
this.log("Error with invoice stream")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
async NewAddress(addressType: Types.AddressType): Promise<NewAddressResponse> {
|
async NewAddress(addressType: Types.AddressType): Promise<NewAddressResponse> {
|
||||||
|
|
@ -170,9 +175,11 @@ export default class {
|
||||||
console.log(payment)
|
console.log(payment)
|
||||||
switch (payment.status) {
|
switch (payment.status) {
|
||||||
case Payment_PaymentStatus.FAILED:
|
case Payment_PaymentStatus.FAILED:
|
||||||
|
this.log("invoice payment failed", payment.failureReason)
|
||||||
rej(PaymentFailureReason[payment.failureReason])
|
rej(PaymentFailureReason[payment.failureReason])
|
||||||
return
|
return
|
||||||
case Payment_PaymentStatus.SUCCEEDED:
|
case Payment_PaymentStatus.SUCCEEDED:
|
||||||
|
this.log("invoice payment succeded", Number(payment.valueSat))
|
||||||
res({ feeSat: Number(payment.feeSat), valueSat: Number(payment.valueSat), paymentPreimage: payment.paymentPreimage })
|
res({ feeSat: Number(payment.feeSat), valueSat: Number(payment.valueSat), paymentPreimage: payment.paymentPreimage })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -193,6 +200,7 @@ export default class {
|
||||||
async PayAddress(address: string, amount: number, satPerVByte: number, label = ""): Promise<SendCoinsResponse> {
|
async PayAddress(address: string, amount: number, satPerVByte: number, label = ""): Promise<SendCoinsResponse> {
|
||||||
this.checkReady()
|
this.checkReady()
|
||||||
const res = await this.lightning.sendCoins(SendCoinsReq(address, amount, satPerVByte, label), DeadLineMetadata())
|
const res = await this.lightning.sendCoins(SendCoinsReq(address, amount, satPerVByte, label), DeadLineMetadata())
|
||||||
|
this.log("sent chain TX for", amount, "sats")
|
||||||
return res.response
|
return res.response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { MainSettings } from './settings.js'
|
||||||
import PaymentManager from './paymentManager.js'
|
import PaymentManager from './paymentManager.js'
|
||||||
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
import { InboundOptionals, defaultInvoiceExpiry } from '../storage/paymentStorage.js'
|
||||||
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'
|
import { ApplicationUser } from '../storage/entity/ApplicationUser.js'
|
||||||
|
import { getLogger } from '../helpers/logger.js'
|
||||||
export default class {
|
export default class {
|
||||||
storage: Storage
|
storage: Storage
|
||||||
settings: MainSettings
|
settings: MainSettings
|
||||||
|
|
@ -35,7 +36,8 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async SetMockAppUserBalance(appId: string, req: Types.SetMockAppUserBalanceRequest) {
|
async SetMockAppUserBalance(appId: string, req: Types.SetMockAppUserBalanceRequest) {
|
||||||
const user = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.user_identifier, 0)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const { user } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.user_identifier, 0)
|
||||||
await this.paymentManager.SetMockUserBalance(user.user.user_id, req.amount)
|
await this.paymentManager.SetMockUserBalance(user.user.user_id, req.amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +49,8 @@ export default class {
|
||||||
|
|
||||||
async AddApp(req: Types.AuthAppRequest): Promise<Types.AuthApp> {
|
async AddApp(req: Types.AuthAppRequest): Promise<Types.AuthApp> {
|
||||||
const app = await this.storage.applicationStorage.AddApplication(req.name)
|
const app = await this.storage.applicationStorage.AddApplication(req.name)
|
||||||
|
getLogger({ appName: app.name })("app created")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
app: {
|
app: {
|
||||||
id: app.app_id,
|
id: app.app_id,
|
||||||
|
|
@ -79,11 +83,16 @@ export default class {
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddAppUser(appId: string, req: Types.AddAppUserRequest): Promise<Types.AppUser> {
|
async AddAppUser(appId: string, req: Types.AddAppUserRequest): Promise<Types.AppUser> {
|
||||||
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const log = getLogger({ appName: app.name })
|
||||||
let u: ApplicationUser
|
let u: ApplicationUser
|
||||||
if (req.fail_if_exists) {
|
if (req.fail_if_exists) {
|
||||||
u = await this.storage.applicationStorage.AddApplicationUser(appId, req.identifier, req.balance)
|
u = await this.storage.applicationStorage.AddApplicationUser(app, req.identifier, req.balance)
|
||||||
|
log(u.identifier, u.user.user_id, "user created")
|
||||||
} else {
|
} else {
|
||||||
u = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.identifier, req.balance)
|
const { user, created } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.identifier, req.balance)
|
||||||
|
u = user
|
||||||
|
if (created) log(u.identifier, u.user.user_id, "user created")
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
identifier: u.identifier,
|
identifier: u.identifier,
|
||||||
|
|
@ -97,26 +106,29 @@ export default class {
|
||||||
|
|
||||||
async AddAppInvoice(appId: string, req: Types.AddAppInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
async AddAppInvoice(appId: string, req: Types.AddAppInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const payer = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.payer_identifier, 0)
|
const { user: payer } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.payer_identifier, 0)
|
||||||
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
||||||
return this.paymentManager.NewInvoice(app.owner.user_id, req.invoice_req, opts)
|
const invoice = await this.paymentManager.NewInvoice(app.owner.user_id, req.invoice_req, opts)
|
||||||
|
getLogger({ appName: app.name })("app invoice created to be paid by", payer.identifier)
|
||||||
|
return invoice
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddAppUserInvoice(appId: string, req: Types.AddAppUserInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
async AddAppUserInvoice(appId: string, req: Types.AddAppUserInvoiceRequest): Promise<Types.NewInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const receiver = await this.storage.applicationStorage.GetApplicationUser(appId, req.receiver_identifier)
|
const receiver = await this.storage.applicationStorage.GetApplicationUser(app, req.receiver_identifier)
|
||||||
const payer = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.payer_identifier, 0)
|
const { user: payer } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.payer_identifier, 0)
|
||||||
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
const opts: InboundOptionals = { callbackUrl: req.http_callback_url, expiry: defaultInvoiceExpiry, expectedPayer: payer.user, linkedApplication: app }
|
||||||
const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts)
|
const appUserInvoice = await this.paymentManager.NewInvoice(receiver.user.user_id, req.invoice_req, opts)
|
||||||
|
getLogger({ appName: app.name })(receiver.identifier, "invoice created to be paid by", payer.identifier)
|
||||||
return {
|
return {
|
||||||
invoice: appUserInvoice.invoice
|
invoice: appUserInvoice.invoice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetAppUser(appId: string, req: Types.GetAppUserRequest): Promise<Types.AppUser> {
|
async GetAppUser(appId: string, req: Types.GetAppUserRequest): Promise<Types.AppUser> {
|
||||||
const user = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
||||||
const max = this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true)
|
const max = this.paymentManager.GetMaxPayableInvoice(user.user.balance_sats, true)
|
||||||
console.log(max, user.user.balance_sats)
|
|
||||||
return {
|
return {
|
||||||
max_withdrawable: max, identifier: req.user_identifier, info: {
|
max_withdrawable: max, identifier: req.user_identifier, info: {
|
||||||
userId: user.user.user_id, balance: user.user.balance_sats
|
userId: user.user.user_id, balance: user.user.balance_sats
|
||||||
|
|
@ -126,25 +138,29 @@ export default class {
|
||||||
|
|
||||||
async PayAppUserInvoice(appId: string, req: Types.PayAppUserInvoiceRequest): Promise<Types.PayAppUserInvoiceResponse> {
|
async PayAppUserInvoice(appId: string, req: Types.PayAppUserInvoiceRequest): Promise<Types.PayAppUserInvoiceResponse> {
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
const appUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
const appUser = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
||||||
return this.paymentManager.PayInvoice(appUser.user.user_id, req, app)
|
const paid = await this.paymentManager.PayInvoice(appUser.user.user_id, req, app)
|
||||||
|
getLogger({ appName: app.name })(appUser.identifier, "invoice paid", paid.amount_paid, "sats")
|
||||||
|
return paid
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendAppUserToAppUserPayment(appId: string, req: Types.SendAppUserToAppUserPaymentRequest): Promise<void> {
|
async SendAppUserToAppUserPayment(appId: string, req: Types.SendAppUserToAppUserPaymentRequest): Promise<void> {
|
||||||
const fromUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.from_user_identifier)
|
|
||||||
const toUser = await this.storage.applicationStorage.GetOrCreateApplicationUser(appId, req.to_user_identifier, 0)
|
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const fromUser = await this.storage.applicationStorage.GetApplicationUser(app, req.from_user_identifier)
|
||||||
|
const { user: toUser } = await this.storage.applicationStorage.GetOrCreateApplicationUser(app, req.to_user_identifier, 0)
|
||||||
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, toUser.user.user_id, req.amount, app)
|
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, toUser.user.user_id, req.amount, app)
|
||||||
|
getLogger({ appName: app.name })(toUser.identifier, "received internal payment by", fromUser.identifier, "of", req.amount, "sats")
|
||||||
}
|
}
|
||||||
|
|
||||||
async SendAppUserToAppPayment(appId: string, req: Types.SendAppUserToAppPaymentRequest): Promise<void> {
|
async SendAppUserToAppPayment(appId: string, req: Types.SendAppUserToAppPaymentRequest): Promise<void> {
|
||||||
const fromUser = await this.storage.applicationStorage.GetApplicationUser(appId, req.from_user_identifier)
|
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const fromUser = await this.storage.applicationStorage.GetApplicationUser(app, req.from_user_identifier)
|
||||||
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, app.owner.user_id, req.amount, app)
|
await this.paymentManager.SendUserToUserPayment(fromUser.user.user_id, app.owner.user_id, req.amount, app)
|
||||||
|
getLogger({ appName: app.name })("app received internal payment by", fromUser.identifier, "of", req.amount, "sats")
|
||||||
}
|
}
|
||||||
async GetAppUserLNURLInfo(appId: string, req: Types.GetAppUserLNURLInfoRequest): Promise<Types.LnurlPayInfoResponse> {
|
async GetAppUserLNURLInfo(appId: string, req: Types.GetAppUserLNURLInfoRequest): Promise<Types.LnurlPayInfoResponse> {
|
||||||
const user = await this.storage.applicationStorage.GetApplicationUser(appId, req.user_identifier)
|
|
||||||
const app = await this.storage.applicationStorage.GetApplication(appId)
|
const app = await this.storage.applicationStorage.GetApplication(appId)
|
||||||
|
const user = await this.storage.applicationStorage.GetApplicationUser(app, req.user_identifier)
|
||||||
return this.paymentManager.GetLnurlPayInfoFromUser(user.user.user_id, app, req.base_url_override)
|
return this.paymentManager.GetLnurlPayInfoFromUser(user.user.user_id, app, req.base_url_override)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -308,6 +308,7 @@ export default class {
|
||||||
const fromUser = await this.storage.userStorage.GetUser(fromUserId, tx)
|
const fromUser = await this.storage.userStorage.GetUser(fromUserId, tx)
|
||||||
const toUser = await this.storage.userStorage.GetUser(toUserId, tx)
|
const toUser = await this.storage.userStorage.GetUser(toUserId, tx)
|
||||||
if (fromUser.balance_sats < amount) {
|
if (fromUser.balance_sats < amount) {
|
||||||
|
console.log({balance:fromUser.balance_sats, amount})
|
||||||
throw new Error("not enough balance to send user to user payment")
|
throw new Error("not enough balance to send user to user payment")
|
||||||
}
|
}
|
||||||
if (!linkedApplication) {
|
if (!linkedApplication) {
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,6 @@ export default (mainHandler: Main): Types.ServerMethods => {
|
||||||
payer_identifier_CustomCheck: id => id !== '',
|
payer_identifier_CustomCheck: id => id !== '',
|
||||||
})
|
})
|
||||||
if (err != null) throw new Error(err.message)
|
if (err != null) throw new Error(err.message)
|
||||||
console.log(req)
|
|
||||||
return mainHandler.applicationManager.AddAppInvoice(ctx.app_id, req)
|
return mainHandler.applicationManager.AddAppInvoice(ctx.app_id, req)
|
||||||
},
|
},
|
||||||
AddAppUserInvoice: async (ctx, req) => {
|
AddAppUserInvoice: async (ctx, req) => {
|
||||||
|
|
|
||||||
|
|
@ -46,38 +46,38 @@ export default class {
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
async AddApplicationUser(appId: string, userIdentifier: string, balance: number) {
|
async AddApplicationUser(application: Application, userIdentifier: string, balance: number) {
|
||||||
return this.DB.transaction(async tx => {
|
return this.DB.transaction(async tx => {
|
||||||
const user = await this.userStorage.AddUser(balance, tx)
|
const user = await this.userStorage.AddUser(balance, tx)
|
||||||
const repo = tx.getRepository(ApplicationUser)
|
const repo = tx.getRepository(ApplicationUser)
|
||||||
const appUser = repo.create({
|
const appUser = repo.create({
|
||||||
user: user,
|
user: user,
|
||||||
application: await this.GetApplication(appId),
|
application,
|
||||||
identifier: userIdentifier,
|
identifier: userIdentifier,
|
||||||
})
|
})
|
||||||
return repo.save(appUser)
|
return repo.save(appUser)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
GetApplicationUserIfExists(appId: string, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
GetApplicationUserIfExists(application: Application, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser | null> {
|
||||||
return entityManager.getRepository(ApplicationUser).findOne({ where: { identifier: userIdentifier, application: { app_id: appId } } })
|
return entityManager.getRepository(ApplicationUser).findOne({ where: { identifier: userIdentifier, application: application } })
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetOrCreateApplicationUser(appId: string, userIdentifier: string, balance: number, entityManager = this.DB): Promise<ApplicationUser> {
|
async GetOrCreateApplicationUser(application: Application, userIdentifier: string, balance: number, entityManager = this.DB): Promise<{ user: ApplicationUser, created: boolean }> {
|
||||||
const found = await this.GetApplicationUserIfExists(appId, userIdentifier, entityManager)
|
const user = await this.GetApplicationUserIfExists(application, userIdentifier, entityManager)
|
||||||
if (found) {
|
if (user) {
|
||||||
return found
|
return { user, created: false }
|
||||||
}
|
}
|
||||||
return this.AddApplicationUser(appId, userIdentifier, balance)
|
return { user: await this.AddApplicationUser(application, userIdentifier, balance), created: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
async GetApplicationUser(appId: string, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser> {
|
async GetApplicationUser(application: Application, userIdentifier: string, entityManager = this.DB): Promise<ApplicationUser> {
|
||||||
const found = await this.GetApplicationUserIfExists(appId, userIdentifier, entityManager)
|
const found = await this.GetApplicationUserIfExists(application, userIdentifier, entityManager)
|
||||||
if (!found) {
|
if (!found) {
|
||||||
throw new Error(`application user not found`)
|
throw new Error(`application user not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found.application.app_id !== appId) {
|
if (found.application.app_id !== application.app_id) {
|
||||||
throw new Error("requested user does not belong to requestor application")
|
throw new Error("requested user does not belong to requestor application")
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { DataSource, EntityManager } from "typeorm"
|
||||||
import { User } from './entity/User.js';
|
import { User } from './entity/User.js';
|
||||||
import { UserBasicAuth } from './entity/UserBasicAuth.js';
|
import { UserBasicAuth } from './entity/UserBasicAuth.js';
|
||||||
import { UserNostrAuth } from './entity/UserNostrAuth.js';
|
import { UserNostrAuth } from './entity/UserNostrAuth.js';
|
||||||
|
import { getLogger } from '../helpers/logger.js';
|
||||||
export default class {
|
export default class {
|
||||||
DB: DataSource | EntityManager
|
DB: DataSource | EntityManager
|
||||||
constructor(DB: DataSource | EntityManager) {
|
constructor(DB: DataSource | EntityManager) {
|
||||||
|
|
@ -84,12 +85,14 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async IncrementUserBalance(userId: string, increment: number, entityManager = this.DB) {
|
async IncrementUserBalance(userId: string, increment: number, entityManager = this.DB) {
|
||||||
|
const user = await this.GetUser(userId, entityManager)
|
||||||
const res = await entityManager.getRepository(User).increment({
|
const res = await entityManager.getRepository(User).increment({
|
||||||
user_id: userId,
|
user_id: userId,
|
||||||
}, "balance_sats", increment)
|
}, "balance_sats", increment)
|
||||||
if (!res.affected) {
|
if (!res.affected) {
|
||||||
throw new Error("unaffected balance increment for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected balance increment for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
|
getLogger({ userId: userId })("incremented balance from", user.balance_sats, "sats, by", increment, "sats")
|
||||||
}
|
}
|
||||||
async DecrementUserBalance(userId: string, decrement: number, entityManager = this.DB) {
|
async DecrementUserBalance(userId: string, decrement: number, entityManager = this.DB) {
|
||||||
const user = await this.GetUser(userId, entityManager)
|
const user = await this.GetUser(userId, entityManager)
|
||||||
|
|
@ -102,6 +105,7 @@ export default class {
|
||||||
if (!res.affected) {
|
if (!res.affected) {
|
||||||
throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing
|
throw new Error("unaffected balance decrement for " + userId) // TODO: fix logs doxing
|
||||||
}
|
}
|
||||||
|
getLogger({ userId: userId })("decremented balance from", user.balance_sats, "sats, by", decrement, "sats")
|
||||||
}
|
}
|
||||||
|
|
||||||
async UpdateUser(userId: string, update: Partial<User>, entityManager = this.DB) {
|
async UpdateUser(userId: string, update: Partial<User>, entityManager = this.DB) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue