Skip to content

Commit fa027f7

Browse files
committed
feat: 🎸 setup Node.js NFS v4 server implementation stub
1 parent d9ab762 commit fa027f7

File tree

6 files changed

+227
-3
lines changed

6 files changed

+227
-3
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"js-base64": "^3.7.2",
9797
"jsbi": "^4.3.0",
9898
"json-pack-napi": "^0.0.2",
99+
"memfs": "^4.49.0",
99100
"messagepack": "^1.1.12",
100101
"msgpack-lite": "^0.1.26",
101102
"msgpack5": "^6.0.2",

src/nfs/v4/server/Nfsv4Operations.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ export interface Nfsv4Operations {
4040
SAVEFH: Nfsv4OperationFn<msg.Nfsv4SavefhRequest, msg.Nfsv4SavefhResponse>;
4141
SECINFO: Nfsv4OperationFn<msg.Nfsv4SecinfoRequest, msg.Nfsv4SecinfoResponse>;
4242
SETATTR: Nfsv4OperationFn<msg.Nfsv4SetattrRequest, msg.Nfsv4SetattrResponse>;
43+
44+
/** @see {@link https://datatracker.ietf.org/doc/html/rfc7530#section-16.33} */
4345
SETCLIENTID: Nfsv4OperationFn<msg.Nfsv4SetclientidRequest, msg.Nfsv4SetclientidResponse>;
46+
4447
SETCLIENTID_CONFIRM: Nfsv4OperationFn<msg.Nfsv4SetclientidConfirmRequest, msg.Nfsv4SetclientidConfirmResponse>;
4548
VERIFY: Nfsv4OperationFn<msg.Nfsv4VerifyRequest, msg.Nfsv4VerifyResponse>;
4649
WRITE: Nfsv4OperationFn<msg.Nfsv4WriteRequest, msg.Nfsv4WriteResponse>;
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import {Nfsv4Stat} from '../constants';
2+
import {Nfsv4OperationCtx, Nfsv4Operations} from './Nfsv4Operations';
3+
import * as msg from '../messages';
4+
import * as struct from '../structs';
5+
6+
export interface Nfsv4OperationsNodeOpts {
7+
/** Node.js `fs` module. */
8+
fs: typeof import('node:fs');
9+
/** Absolute path to the root directory to serve. */
10+
dir: string;
11+
}
12+
13+
/**
14+
* NFS v4 Operations implementation for Node.js `fs` filesystem.
15+
*/
16+
export class Nfsv4OperationsNode implements Nfsv4Operations {
17+
protected fs: typeof import('node:fs');
18+
protected dir: string;
19+
20+
constructor (opts: Nfsv4OperationsNodeOpts) {
21+
this.fs = opts.fs;
22+
this.dir = opts.dir;
23+
}
24+
25+
public async ACCESS(request: msg.Nfsv4AccessRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4AccessResponse> {
26+
ctx.connection.logger.log('ACCESS', request);
27+
throw new Error('Not implemented');
28+
}
29+
public async CLOSE(request: msg.Nfsv4CloseRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4CloseResponse> {
30+
ctx.connection.logger.log('CLOSE', request);
31+
throw new Error('Not implemented');
32+
}
33+
public async COMMIT(request: msg.Nfsv4CommitRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4CommitResponse> {
34+
ctx.connection.logger.log('COMMIT', request);
35+
throw new Error('Not implemented');
36+
}
37+
public async CREATE(request: msg.Nfsv4CreateRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4CreateResponse> {
38+
ctx.connection.logger.log('CREATE', request);
39+
throw new Error('Not implemented');
40+
}
41+
public async DELEGPURGE(request: msg.Nfsv4DelegpurgeRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4DelegpurgeResponse> {
42+
ctx.connection.logger.log('DELEGPURGE', request);
43+
throw new Error('Not implemented');
44+
}
45+
public async DELEGRETURN(request: msg.Nfsv4DelegreturnRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4DelegreturnResponse> {
46+
ctx.connection.logger.log('DELEGRETURN', request);
47+
throw new Error('Not implemented');
48+
}
49+
public async GETATTR(request: msg.Nfsv4GetattrRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4GetattrResponse> {
50+
ctx.connection.logger.log('GETATTR', request);
51+
throw new Error('Not implemented');
52+
}
53+
public async GETFH(request: msg.Nfsv4GetfhRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4GetfhResponse> {
54+
ctx.connection.logger.log('GETFH', request);
55+
throw new Error('Not implemented');
56+
}
57+
public async LINK(request: msg.Nfsv4LinkRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4LinkResponse> {
58+
ctx.connection.logger.log('LINK', request);
59+
throw new Error('Not implemented');
60+
}
61+
public async LOCK(request: msg.Nfsv4LockRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4LockResponse> {
62+
ctx.connection.logger.log('LOCK', request);
63+
throw new Error('Not implemented');
64+
}
65+
public async LOCKT(request: msg.Nfsv4LocktRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4LocktResponse> {
66+
ctx.connection.logger.log('LOCKT', request);
67+
throw new Error('Not implemented');
68+
}
69+
public async LOCKU(request: msg.Nfsv4LockuRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4LockuResponse> {
70+
ctx.connection.logger.log('LOCKU', request);
71+
throw new Error('Not implemented');
72+
}
73+
public async LOOKUP(request: msg.Nfsv4LookupRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4LookupResponse> {
74+
ctx.connection.logger.log('LOOKUP', request);
75+
throw new Error('Not implemented');
76+
}
77+
public async LOOKUPP(request: msg.Nfsv4LookuppRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4LookuppResponse> {
78+
ctx.connection.logger.log('LOOKUPP', request);
79+
throw new Error('Not implemented');
80+
}
81+
public async NVERIFY(request: msg.Nfsv4NverifyRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4NverifyResponse> {
82+
ctx.connection.logger.log('NVERIFY', request);
83+
throw new Error('Not implemented');
84+
}
85+
public async OPEN(request: msg.Nfsv4OpenRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4OpenResponse> {
86+
ctx.connection.logger.log('OPEN', request);
87+
throw new Error('Not implemented');
88+
}
89+
public async OPENATTR(request: msg.Nfsv4OpenattrRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4OpenattrResponse> {
90+
ctx.connection.logger.log('OPENATTR', request);
91+
throw new Error('Not implemented');
92+
}
93+
public async OPEN_CONFIRM(request: msg.Nfsv4OpenConfirmRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4OpenConfirmResponse> {
94+
ctx.connection.logger.log('OPEN_CONFIRM', request);
95+
throw new Error('Not implemented');
96+
}
97+
public async OPEN_DOWNGRADE(request: msg.Nfsv4OpenDowngradeRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4OpenDowngradeResponse> {
98+
ctx.connection.logger.log('OPEN_DOWNGRADE', request);
99+
throw new Error('Not implemented');
100+
}
101+
public async PUTFH(request: msg.Nfsv4PutfhRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4PutfhResponse> {
102+
ctx.connection.logger.log('PUTFH', request);
103+
throw new Error('Not implemented');
104+
}
105+
public async PUTPUBFH(request: msg.Nfsv4PutpubfhRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4PutpubfhResponse> {
106+
ctx.connection.logger.log('PUTPUBFH', request);
107+
throw new Error('Not implemented');
108+
}
109+
public async PUTROOTFH(request: msg.Nfsv4PutrootfhRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4PutrootfhResponse> {
110+
ctx.connection.logger.log('PUTROOTFH', request);
111+
throw new Error('Not implemented');
112+
}
113+
public async READ(request: msg.Nfsv4ReadRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4ReadResponse> {
114+
ctx.connection.logger.log('READ', request);
115+
throw new Error('Not implemented');
116+
}
117+
public async READDIR(request: msg.Nfsv4ReaddirRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4ReaddirResponse> {
118+
ctx.connection.logger.log('READDIR', request);
119+
throw new Error('Not implemented');
120+
}
121+
public async READLINK(request: msg.Nfsv4ReadlinkRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4ReadlinkResponse> {
122+
ctx.connection.logger.log('READLINK', request);
123+
throw new Error('Not implemented');
124+
}
125+
public async REMOVE(request: msg.Nfsv4RemoveRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4RemoveResponse> {
126+
ctx.connection.logger.log('REMOVE', request);
127+
throw new Error('Not implemented');
128+
}
129+
public async RENAME(request: msg.Nfsv4RenameRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4RenameResponse> {
130+
ctx.connection.logger.log('RENAME', request);
131+
throw new Error('Not implemented');
132+
}
133+
public async RENEW(request: msg.Nfsv4RenewRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4RenewResponse> {
134+
ctx.connection.logger.log('RENEW', request);
135+
throw new Error('Not implemented');
136+
}
137+
public async RESTOREFH(request: msg.Nfsv4RestorefhRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4RestorefhResponse> {
138+
ctx.connection.logger.log('RESTOREFH', request);
139+
throw new Error('Not implemented');
140+
}
141+
public async SAVEFH(request: msg.Nfsv4SavefhRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4SavefhResponse> {
142+
ctx.connection.logger.log('SAVEFH', request);
143+
throw new Error('Not implemented');
144+
}
145+
public async SECINFO(request: msg.Nfsv4SecinfoRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4SecinfoResponse> {
146+
ctx.connection.logger.log('SECINFO', request);
147+
throw new Error('Not implemented');
148+
}
149+
public async SETATTR(request: msg.Nfsv4SetattrRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4SetattrResponse> {
150+
ctx.connection.logger.log('SETATTR', request);
151+
throw new Error('Not implemented');
152+
}
153+
public async SETCLIENTID(request: msg.Nfsv4SetclientidRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4SetclientidResponse> {
154+
const verifier = new struct.Nfsv4Verifier(new Uint8Array([1,2,3,4]));
155+
const body = new msg.Nfsv4SetclientidResOk(123n, verifier);
156+
const response = new msg.Nfsv4SetclientidResponse(Nfsv4Stat.NFS4_OK, body);
157+
return response;
158+
}
159+
public async SETCLIENTID_CONFIRM(request: msg.Nfsv4SetclientidConfirmRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4SetclientidConfirmResponse> {
160+
ctx.connection.logger.log('SETCLIENTID_CONFIRM', request);
161+
throw new Error('Not implemented');
162+
}
163+
public async VERIFY(request: msg.Nfsv4VerifyRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4VerifyResponse> {
164+
ctx.connection.logger.log('VERIFY', request);
165+
throw new Error('Not implemented');
166+
}
167+
public async WRITE(request: msg.Nfsv4WriteRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4WriteResponse> {
168+
ctx.connection.logger.log('WRITE', request);
169+
throw new Error('Not implemented');
170+
}
171+
public async RELEASE_LOCKOWNER(request: msg.Nfsv4ReleaseLockOwnerRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4ReleaseLockOwnerResponse> {
172+
ctx.connection.logger.log('RELEASE_LOCKOWNER', request);
173+
throw new Error('Not implemented');
174+
}
175+
public async ILLEGAL(request: msg.Nfsv4IllegalRequest, ctx: Nfsv4OperationCtx): Promise<msg.Nfsv4IllegalResponse> {
176+
ctx.connection.logger.log('ILLEGAL', request);
177+
throw new Error('Not implemented');
178+
}
179+
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import {Nfsv4OperationsNotImpl} from '../Nfsv4OperationsNotImpl';
1+
import {Nfsv4OperationsNode} from '../Nfsv4OperationsNode';
22
import {Nfsv4TcpServer} from '../Nfsv4TcpServer';
3+
import {fs} from 'memfs';
34

4-
const ops = new Nfsv4OperationsNotImpl();
5+
const ops = new Nfsv4OperationsNode({fs: <any>fs, dir: '/'});
56
Nfsv4TcpServer.start({ops, debug: true});

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"target": "es6",
3+
"target": "es2020",
44
"module": "commonjs",
55
"moduleResolution": "Node",
66
"removeComments": true,

yarn.lock

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,19 @@
615615
resolved "https://registry.yarnpkg.com/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz#5c23f796c47675f166d23b948cdb889184b93207"
616616
integrity sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==
617617

618+
"@jsonjoy.com/json-pack@^1.11.0":
619+
version "1.20.0"
620+
resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pack/-/json-pack-1.20.0.tgz#c59cbac0f3fcab0fa9fd5a36cd2b15d020b0bc0a"
621+
integrity sha512-adcXFVorSQULtT4XDL0giRLr2EVGIcyWm6eQKZWTrRA4EEydGOY8QVQtL0PaITQpUyu+lOd/QOicw6vdy1v8QQ==
622+
dependencies:
623+
"@jsonjoy.com/base64" "^1.1.2"
624+
"@jsonjoy.com/buffers" "^1.2.0"
625+
"@jsonjoy.com/codegen" "^1.0.0"
626+
"@jsonjoy.com/json-pointer" "^1.0.2"
627+
"@jsonjoy.com/util" "^1.9.0"
628+
hyperdyperid "^1.2.0"
629+
thingies "^2.5.0"
630+
618631
"@jsonjoy.com/json-pointer@^1.0.2":
619632
version "1.0.2"
620633
resolved "https://registry.yarnpkg.com/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz#049cb530ac24e84cba08590c5e36b431c4843408"
@@ -1692,6 +1705,11 @@ gh-pages@^5.0.0:
16921705
fs-extra "^8.1.0"
16931706
globby "^6.1.0"
16941707

1708+
glob-to-regex.js@^1.0.1:
1709+
version "1.2.0"
1710+
resolved "https://registry.yarnpkg.com/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz#2b323728271d133830850e32311f40766c5f6413"
1711+
integrity sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==
1712+
16951713
glob@^10.3.7:
16961714
version "10.3.12"
16971715
resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz"
@@ -2431,6 +2449,18 @@ marked@^4.3.0:
24312449
resolved "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz"
24322450
integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==
24332451

2452+
memfs@^4.49.0:
2453+
version "4.49.0"
2454+
resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.49.0.tgz#bc35069570d41a31c62e31f1a6ec6057a8ea82f0"
2455+
integrity sha512-L9uC9vGuc4xFybbdOpRLoOAOq1YEBBsocCs5NVW32DfU+CZWWIn3OVF+lB8Gp4ttBVSMazwrTrjv8ussX/e3VQ==
2456+
dependencies:
2457+
"@jsonjoy.com/json-pack" "^1.11.0"
2458+
"@jsonjoy.com/util" "^1.9.0"
2459+
glob-to-regex.js "^1.0.1"
2460+
thingies "^2.5.0"
2461+
tree-dump "^1.0.3"
2462+
tslib "^2.0.0"
2463+
24342464
merge-stream@^2.0.0:
24352465
version "2.0.0"
24362466
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
@@ -3122,6 +3152,11 @@ to-regex-range@^5.0.1:
31223152
dependencies:
31233153
is-number "^7.0.0"
31243154

3155+
tree-dump@^1.0.3:
3156+
version "1.1.0"
3157+
resolved "https://registry.yarnpkg.com/tree-dump/-/tree-dump-1.1.0.tgz#ab29129169dc46004414f5a9d4a3c6e89f13e8a4"
3158+
integrity sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==
3159+
31253160
trim-repeated@^1.0.0:
31263161
version "1.0.0"
31273162
resolved "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz"
@@ -3178,6 +3213,11 @@ tslib@^1.13.0, tslib@^1.8.1:
31783213
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
31793214
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
31803215

3216+
tslib@^2.0.0:
3217+
version "2.8.1"
3218+
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
3219+
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
3220+
31813221
tslib@^2.6.2:
31823222
version "2.6.2"
31833223
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"

0 commit comments

Comments
 (0)