showterm 0.1.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/ext/ttyrec.c ADDED
@@ -0,0 +1,483 @@
1
+ /*
2
+ * Copyright (c) 1980 Regents of the University of California.
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions
7
+ * are met:
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * 3. All advertising materials mentioning features or use of this software
14
+ * must display the following acknowledgement:
15
+ * This product includes software developed by the University of
16
+ * California, Berkeley and its contributors.
17
+ * 4. Neither the name of the University nor the names of its contributors
18
+ * may be used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
+ * SUCH DAMAGE.
32
+ */
33
+
34
+ /* 1999-02-22 Arkadiusz Mi�kiewicz <misiek@misiek.eu.org>
35
+ * - added Native Language Support
36
+ */
37
+
38
+ /* 2000-12-27 Satoru Takabayashi <satoru@namazu.org>
39
+ * - modify `script' to create `ttyrec'.
40
+ */
41
+
42
+ /*
43
+ * script
44
+ */
45
+ #include <sys/types.h>
46
+ #include <sys/stat.h>
47
+ #include <termios.h>
48
+ #include <sys/ioctl.h>
49
+ #include <sys/time.h>
50
+ #include <sys/file.h>
51
+ #include <sys/signal.h>
52
+ #include <stdio.h>
53
+ #include <time.h>
54
+ #include <unistd.h>
55
+ #include <string.h>
56
+ #include <stdlib.h>
57
+
58
+ #if defined(SVR4)
59
+ #include <fcntl.h>
60
+ #include <stropts.h>
61
+ #endif /* SVR4 */
62
+
63
+ #include <sys/time.h>
64
+ #include "ttyrec.h"
65
+ #include "io.h"
66
+
67
+ #define HAVE_inet_aton
68
+ #define HAVE_scsi_h
69
+ #define HAVE_kd_h
70
+
71
+ #define _(FOO) FOO
72
+
73
+ #ifdef HAVE_openpty
74
+ #include <libutil.h>
75
+ #endif
76
+
77
+ #if defined(SVR4) && !defined(CDEL)
78
+ #if defined(_POSIX_VDISABLE)
79
+ #define CDEL _POSIX_VDISABLE
80
+ #elif defined(CDISABLE)
81
+ #define CDEL CDISABLE
82
+ #else /* not _POSIX_VISIBLE && not CDISABLE */
83
+ #define CDEL 255
84
+ #endif /* not _POSIX_VISIBLE && not CDISABLE */
85
+ #endif /* SVR4 && ! CDEL */
86
+
87
+ void done(void);
88
+ void fail(void);
89
+ void fixtty(void);
90
+ void getmaster(void);
91
+ void getslave(void);
92
+ void doinput(void);
93
+ void dooutput(void);
94
+ void doshell(const char*);
95
+
96
+ char *shell;
97
+ FILE *fscript;
98
+ int master;
99
+ int slave;
100
+ int child;
101
+ int subchild;
102
+ char *fname;
103
+
104
+ struct termios tt;
105
+ struct winsize win;
106
+ int lb;
107
+ int l;
108
+ #if !defined(SVR4)
109
+ #ifndef HAVE_openpty
110
+ char line[] = "/dev/ptyXX";
111
+ #endif
112
+ #endif /* !SVR4 */
113
+ int aflg;
114
+ int uflg;
115
+
116
+ int
117
+ main(argc, argv)
118
+ int argc;
119
+ char *argv[];
120
+ {
121
+ extern int optind;
122
+ int ch;
123
+ void finish();
124
+ char *getenv();
125
+ char *command = NULL;
126
+
127
+ while ((ch = getopt(argc, argv, "aue:h?")) != EOF)
128
+ switch((char)ch) {
129
+ case 'a':
130
+ aflg++;
131
+ break;
132
+ case 'u':
133
+ uflg++;
134
+ break;
135
+ case 'e':
136
+ command = strdup(optarg);
137
+ break;
138
+ case 'h':
139
+ case '?':
140
+ default:
141
+ fprintf(stderr, _("usage: ttyrec [-u] [-e command] [-a] [file]\n"));
142
+ exit(1);
143
+ }
144
+ argc -= optind;
145
+ argv += optind;
146
+
147
+ if (argc > 0)
148
+ fname = argv[0];
149
+ else
150
+ fname = "ttyrecord";
151
+ if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
152
+ perror(fname);
153
+ fail();
154
+ }
155
+ setbuf(fscript, NULL);
156
+
157
+ shell = getenv("SHELL");
158
+ if (shell == NULL)
159
+ shell = "/bin/sh";
160
+
161
+ getmaster();
162
+ fixtty();
163
+
164
+ (void) signal(SIGCHLD, finish);
165
+ child = fork();
166
+ if (child < 0) {
167
+ perror("fork");
168
+ fail();
169
+ }
170
+ if (child == 0) {
171
+ subchild = child = fork();
172
+ if (child < 0) {
173
+ perror("fork");
174
+ fail();
175
+ }
176
+ if (child)
177
+ dooutput();
178
+ else
179
+ doshell(command);
180
+ }
181
+ doinput();
182
+
183
+ return 0;
184
+ }
185
+
186
+ void
187
+ doinput()
188
+ {
189
+ register int cc;
190
+ char ibuf[BUFSIZ];
191
+
192
+ (void) fclose(fscript);
193
+ #ifdef HAVE_openpty
194
+ (void) close(slave);
195
+ #endif
196
+ while ((cc = read(0, ibuf, BUFSIZ)) > 0)
197
+ (void) write(master, ibuf, cc);
198
+ done();
199
+ }
200
+
201
+ #include <sys/wait.h>
202
+
203
+ void
204
+ finish()
205
+ {
206
+ #if defined(SVR4)
207
+ int status;
208
+ #else /* !SVR4 */
209
+ union wait status;
210
+ #endif /* !SVR4 */
211
+ register int pid;
212
+ register int die = 0;
213
+
214
+ while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
215
+ if (pid == child)
216
+ die = 1;
217
+
218
+ if (die)
219
+ done();
220
+ }
221
+
222
+ struct linebuf {
223
+ char str[BUFSIZ + 1]; /* + 1 for an additional NULL character.*/
224
+ int len;
225
+ };
226
+
227
+
228
+ void
229
+ check_line (const char *line)
230
+ {
231
+ static int uuencode_mode = 0;
232
+ static FILE *uudecode;
233
+
234
+ if (uuencode_mode == 1) {
235
+ fprintf(uudecode, "%s", line);
236
+ if (strcmp(line, "end\n") == 0) {
237
+ pclose(uudecode);
238
+ uuencode_mode = 0;
239
+ }
240
+ } else {
241
+ int dummy; char dummy2[BUFSIZ];
242
+ if (sscanf(line, "begin %o %s", &dummy, dummy2) == 2) {
243
+ /*
244
+ * uuencode line found!
245
+ */
246
+ uudecode = popen("uudecode", "w");
247
+ fprintf(uudecode, "%s", line);
248
+ uuencode_mode = 1;
249
+ }
250
+ }
251
+ }
252
+
253
+ void
254
+ check_output(const char *str, int len)
255
+ {
256
+ static struct linebuf lbuf = {"", 0};
257
+ int i;
258
+
259
+ for (i = 0; i < len; i++) {
260
+ if (lbuf.len < BUFSIZ) {
261
+ lbuf.str[lbuf.len] = str[i];
262
+ if (lbuf.str[lbuf.len] == '\r') {
263
+ lbuf.str[lbuf.len] = '\n';
264
+ }
265
+ lbuf.len++;
266
+ if (lbuf.str[lbuf.len - 1] == '\n') {
267
+ if (lbuf.len > 1) { /* skip a blank line. */
268
+ lbuf.str[lbuf.len] = '\0';
269
+ check_line(lbuf.str);
270
+ }
271
+ lbuf.len = 0;
272
+ }
273
+ } else {/* buffer overflow */
274
+ lbuf.len = 0;
275
+ }
276
+ }
277
+ }
278
+
279
+ void
280
+ dooutput()
281
+ {
282
+ int cc;
283
+ char obuf[BUFSIZ];
284
+
285
+ setbuf(stdout, NULL);
286
+ (void) close(0);
287
+ #ifdef HAVE_openpty
288
+ (void) close(slave);
289
+ #endif
290
+ for (;;) {
291
+ Header h;
292
+
293
+ cc = read(master, obuf, BUFSIZ);
294
+ if (cc <= 0)
295
+ break;
296
+ if (uflg)
297
+ check_output(obuf, cc);
298
+ h.len = cc;
299
+ gettimeofday(&h.tv, NULL);
300
+ (void) write(1, obuf, cc);
301
+ (void) write_header(fscript, &h);
302
+ (void) fwrite(obuf, 1, cc, fscript);
303
+ }
304
+ done();
305
+ }
306
+
307
+ void
308
+ doshell(const char* command)
309
+ {
310
+ /***
311
+ int t;
312
+
313
+ t = open(_PATH_TTY, O_RDWR);
314
+ if (t >= 0) {
315
+ (void) ioctl(t, TIOCNOTTY, (char *)0);
316
+ (void) close(t);
317
+ }
318
+ ***/
319
+ getslave();
320
+ (void) close(master);
321
+ (void) fclose(fscript);
322
+ (void) dup2(slave, 0);
323
+ (void) dup2(slave, 1);
324
+ (void) dup2(slave, 2);
325
+ (void) close(slave);
326
+
327
+ if (!command) {
328
+ execl(shell, strrchr(shell, '/') + 1, "-i", 0);
329
+ } else {
330
+ execl(shell, strrchr(shell, '/') + 1, "-c", command, 0);
331
+ }
332
+ perror(shell);
333
+ fail();
334
+ }
335
+
336
+ void
337
+ fixtty()
338
+ {
339
+ struct termios rtt;
340
+
341
+ rtt = tt;
342
+ #if defined(SVR4)
343
+ rtt.c_iflag = 0;
344
+ rtt.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|ECHOE|ECHOK|ECHONL);
345
+ rtt.c_oflag = OPOST;
346
+ rtt.c_cc[VINTR] = CDEL;
347
+ rtt.c_cc[VQUIT] = CDEL;
348
+ rtt.c_cc[VERASE] = CDEL;
349
+ rtt.c_cc[VKILL] = CDEL;
350
+ rtt.c_cc[VEOF] = 1;
351
+ rtt.c_cc[VEOL] = 0;
352
+ #else /* !SVR4 */
353
+ cfmakeraw(&rtt);
354
+ rtt.c_lflag &= ~ECHO;
355
+ #endif /* !SVR4 */
356
+ (void) tcsetattr(0, TCSAFLUSH, &rtt);
357
+ }
358
+
359
+ void
360
+ fail()
361
+ {
362
+
363
+ (void) kill(0, SIGTERM);
364
+ done();
365
+ }
366
+
367
+ void
368
+ done()
369
+ {
370
+ if (subchild) {
371
+ (void) fclose(fscript);
372
+ (void) close(master);
373
+ } else {
374
+ (void) tcsetattr(0, TCSAFLUSH, &tt);
375
+ }
376
+ exit(0);
377
+ }
378
+
379
+ void
380
+ getmaster()
381
+ {
382
+ #if defined(SVR4)
383
+ (void) tcgetattr(0, &tt);
384
+ (void) ioctl(0, TIOCGWINSZ, (char *)&win);
385
+ if ((master = open("/dev/ptmx", O_RDWR)) < 0) {
386
+ perror("open(\"/dev/ptmx\", O_RDWR)");
387
+ fail();
388
+ }
389
+ #else /* !SVR4 */
390
+ #ifdef HAVE_openpty
391
+ (void) tcgetattr(0, &tt);
392
+ (void) ioctl(0, TIOCGWINSZ, (char *)&win);
393
+ if (openpty(&master, &slave, NULL, &tt, &win) < 0) {
394
+ fprintf(stderr, _("openpty failed\n"));
395
+ fail();
396
+ }
397
+ #else
398
+ #ifdef HAVE_getpt
399
+ if ((master = getpt()) < 0) {
400
+ perror("getpt()");
401
+ fail();
402
+ }
403
+ #else
404
+ char *pty, *bank, *cp;
405
+ struct stat stb;
406
+
407
+ pty = &line[strlen("/dev/ptyp")];
408
+ for (bank = "pqrs"; *bank; bank++) {
409
+ line[strlen("/dev/pty")] = *bank;
410
+ *pty = '0';
411
+ if (stat(line, &stb) < 0)
412
+ break;
413
+ for (cp = "0123456789abcdef"; *cp; cp++) {
414
+ *pty = *cp;
415
+ master = open(line, O_RDWR);
416
+ if (master >= 0) {
417
+ char *tp = &line[strlen("/dev/")];
418
+ int ok;
419
+
420
+ /* verify slave side is usable */
421
+ *tp = 't';
422
+ ok = access(line, R_OK|W_OK) == 0;
423
+ *tp = 'p';
424
+ if (ok) {
425
+ (void) tcgetattr(0, &tt);
426
+ (void) ioctl(0, TIOCGWINSZ,
427
+ (char *)&win);
428
+ return;
429
+ }
430
+ (void) close(master);
431
+ }
432
+ }
433
+ }
434
+ fprintf(stderr, _("Out of pty's\n"));
435
+ fail();
436
+ #endif /* not HAVE_getpt */
437
+ #endif /* not HAVE_openpty */
438
+ #endif /* !SVR4 */
439
+ }
440
+
441
+ void
442
+ getslave()
443
+ {
444
+ #if defined(SVR4)
445
+ (void) setsid();
446
+ grantpt( master);
447
+ unlockpt(master);
448
+ if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
449
+ perror("open(fd, O_RDWR)");
450
+ fail();
451
+ }
452
+ if (isastream(slave)) {
453
+ if (ioctl(slave, I_PUSH, "ptem") < 0) {
454
+ perror("ioctl(fd, I_PUSH, ptem)");
455
+ fail();
456
+ }
457
+ if (ioctl(slave, I_PUSH, "ldterm") < 0) {
458
+ perror("ioctl(fd, I_PUSH, ldterm)");
459
+ fail();
460
+ }
461
+ #ifndef _HPUX_SOURCE
462
+ if (ioctl(slave, I_PUSH, "ttcompat") < 0) {
463
+ perror("ioctl(fd, I_PUSH, ttcompat)");
464
+ fail();
465
+ }
466
+ #endif
467
+ (void) ioctl(0, TIOCGWINSZ, (char *)&win);
468
+ }
469
+ #else /* !SVR4 */
470
+ #ifndef HAVE_openpty
471
+ line[strlen("/dev/")] = 't';
472
+ slave = open(line, O_RDWR);
473
+ if (slave < 0) {
474
+ perror(line);
475
+ fail();
476
+ }
477
+ (void) tcsetattr(slave, TCSAFLUSH, &tt);
478
+ (void) ioctl(slave, TIOCSWINSZ, (char *)&win);
479
+ #endif
480
+ (void) setsid();
481
+ (void) ioctl(slave, TIOCSCTTY, 0);
482
+ #endif /* SVR4 */
483
+ }
data/ext/ttyrec.h ADDED
@@ -0,0 +1,12 @@
1
+ #ifndef __TTYREC_H__
2
+ #define __TTYREC_H__
3
+
4
+ #include "sys/time.h"
5
+
6
+ typedef struct header {
7
+ struct timeval tv;
8
+ int len;
9
+ } Header;
10
+
11
+
12
+ #endif
data/ext/ttytime.1 ADDED
@@ -0,0 +1,27 @@
1
+ .\"
2
+ .\" This manual page is written by NAKANO Takeo <nakano@webmasters.gr.jp>
3
+ .\"
4
+ .TH TTYTIME 1
5
+ .SH NAME
6
+ ttytime \- print the time of the recorded session data by ttyrec(1)
7
+ .SH SYNOPSIS
8
+ .br
9
+ .B ttytime
10
+ .I file...
11
+ .SH DESCRIPTION
12
+ .B Ttytime
13
+ tells you the time of recorded data in seconds.
14
+ For example:
15
+ .sp
16
+ .RS
17
+ .nf
18
+ % ttytime *.tty
19
+ 173 foo.tty
20
+ 1832 bar.tty
21
+ .fi
22
+ .RE
23
+ .SH "SEE ALSO"
24
+ .BR script (1),
25
+ .BR ttyrec (1),
26
+ .BR ttyplay (1)
27
+
data/ext/ttytime.c ADDED
@@ -0,0 +1,70 @@
1
+ /*
2
+ * Copyright (c) 1980 Regents of the University of California.
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions
7
+ * are met:
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * 3. All advertising materials mentioning features or use of this software
14
+ * must display the following acknowledgement:
15
+ * This product includes software developed by the University of
16
+ * California, Berkeley and its contributors.
17
+ * 4. Neither the name of the University nor the names of its contributors
18
+ * may be used to endorse or promote products derived from this software
19
+ * without specific prior written permission.
20
+ *
21
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
+ * SUCH DAMAGE.
32
+ */
33
+
34
+ #include <stdio.h>
35
+ #include <stdlib.h>
36
+ #include <assert.h>
37
+
38
+ #include "io.h"
39
+ #include "ttyrec.h"
40
+
41
+ int
42
+ calc_time (const char *filename)
43
+ {
44
+ Header start, end;
45
+ FILE *fp = efopen(filename, "r");
46
+
47
+ read_header(fp, &start);
48
+ fseek(fp, start.len, SEEK_CUR);
49
+ while (1) {
50
+ Header h;
51
+ if (read_header(fp, &h) == 0) {
52
+ break;
53
+ }
54
+ end = h;
55
+ fseek(fp, h.len, SEEK_CUR);
56
+ }
57
+ return end.tv.tv_sec - start.tv.tv_sec;
58
+ }
59
+
60
+ int
61
+ main (int argc, char **argv)
62
+ {
63
+ int i;
64
+ set_progname(argv[0]);
65
+ for (i = 1; i < argc; i++) {
66
+ char *filename = argv[i];
67
+ printf("%7d %s\n", calc_time(filename), filename);
68
+ }
69
+ return 0;
70
+ }
data/lib/showterm.rb CHANGED
@@ -1,54 +1,100 @@
1
- require 'json'
2
1
  require 'tempfile'
