listing of files on connect

This commit is contained in:
William Harrell 2022-11-02 22:20:32 -04:00
parent 1505abb703
commit 70e84c5840
12 changed files with 160 additions and 26 deletions

View File

@ -8,7 +8,8 @@
<div v-for="item in files" :key="item.name" class="files-list-item"> <div v-for="item in files" :key="item.name" class="files-list-item">
<i :class="fileIcon(item)" /> <i :class="fileIcon(item)" />
<p>{{ item.name }}</p> <p>{{ item.name }}</p>
<i class="fas fa-download download" @click="() => download(item)" /> <i v-if="item.type !== 'dir'" class="fas fa-download download"
@click="() => download(item)" />
</div> </div>
</div> </div>
<div class="files-transfer" @dragover.prevent @drop.prevent="onFileDrop"> <div class="files-transfer" @dragover.prevent @drop.prevent="onFileDrop">
@ -111,7 +112,6 @@
<script lang="ts"> <script lang="ts">
import { Component, Vue } from 'vue-property-decorator' import { Component, Vue } from 'vue-property-decorator'
import { onMounted, onUnmounted } from 'vue'
import Markdown from './markdown' import Markdown from './markdown'
import Content from './context.vue' import Content from './context.vue'
@ -125,28 +125,12 @@
}) })
export default class extends Vue { export default class extends Vue {
data() { get cwd() {
return { return this.$accessor.files.cwd
cwd: '~/Downloads', }
files: [
{ get files() {
name: 'a.txt', return this.$accessor.files.files
type: 'file'
},
{
name: 'b',
type: 'dir'
},
{
name: 'c.mkv',
type: 'file'
},
{
name: 'd.mp3',
type: 'file'
}
]
}
} }
refresh() { refresh() {

View File

@ -38,6 +38,13 @@ export const EVENT = {
MESSAGE: 'chat/message', MESSAGE: 'chat/message',
EMOTE: 'chat/emote', EMOTE: 'chat/emote',
}, },
FILETRANSFER: {
ENABLE: 'filetransfer/enable',
DISABLE: 'filetransfer/disable',
UNPRIVENABLE: 'filetransfer/unprivenable',
UNPRIVDISABLE: 'filetransfer/unprivdisable',
LIST: 'filetransfer/list'
},
SCREEN: { SCREEN: {
CONFIGURATIONS: 'screen/configurations', CONFIGURATIONS: 'screen/configurations',
RESOLUTION: 'screen/resolution', RESOLUTION: 'screen/resolution',
@ -69,6 +76,7 @@ export type WebSocketEvents =
| MemberEvents | MemberEvents
| SignalEvents | SignalEvents
| ChatEvents | ChatEvents
| FileTransferEvents
| ScreenEvents | ScreenEvents
| BroadcastEvents | BroadcastEvents
| AdminEvents | AdminEvents
@ -91,6 +99,14 @@ export type SignalEvents =
| typeof EVENT.SIGNAL.CANDIDATE | typeof EVENT.SIGNAL.CANDIDATE
export type ChatEvents = typeof EVENT.CHAT.MESSAGE | typeof EVENT.CHAT.EMOTE export type ChatEvents = typeof EVENT.CHAT.MESSAGE | typeof EVENT.CHAT.EMOTE
export type FileTransferEvents =
| typeof EVENT.FILETRANSFER.ENABLE
| typeof EVENT.FILETRANSFER.DISABLE
| typeof EVENT.FILETRANSFER.UNPRIVENABLE
| typeof EVENT.FILETRANSFER.UNPRIVDISABLE
| typeof EVENT.FILETRANSFER.LIST
export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET
export type BroadcastEvents = export type BroadcastEvents =

View File

@ -24,6 +24,7 @@ import {
AdminLockMessage, AdminLockMessage,
SystemInitPayload, SystemInitPayload,
AdminLockResource, AdminLockResource,
FileTransferListPayload,
} from './messages' } from './messages'
interface NekoEvents extends BaseEvents {} interface NekoEvents extends BaseEvents {}
@ -351,6 +352,14 @@ export class NekoClient extends BaseClient implements EventEmitter<NekoEvents> {
this.$accessor.chat.newEmote({ type: emote }) this.$accessor.chat.newEmote({ type: emote })
} }
/////////////////////////////
// Chat Events
/////////////////////////////
protected [EVENT.FILETRANSFER.LIST]({ cwd, files }: FileTransferListPayload) {
this.$accessor.files.setCwd(cwd)
this.$accessor.files.setFileList(files)
}
///////////////////////////// /////////////////////////////
// Screen Events // Screen Events
///////////////////////////// /////////////////////////////

View File

@ -8,8 +8,14 @@ import {
ChatEvents, ChatEvents,
ScreenEvents, ScreenEvents,
AdminEvents, AdminEvents,
FileTransferEvents,
} from './events' } from './events'
import { Member, ScreenConfigurations, ScreenResolution } from './types' import {
FileListItem,
Member,
ScreenConfigurations,
ScreenResolution
} from './types'
export type WebSocketMessages = export type WebSocketMessages =
| WebSocketMessage | WebSocketMessage
@ -192,6 +198,15 @@ export interface EmojiSendPayload {
emote: string emote: string
} }
// file transfer
export interface FileTransferMessage extends WebSocketMessage, FileTransferListPayload {
event: FileTransferEvents
}
export interface FileTransferListPayload {
cwd: string,
files: FileListItem[]
}
/* /*
SCREEN PAYLOADS SCREEN PAYLOADS
*/ */

View File

@ -22,3 +22,8 @@ export interface ScreenResolution {
height: number height: number
rate: number rate: number
} }
export interface FileListItem {
name: string,
type: 'file' | 'dir'
}

