p2p submodule split, bug fixes

This commit is contained in:
mrfry
2023-05-03 16:07:45 +02:00
parent 0fea32c204
commit 54c3e1252b
12 changed files with 1426 additions and 995 deletions
+295
View File
@@ -0,0 +1,295 @@
import path from 'node:path'
import { paths } from '../../../utils/files'
import utils from '../../../utils/utils'
import { UserDirDataFile } from '../submodules/userFiles'
import {
SyncDataResult,
SyncResponseBase,
SyncResult,
peerToString,
updatePeersFile,
} from './p2putils'
import constants from '../../../constants'
import { PeerInfo } from '../../../types/basicTypes'
import { downloadFile } from '../../../utils/networkUtils'
import logger from '../../../utils/logger'
interface UserFileToGet {
fileName: string
dir: string
filePath: string
data: UserDirDataFile
peer: PeerInfo
}
export interface NewUserFilesRequestBody {
host: string
newFiles: {
[key: string]: {
// key: dir
[key: string]: UserDirDataFile // key: file name
}
}
}
// ---------------------------------------------------------------------------------------------
// Getting
// ---------------------------------------------------------------------------------------------
export function getUserFiles(since: number): SyncResponseBase & {
newFiles: {
[key: string]: {
[key: string]: UserDirDataFile
}
}
} {
const newFiles: SyncDataResult['userFiles']['newFiles'] = {}
const dirs = utils.ReadDir(paths.userFilesDir)
dirs.forEach((dir) => {
const userDirPath = path.join(paths.userFilesDir, dir)
const dataFilePath = path.join(
userDirPath,
constants.userFilesDataFileName
)
if (!utils.FileExists(dataFilePath)) {
return
}
const dataFile =
utils.ReadJSON<Map<string, UserDirDataFile>>(dataFilePath)
Object.entries(dataFile).forEach(([fileName, data]) => {
const mtime = utils.statFile(path.join(userDirPath, fileName)).mtime
if (mtime.getTime() >= since) {
if (!newFiles[dir]) {
newFiles[dir] = {}
}
newFiles[dir][fileName] = data
}
})
})
return { success: true, newFiles: newFiles }
}
function setupFilesToGet(
newFiles: SyncDataResult['userFiles']['newFiles'],
peer: PeerInfo
): UserFileToGet[] {
const filesToGet: UserFileToGet[] = []
Object.entries(newFiles).forEach(([dirName, userFilesDir]) => {
Object.entries(userFilesDir).forEach(([fileName, data]) => {
filesToGet.push({
fileName: fileName,
dir: dirName,
filePath: path.join(paths.userFilesDir, dirName, fileName),
data: data,
peer: peer,
})
})
})
return filesToGet
}
async function downloadUserFiles(filesToGet: UserFileToGet[]) {
let addedFiles = 0
for (const fileToGet of filesToGet) {
const { peer, dir, fileName, filePath, data } = fileToGet
try {
await downloadFile(
{
host: peer.host,
port: peer.port,
path: `/api/userFiles/${dir}/${fileName}`,
},
filePath,
peer.http
)
const dataFilePath = path.join(
paths.userFilesDir,
dir,
constants.userFilesDataFileName
)
if (!utils.FileExists(dataFilePath)) {
utils.WriteFile(JSON.stringify({}), dataFilePath)
}
const dataFile = utils.ReadJSON<{
[key: string]: UserDirDataFile
}>(dataFilePath)
if (dataFile[fileName]) {
// dataFile[fileName].views += data.views // views are not unique
dataFile[fileName].upvotes = dataFile[fileName].upvotes
? dataFile[fileName].upvotes
.concat(data.upvotes)
.reduce((acc, x) => {
if (acc.includes(x)) return acc
return [...acc, x]
}, [])
: []
dataFile[fileName].downvotes = dataFile[fileName].downvotes
? dataFile[fileName].downvotes
.concat(data.downvotes)
.reduce((acc, x) => {
if (acc.includes(x)) return acc
return [...acc, x]
}, [])
: []
} else {
dataFile[fileName] = data
}
utils.WriteFile(JSON.stringify(dataFile), dataFilePath)
addedFiles += 1
} catch (e) {
logger.Log(`Unable to download "${fileName}": ${e.message}`)
console.error(e)
}
}
return addedFiles
}
// ---------------------------------------------------------------------------------------------
// Adding new
// ---------------------------------------------------------------------------------------------
export async function handleNewUserFiles(
props: NewUserFilesRequestBody & { peers: PeerInfo[] }
): Promise<{
success: boolean
addedFileCount?: number
message?: string
}> {
const result = await addNewUserFiles(props)
if (!result.success) {
logger.Log(
`Error while adding new user files: "${result.message}", from host: "${props.host}"`,
'yellowbg'
)
}
return result
}
async function addNewUserFiles({
newFiles,
host,
peers,
}: NewUserFilesRequestBody & { peers: PeerInfo[] }): Promise<{
success: boolean
addedFileCount?: number
message?: string
}> {
if (!newFiles || !host) {
return {
success: false,
message: 'newFiles or host key are missing from body',
}
}
const remotePeerInfo = peers.find((peer) => {
return peerToString(peer) === host
})
if (!remotePeerInfo) {
return {
success: false,
message: "couldn't find remote peer info based on host",
}
}
try {
const filesToGet = setupFilesToGet(newFiles, remotePeerInfo)
const addedFileCount = await downloadUserFiles(filesToGet)
logger.Log(
`\tAdded ${logger.C(
'blue'
)}${addedFileCount}${logger.C()} new files from ${logger.C(
'blue'
)}${peerToString(remotePeerInfo)}${logger.C()}`
)
return { success: true, addedFileCount: addedFileCount }
} catch (e) {
return { success: false, message: e.message }
}
}
// ---------------------------------------------------------------------------------------------
// Syncing
// ---------------------------------------------------------------------------------------------
export async function syncUserFiles(
newData: (SyncDataResult['userFiles'] & { peer: PeerInfo })[],
syncStart: number
): Promise<SyncResult> {
logger.Log('Syncing user files...')
const recievedUserFilesCount: (string | number)[][] = []
let totalRecievedd = 0
newData.forEach((res) => {
const count = Object.values(res.newFiles).reduce((acc, data) => {
totalRecievedd += Object.keys(data).length
return acc + Object.keys(data).length
}, 0)
recievedUserFilesCount.push([peerToString(res.peer), count])
})
if (totalRecievedd === 0) {
logger.Log(
`No peers returned any new files. User file sync successfully finished!`,
'green'
)
return {
old: {
userFiles: 0,
},
added: {
userFiles: 0,
},
final: {
userFiles: 0,
},
}
}
logger.logTable([['', 'Files'], ...recievedUserFilesCount], {
colWidth: [20],
rowPrefix: '\t',
})
const filesToGet: UserFileToGet[] = []
newData.forEach((res) => {
filesToGet.push(...setupFilesToGet(res.newFiles, res.peer))
})
const addedFiles = await downloadUserFiles(filesToGet)
newData.forEach((res) => {
updatePeersFile(res.peer, {
lastUserFilesSync: syncStart,
})
})
logger.Log(
`Successfully synced user files! Added ${addedFiles} files`,
'green'
)
return {
old: {
userFiles: 0,
},
added: {
userFiles: addedFiles,
},
final: {
userFiles: 0,
},
}
}