summaryrefslogtreecommitdiff
path: root/frontend/lib/drive_server.ts
blob: 8af0356fcfbe17772b8b0b96130c58bb99a34a04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import { spawnSync } from 'child_process'
import { DriveLsEntry, DriveLogEntry } from './drive_types'
import { Drive_split_path, Drive_basename } from './drive_shared'

/**
 * Server-only drive functions that use Node.js APIs
 */

/// lists the given path on the drive
export async function Drive_ls(path: string, recursive: boolean): Promise<DriveLsEntry[]> {
  const args = ['ls']
  if (recursive) {
    args.push('-r')
  }
  if (path) {
    args.push(path)
  }

  const result = spawnSync('fctdrive', args, { encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 })
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`)
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`)
  }
  const stdout = result.stdout
  const entries = []
  for (const line of stdout.split('\n')) {
    if (line.trim() == "")
      continue;

    const parts = line.split('\t');
    const path = parts[0];
    const type = parts[1];
    const lastmod = parseInt(parts[2]);
    const blobStr = parts[3];
    const sizeStr = parts[4];
    const author = parts[5];

    let blob = null;
    if (blobStr != "-")
      blob = blobStr;

    let size = null;
    if (sizeStr != "-")
      size = parseFloat(sizeStr);

    entries.push({
      path, type, lastmod, blob, size, author
    } as DriveLsEntry);
  }
  return entries;
}

/// import the file at local_path by moving it to drive_path
export async function Drive_import(local_path: string, drive_path: string, email: string) {
  const result = spawnSync('fctdrive', ['import', local_path, "--mode", "move", "--destination", drive_path, "--email", email], { encoding: 'utf-8' });
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`);
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`);
  }
}

/// returns the full filesystem path of the blob given its id
export async function Drive_blob_path(blob: string): Promise<string> {
  const result = spawnSync('fctdrive', ['blob', blob], { encoding: 'utf-8' })
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`)
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`)
  }
  return result.stdout.trim();
}

/// removes the file or directory at the given path
export async function Drive_remove(path: string, email: string) {
  const result = spawnSync('fctdrive', ['remove', '--email', email, path], { encoding: 'utf-8' });
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`);
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`);
  }
}

/// creates a directory at the given path
export async function Drive_mkdir(path: string, email: string) {
  const result = spawnSync('fctdrive', ['mkdir', '--email', email, '--path', path], { encoding: 'utf-8' });
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`);
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`);
  }
}

/// renames a file or directory from old path to new path
export async function Drive_rename(oldPath: string, newPath: string, email: string) {
  const result = spawnSync('fctdrive', ['rename', '--email', email, '--old', oldPath, '--new', newPath], { encoding: 'utf-8' });
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`);
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`);
  }
}

/// gets the blob ID for a given path
export async function Drive_stat(path: string): Promise<string> {
  const result = spawnSync('fctdrive', ['stat', path], { encoding: 'utf-8' });
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`);
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`);
  }
  return result.stdout.trim();
}


/// lists only directories (recursively) from the given path
export async function Drive_ls_directories(path: string = '/'): Promise<DriveLsEntry[]> {
  // Get all entries recursively and filter for directories
  const allEntries = await Drive_ls(path, true)
  return allEntries.filter(entry => entry.type === 'dir')
}

/// returns the log entries from the drive
export async function Drive_log(): Promise<DriveLogEntry[]> {
  const result = spawnSync('fctdrive', ['log'], { encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 })
  if (result.error) {
    throw new Error(`Failed to execute fctdrive: ${result.error.message}`)
  }
  if (result.status !== 0) {
    throw new Error(`fctdrive exited with code ${result.status}: ${result.stderr}`)
  }
  
  const stdout = result.stdout
  const entries = []
  for (const line of stdout.split('\n')) {
    if (line.trim() === "")
      continue;

    const parts = line.split('\t');
    const timestamp = parseInt(parts[0]);
    const log_id = parseInt(parts[1]);
    const email = parts[2];
    const action = parts[3];
    const path = parts[4];
    const blob_id = parts[5];
    const size = parseInt(parts[6]);

    entries.push({
      timestamp, log_id, email, action, path, blob_id, size
    } as DriveLogEntry);
  }
  return entries;
}