35
client/src/store/files.ts Normal file
View File

@ -0,0 +1,35 @@
import { actionTree, getterTree, mutationTree } from 'typed-vuex'
import { FileListItem } from '~/neko/types'
import { accessor } from '~/store'
export const state = () => ({
cwd: '',
files: [] as FileListItem[]
})
export const getters = getterTree(state, {
//
})
export const mutations = mutationTree(state, {
_setCwd(state, cwd: string) {
state.cwd = cwd
},
_setFileList(state, files: FileListItem[]) {
state.files = files
}
})
export const actions = actionTree(
{ state, getters, mutations },
{
setCwd(store, cwd: string) {
accessor.files._setCwd(cwd)
},
setFileList(store, files: FileListItem[]) {
accessor.files._setFileList(files)
}
}
)

View File

@ -7,6 +7,7 @@ import { get, set } from '~/utils/localstorage'
import * as video from './video' import * as video from './video'
import * as chat from './chat' import * as chat from './chat'
import * as files from './files'
import * as remote from './remote' import * as remote from './remote'
import * as user from './user' import * as user from './user'
import * as settings from './settings' import * as settings from './settings'
@ -97,7 +98,7 @@ export const storePattern = {
state, state,
mutations, mutations,
actions, actions,
modules: { video, chat, user, remote, settings, client, emoji }, modules: { video, chat, files, user, remote, settings, client, emoji },
} }
Vue.use(Vuex) Vue.use(Vuex)

View File

@ -34,6 +34,14 @@ const (
CHAT_EMOTE = "chat/emote" CHAT_EMOTE = "chat/emote"
) )
const (
FILETRANSFER_ENABLE = "filetransfer/enable"
FILETRANSFER_DISABLE = "filetransfer/disable"
FILETRANSFER_UNPRIVENABLE = "filetransfer/unprivenable"
FILETRANSFER_UNPRIVDISABLE = "filetransfer/unprivdisable"
FILETRANSFER_LIST = "filetransfer/list"
)
const ( const (
SCREEN_CONFIGURATIONS = "screen/configurations" SCREEN_CONFIGURATIONS = "screen/configurations"
SCREEN_RESOLUTION = "screen/resolution" SCREEN_RESOLUTION = "screen/resolution"

View File

@ -106,6 +106,17 @@ type EmoteSend struct {
Emote string `json:"emote"` Emote string `json:"emote"`
} }
type FileTransferTarget struct {
Event string `json:"event"`
ID string `json:"id"`
}
type FileList struct {
Event string `json:"event"`
Cwd string `json:"cwd"`
Files []types.FileListItem `json:"files"`
}
type Admin struct { type Admin struct {
Event string `json:"event"` Event string `json:"event"`
ID string `json:"id"` ID string `json:"id"`

View File

@ -37,3 +37,8 @@ type WebSocketHandler interface {
CanTransferFiles(password string) (bool, error) CanTransferFiles(password string) (bool, error)
MakeFilePath(filename string) string MakeFilePath(filename string) string
} }
type FileListItem struct {
Filename string `json:"name"`
Type string `json:"type"`
}

View File

@ -0,0 +1,30 @@
package utils
import (
"os"
"m1k1o/neko/internal/types"
)
func ListFiles(path string) (*[]types.FileListItem, error) {
items, err := os.ReadDir(path)
if err != nil {
return nil, err
}
out := make([]types.FileListItem, len(items))
for i, item := range items {
var itemType string = ""
if item.IsDir() {
itemType = "dir"
} else {
itemType = "file"
}
out[i] = types.FileListItem{
Filename: item.Name(),
Type: itemType,
}
}
return &out, nil
}

View File

@ -133,6 +133,21 @@ func (ws *WebSocketHandler) Start() {
} }
} }
// send file list if necessary
if session.Admin() && ws.conf.FileTransfer || ws.conf.FileTransfer && ws.conf.UnprivFileTransfer {
files, err := utils.ListFiles(ws.conf.FileTransferPath)
if err == nil {
if err := session.Send(
message.FileList{
Event: event.FILETRANSFER_LIST,
Cwd: ws.conf.FileTransferPath,
Files: *files,
}); err != nil {
ws.logger.Warn().Err(err).Msg("file list event has failed")
}
}
}
// remove outdated stats // remove outdated stats
if session.Admin() { if session.Admin() {
ws.lastAdminLeftAt = nil ws.lastAdminLeftAt = nil