3
2
  require 'net/https'
4
3
 
5
4
  module Showterm
6
5
  extend self
7
6
 
7
+ # Record a terminal session.
8
+ #
9
+ # If a command is given, use that command; otherwise the current user's
10
+ # login shell will be used.
11
+ #
12
+ # @param [*String] cmd
13
+ # @return [scriptfile, timingfile] the two halves of a termshow
8
14
  def record!(*cmd)
9
-
10
15
  scriptfile = Tempfile.new('showterm.script')
11
- timingfile = Tempfile.new('showterm.time')
12
-
13
- sf, tf = [scriptfile, timingfile].map(&:path)
14
-
15
- scriptfile.close(true)
16
- timingfile.close(true)
16
+ scriptfile.close(false)
17
17
 
18
- args = []
18
+ args = [File.join(File.dirname(__FILE__), '../ext/ttyrec')]
19
19
  if cmd.size > 0
20
- args << '-c' + cmd.join(" ")
20
+ args << '-e' + cmd.join(" ")
21
21
  end
22
-
23
- args << '-q'
24
- args << '-t' + tf
25
- args << sf
22
+ args << scriptfile.path
26
23
 
27
24
  puts "showterm is recording, quit when you're done."
28
-
29
- unless system('script', *args)
30
- raise "Could not run 'script', please check that it's installed"
31
- end
32
-
25
+ system(*args) or raise "showterm recording failed"
33
26
  puts 'showterm recording finished'
