-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.ts
More file actions
117 lines (103 loc) · 2.99 KB
/
server.ts
File metadata and controls
117 lines (103 loc) · 2.99 KB
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
import { createServer } from "http";
import { Server, Socket } from "socket.io";
import { of, fromEvent, concat } from "rxjs";
import { map, mergeMap, switchMap, tap } from "rxjs/operators";
import * as shell from "shelljs";
import {
localFileChange$,
PairChangePayload,
PAIR_FILE_CHANGE_EVENT,
BRANCH_EVENT,
initialServerChangesStream,
} from "./common";
import * as localtunnel from "localtunnel";
import { writeFileSync } from "fs";
const silent = true;
if (!shell.which("git")) {
shell.echo("Sorry, this script requires git");
shell.exit(1);
}
const repoPath = shell.exec("git rev-parse --show-toplevel", { silent });
if (repoPath.code) {
shell.echo("Run this inside a git repo!");
shell.exit(1);
}
process.chdir(repoPath.trim());
const httpServer = createServer();
const io$ = of(
new Server(httpServer, {
// ...
})
);
const connection$ = io$.pipe(
switchMap((server) =>
fromEvent(server, "connection").pipe(
map((socket: Socket) => ({ socket, server }))
)
)
);
const fileChangeReceived$ = connection$.pipe(
mergeMap(({ socket }) =>
fromEvent(socket, PAIR_FILE_CHANGE_EVENT).pipe(
map((x: PairChangePayload) => ({ ...x, socket }))
)
)
);
const onConnectAndThenSyncThenLocalFileChange$ = connection$.pipe(
switchMap(({ server }) =>
concat(
initialServerChangesStream().pipe(
tap(({ filename }) => console.log(filename))
),
localFileChange$
).pipe(map((x) => ({ server, ...x })))
)
);
// consumes
let lastChangeReceived: string;
let lastChangeSent: string;
connection$.subscribe(({ socket }) => {
const sha = shell.exec("git rev-parse HEAD", { silent }).trim();
const branch = shell
.exec("git rev-parse --abbrev-ref HEAD", { silent })
.trim();
socket.emit(BRANCH_EVENT, branch, sha);
console.log(
`Client ${socket.id} connected and asked to track ${branch}:${sha}`
);
socket.on("disconnect", () =>
console.log(`Client ${socket.id} disconnected`)
);
});
concat(onConnectAndThenSyncThenLocalFileChange$).subscribe(
({ filename, diff: d, server, untracked }) => {
const diff = d.toString();
if (diff !== lastChangeSent && diff !== lastChangeReceived) {
console.log("emitting change", filename);
server.emit(PAIR_FILE_CHANGE_EVENT, { filename, diff, untracked });
lastChangeSent = diff;
}
}
);
fileChangeReceived$.subscribe(({ socket, filename, diff, untracked }) => {
console.log(
untracked
? "received untracked file update"
: "received tracked file update",
filename
);
lastChangeReceived = diff;
socket.broadcast.emit(PAIR_FILE_CHANGE_EVENT, { filename, diff, untracked });
if (untracked) {
writeFileSync(filename, diff);
} else {
shell.exec(`git checkout ${filename}`, { silent });
shell.ShellString(diff).exec("git apply");
}
});
// start server
localtunnel({ port: 3000 }).then((tunnel) => {
console.log("server listening on port 3000");
console.log(`clients should connect to ${tunnel.url}`);
httpServer.listen(3000);
});