Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/app-mtp/main/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export default {
},
moduleFileExtensions: ["ts", "tsx", "js", "jsx"],
coverageDirectory: "../../../coverage/libs/app-mtp/main",
testEnvironment: "node",
}
7 changes: 7 additions & 0 deletions libs/app-mtp/main/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

export * from "./lib/app-mtp"
export * from "./lib/app-mtp.interface"
102 changes: 102 additions & 0 deletions libs/app-mtp/main/src/lib/app-examples/app-mtp-cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import yargs from "yargs"
import { hideBin } from "yargs/helpers"
import { AppMtp } from "../app-mtp"
import {
TransferTransactionData,
MtpTransferFileData,
} from "../app-mtp.interface"
import * as dotenv from "dotenv"
import { DotnetCliCommandAction } from "../dotnet-mtp/dotnet-mtp.interface"

dotenv.config()
const appMtp = new AppMtp()

interface MtpCliCommand {
action: DotnetCliCommandAction

[key: string]: unknown
}

const handleAction = (action: DotnetCliCommandAction, parsedData: unknown) => {
switch (action) {
case DotnetCliCommandAction.GET_DEVICES:
appMtp
.getDevices()
.then((devices) => {
console.log("[app-mtp-cli] output: ", devices)
})
.catch((err) => {
console.error("[app-mtp-cli] output: Error fetching devices:", err)
})
break

case DotnetCliCommandAction.GET_DEVICE_STORAGES:
appMtp
.getDeviceStorages((parsedData as { deviceId: string }).deviceId)
.then((storages) => {
console.log("[app-mtp-cli] output:", storages)
})
.catch((err) => {
console.error(
"[app-mtp-cli] output: Error fetching device storages:",
err
)
})
break

case DotnetCliCommandAction.UPLOAD_FILE:
appMtp
.uploadFile(parsedData as MtpTransferFileData)
.then(() => {
console.log("[app-mtp-cli] output: File uploaded successfully.")
})
.catch((err) => {
console.error("[app-mtp-cli] output: Error uploading file:", err)
})
break

case DotnetCliCommandAction.GET_UPLOAD_FILE_PROGRESS:
appMtp
.getTransferredFileProgress(parsedData as TransferTransactionData)
.then((progress) => {
console.log("[app-mtp-cli] output:", progress)
})
.catch((err) => {
console.error(
"[app-mtp-cli] output: Error fetching upload file progress:",
err
)
})
break

default:
console.error("[app-mtp-cli] output: Unknown action:", action)
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-expressions
yargs(hideBin(process.argv))
.middleware((argv) => {
const jsonString = argv._[0] as string
if (jsonString) {
try {
const parsedData: MtpCliCommand = JSON.parse(jsonString)
console.log("[app-mtp-cli] input: ", parsedData)

const { action } = parsedData

handleAction(action, parsedData)
} catch (error) {
console.error("[app-mtp-cli] output: Invalid JSON string:", jsonString)
console.error("[app-mtp-cli] output:", error)
}
} else {
console.error("[app-mtp-cli] output: No JSON string provided.")
}
})
.help().argv
62 changes: 62 additions & 0 deletions libs/app-mtp/main/src/lib/app-examples/app-mtp-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import express, { Application, Request, Response, Router } from "express"
import bodyParser from "body-parser"
import http from "http"
import { AppMtp } from "../app-mtp"
import * as dotenv from "dotenv"

dotenv.config()
const appMtp = new AppMtp()

const app: Application = express()
const router: Router = Router()

app.use(bodyParser.json())

router.get("/get-devices", (_req: Request, res: Response) => {
appMtp.getDevices().then((devices) => {
res.json(devices)
})
})

router.get("/get-device-storages", (req: Request, res: Response) => {
const deviceId = req.body.deviceId
appMtp.getDeviceStorages(deviceId).then((result) => {
res.json(result)
})
})

router.post("/upload-file", (req: Request, res: Response) => {
appMtp.uploadFile(req.body).then((result) => {
res.json(result)
})
})

router.post("/export-file", (req: Request, res: Response) => {
appMtp.exportFile(req.body).then((result) => {
res.json(result)
})
})

router.get("/transferred-file-progress", (req: Request, res: Response) => {
appMtp.getTransferredFileProgress(req.body).then((result) => {
res.json(result)
})
})

router.get("/cancel-file-transfer", (req: Request, res: Response) => {
appMtp.cancelFileTransfer(req.body).then((result) => {
res.json(result)
})
})

app.use("/", router)

const server = http.createServer(app)
server.listen(3000, () => {
console.log("[app-mtp-server] running at http://127.0.0.1:3000/")
})
19 changes: 19 additions & 0 deletions libs/app-mtp/main/src/lib/app-mtp.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import { MtpInterface } from "./app-mtp.interface"
import { DotnetMtp } from "./dotnet-mtp/dotnet-mtp"
import { NodeMtp } from "./node-mtp/node-mtp"
import { NodeMtpDeviceManager } from "./node-mtp/node-mtp-device-manager"

export class MtpFactory {
static createInstance(): MtpInterface {
if (process.platform === "win32") {
return new DotnetMtp()
} else {
return new NodeMtp(new NodeMtpDeviceManager())
}
}
}
84 changes: 84 additions & 0 deletions libs/app-mtp/main/src/lib/app-mtp.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import { AppError, AppResult } from "app-utils/models"

export interface MtpDevice {
id: string
name: string
}

export interface MtpStorage {
id: string
name: string
isInternal?: boolean
}

export interface TransactionStatus {
progress: number
error?: AppError
}

export enum MTPError {
MTP_DEVICE_NOT_FOUND = "MTP_DEVICE_NOT_FOUND",
MTP_STORAGE_NOT_FOUND = "MTP_STORAGE_NOT_FOUND",
MTP_SOURCE_PATH_NOT_FOUND = "MTP_SOURCE_PATH_NOT_FOUND",
MTP_TRANSACTION_NOT_FOUND = "MTP_TRANSACTION_NOT_FOUND",
MTP_READ_TIMEOUT = "MTP_READ_TIMEOUT",
MTP_READ_FAILURE = "MTP_READ_FAILURE",
MTP_WRITE_TIMEOUT = "MTP_WRITE_TIMEOUT",
MTP_GENERAL_ERROR = "MTP_GENERAL_ERROR",
MTP_PROCESS_CANCELLED = "MTP_PROCESS_CANCELLED",
MTP_INITIALIZE_ACCESS_ERROR = "MTP_INITIALIZE_ACCESS_ERROR",
MTP_FILE_EXISTS_ERROR = "MTP_FILE_EXISTS_ERROR",
MTP_NOT_ENOUGH_SPACE = "MTP_NOT_ENOUGH_SPACE",
MTP_CANCEL_FAILED_ALREADY_TRANSFERRED = "MTP_CANCEL_FAILED_ALREADY_TRANSFERRED",
}

export interface MtpTransferFileData {
deviceId: string // on Mac and Linux: Kompakt serial number; on Windows: PID
storageId: string
destinationPath: string
sourcePath: string
action?: string
}

export interface TransferFileResultData {
transactionId: string
}

export interface TransferTransactionData {
transactionId: string
}

export interface GetTransferFileProgressResultData {
progress: number
}

export type TransferUploadFileResultData = object

export type CancelTransferResultData = object

export interface MtpInterface {
getDevices(): Promise<MtpDevice[]>

getDeviceStorages(deviceId: string): Promise<AppResult<MtpStorage[]>>

uploadFile(
data: MtpTransferFileData
): Promise<AppResult<TransferFileResultData>>

exportFile(
data: MtpTransferFileData
): Promise<AppResult<TransferFileResultData>>

getTransferredFileProgress(
data: TransferTransactionData
): Promise<AppResult<GetTransferFileProgressResultData>>

cancelFileTransfer(
data: TransferTransactionData
): Promise<AppResult<CancelTransferResultData>>
}
92 changes: 92 additions & 0 deletions libs/app-mtp/main/src/lib/app-mtp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import { AppResult } from "app-utils/models"
import {
CancelTransferResultData,
TransferTransactionData,
GetTransferFileProgressResultData,
MtpDevice,
MtpInterface,
MtpStorage,
MtpTransferFileData,
TransferFileResultData,
} from "./app-mtp.interface"
import { MtpFactory } from "./app-mtp.factory"

export class AppMtp implements MtpInterface {
private mtp: MtpInterface

constructor() {
this.mtp = MtpFactory.createInstance()
}

async getDevices(): Promise<MtpDevice[]> {
console.log(`[app-mtp] getting devices`)
const result = await this.mtp.getDevices()
console.log(`[app-mtp] getting devices result: ${JSON.stringify(result)}`)
return result
}

async getDeviceStorages(deviceId: string): Promise<AppResult<MtpStorage[]>> {
console.log(`[app-mtp] getting device storages for device: ${deviceId}`)
const result = await this.mtp.getDeviceStorages(deviceId)
console.log(
`[app-mtp] getting device storages result: ${JSON.stringify(result)}`
)
return result
}

async uploadFile(
data: MtpTransferFileData
): Promise<AppResult<TransferFileResultData>> {
console.log(
`[app-mtp] starting upload file process for data: ${JSON.stringify(data)}`
)
const result = await this.mtp.uploadFile(data)
console.log(
`[app-mtp] starting upload file process result: ${JSON.stringify(result)}`
)
return result
}

async exportFile(
data: MtpTransferFileData
): Promise<AppResult<TransferFileResultData>> {
console.log(
`[app-mtp] starting export file process for data: ${JSON.stringify(data)}`
)
const result = await this.mtp.exportFile(data)
console.log(
`[app-mtp] starting export file process result: ${JSON.stringify(result)}`
)
return result
}

async getTransferredFileProgress(
data: TransferTransactionData
): Promise<AppResult<GetTransferFileProgressResultData>> {
console.log(
`[app-mtp] getting file transfer progress for transaction: ${data.transactionId}`
)
const result = await this.mtp.getTransferredFileProgress(data)

console.log(
`[app-mtp] getting file transfer progress result: ${JSON.stringify(
result
)}`
)

return result
}

async cancelFileTransfer(
data: TransferTransactionData
): Promise<AppResult<CancelTransferResultData>> {
const result = await this.mtp.cancelFileTransfer(data)
console.log(`[app-mtp] canceling status: ${JSON.stringify(result)}`)
return result
}
}
Loading
Loading