34
27
 
35
- [sf, tf]
28
+ ret = scriptfile.open.read
29
+ scriptfile.close(true)
30
+ convert(ret)
31
+ end
32
+
33
+ # Get the current width of the terminal
34
+ #
35
+ # @return [Integer] number of columns
36
+ def terminal_width
37
+ guess = `tput cols`.to_i
38
+ guess == 0 ? 80 : guess
36
39
  end
37
40
 
38
- def upload!(scriptfile, timingfile, cols=80)
41
+ # Upload the termshow to showterm.io
42
+ #
43
+ # @param [String] scriptfile The ANSI dump of the terminal
44
+ # @param [String] timingfile The timings
45
+ # @param [Integer] cols The width of the terminal
46
+ def upload!(scriptfile, timingfile, cols=terminal_width)
39
47
  puts 'uploading, please wait.'
40
48
  request = Net::HTTP::Post.new("/scripts")
41
- request.set_form_data(:scriptfile => File.read(scriptfile),
42
- :timingfile => File.read(timingfile),
49
+ request.set_form_data(:scriptfile => scriptfile,
50
+ :timingfile => timingfile,
43
51
  :cols => cols)
44
52
 
45
53
  response = http(request)
46
54
  raise response.body unless Net::HTTPSuccess === response
47
55
  puts response.body
56
+ rescue => e
57
+ raise if retried
58
+ retried = true
59
+ retry
48
60
  end
49
61
 
50
62
  private
51
63
 
64
+ # The original version of showterm used the 'script' binary.
65
+ #
66
+ # Unfortunately that varies wildly from platform to platform, so we now
67
+ # bundle 'ttyrec' instead. This converts between the output of ttyrec and
68
+ # the output of 'script' so that the server remains solely a 'script' server.
69
+ #
70
+ # @param [String] ttyrecord
71
+ # @return [scriptfile, timingfile]
72
+ def convert(ttyrecord)
73
+ ttyrecord.force_encoding('BINARY') if ttyrecord.respond_to?(:force_encoding)
74
+ raise "Invalid ttyrecord: #{ttyrecord.inspect}" if ttyrecord.size < 12
75
+
76
+ scriptfile = "Converted from ttyrecord\n"
77
+ timingfile = ""
78
+
79
+ prev_sec, prev_usec = ttyrecord.unpack('VV')
80
+ pos = 0
81
+
82
+ while pos < ttyrecord.size
83
+ sec, usec, bytes = ttyrecord[pos..(pos + 12)].unpack('VVV')
84
+ time = (sec - prev_sec) + (usec - prev_usec) * 0.000_001
85
+
86
+ prev_sec = sec
87
+ prev_usec = usec
88
+
89
+ timingfile << "#{time} #{bytes}\n"
90
+ scriptfile << ttyrecord[(pos + 12)...(pos + 12 + bytes)]
91
+
92
+ pos += 12 + bytes
93
+ end
94
+
95
+ [scriptfile, timingfile]
96
+ end
97
+
52
98
  def http(request)
53
99
  connection = Net::HTTP.new("showterm.herokuapp.com", 443)
54
100
  connection.use_ssl = true