Mercurial > cgi-bin > hgweb.cgi > PassMan
annotate src/main/kotlin/name/blackcap/passman/Main.kt @ 28:287eadf5ab30 default tip
Check for timeouts inside subcommands while in interactive mode as well.
author | David Barts <n5jrn@me.com> |
---|---|
date | Wed, 31 Jul 2024 11:21:18 -0700 |
parents | 3a3067ba673b |
children |
rev | line source |
---|---|
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
1 package name.blackcap.passman |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
2 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
3 import java.util.* |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
4 import kotlin.system.exitProcess |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
5 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
6 fun main(args: Array<String>) { |
24
2188b2f13326
Make some minor tweaks to the help system.
David Barts <n5jrn@me.com>
parents:
23
diff
changeset
|
7 val NOPASSWORD = setOf<String>("help", "quit") |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
8 if (args.isEmpty()) { |
22 | 9 openDatabase() |
10 runInteractive() | |
11 } | |
12 val subcommand = args[0] | |
13 val scArgs = args.sliceArray(1 until args.size) | |
14 if (subcommand !in NOPASSWORD) { | |
15 openDatabase() | |
16 } | |
17 runNonInteractive(subcommand, scArgs) | |
18 } | |
19 | |
20 fun openDatabase() { | |
21 try { | |
22 Database.default = Database.open() | |
23 } catch (e: DatabaseException) { | |
24 handleMessagedException(e) | |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
25 exitProcess(2) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
26 } |
22 | 27 } |
28 | |
29 fun runNonInteractive(subcommand: String, scArgs: Array<String>): Unit { | |
30 try { | |
31 runSubcommand(subcommand, scArgs) | |
32 } catch (e: SubcommandException) { | |
33 handleSubcommandException(e) | |
34 exitProcess(e.status) | |
35 } catch (e: MessagedException) { | |
36 handleMessagedException(e) | |
37 exitProcess(1) | |
38 } | |
39 exitProcess(0) | |
40 } | |
41 | |
42 fun runInteractive() { | |
43 val DISALLOWED = setOf<String>("password") | |
44 val QUIT = setOf<String>("exit", "quit") | |
27
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
45 val MAX_TIME_MILLIS = 10L * 60L * 1000L |
22 | 46 var lastStatus = 0 |
24
2188b2f13326
Make some minor tweaks to the help system.
David Barts <n5jrn@me.com>
parents:
23
diff
changeset
|
47 println("This is PassMan interactive mode. Type help for help.") |
22 | 48 while (true) { |
27
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
49 val beforeRead = System.currentTimeMillis() |
23 | 50 val rawLine = System.console()?.readLine("passman> ") |
51 if (rawLine == null) { | |
52 println() // ensure shell prompt comes out on a line of its own | |
53 break | |
54 } | |
27
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
55 if (System.currentTimeMillis() - beforeRead > MAX_TIME_MILLIS) { |
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
56 error("time limit exceeded, goodbye!") |
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
57 lastStatus = 1 |
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
58 break |
3a3067ba673b
Add idle-time detection to interactive mode, clean up imports.
David Barts <n5jrn@me.com>
parents:
24
diff
changeset
|
59 } |
22 | 60 val s = Shplitter() |
61 s.feed(rawLine) | |
62 if (!s.complete) { | |
63 error("unterminated quoting") | |
64 lastStatus = 1 | |
65 continue | |
66 } | |
67 val line = s.split().toList() | |
68 if (line.isEmpty()) { | |
69 continue | |
70 } | |
71 val subcommand = line.first() | |
72 val scArgs = line.drop(1).toTypedArray() | |
73 if (subcommand in QUIT) { | |
74 break | |
75 } | |
76 if (subcommand in DISALLOWED) { | |
77 error("$subcommand subcommand not allowed in interactive mode") | |
78 lastStatus = 2 | |
79 continue | |
80 } | |
28
287eadf5ab30
Check for timeouts inside subcommands while in interactive mode as well.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
81 val beforeRun = System.currentTimeMillis() |
22 | 82 try { |
83 runSubcommand(subcommand, scArgs) | |
84 lastStatus = 0 | |
85 } catch(e: SubcommandException) { | |
86 handleSubcommandException(e) | |
87 lastStatus = e.status | |
88 } catch(e: MessagedException) { | |
89 handleMessagedException(e) | |
90 lastStatus = 1 | |
91 } | |
28
287eadf5ab30
Check for timeouts inside subcommands while in interactive mode as well.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
92 if (System.currentTimeMillis() - beforeRun > MAX_TIME_MILLIS) { |
287eadf5ab30
Check for timeouts inside subcommands while in interactive mode as well.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
93 error("time limit exceeded, goodbye!") |
287eadf5ab30
Check for timeouts inside subcommands while in interactive mode as well.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
94 lastStatus = 1 |
287eadf5ab30
Check for timeouts inside subcommands while in interactive mode as well.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
95 break |
287eadf5ab30
Check for timeouts inside subcommands while in interactive mode as well.
David Barts <n5jrn@me.com>
parents:
27
diff
changeset
|
96 } |
22 | 97 } |
98 exitProcess(lastStatus) | |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
99 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
100 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
101 fun runSubcommand(name: String, args: Array<String>): Unit { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
102 val instance = getInstanceForClass(getClassForSubcommand(name)) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
103 if (instance == null) { |
22 | 104 throw SubcommandException(message = "${see(name)} - unknown subcommand", status = 2) |
0
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
105 } else { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
106 instance.run(args) |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
107 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
108 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
109 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
110 fun getClassForSubcommand(name: String): Class<Subcommand>? = try { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
111 val shortName = name.replace('-', '_') |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
112 .lowercase() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
113 .replaceFirstChar { it.titlecase(Locale.getDefault()) } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
114 Class.forName("$MAIN_PACKAGE.${shortName}Subcommand") as? Class<Subcommand> |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
115 } catch (e: ClassNotFoundException) { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
116 null |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
117 } |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
118 |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
119 fun getInstanceForClass(klass: Class<Subcommand>?) = try { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
120 klass?.getDeclaredConstructor()?.newInstance() |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
121 } catch (e: ReflectiveOperationException) { |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
122 null |
a6cfdffcaa94
Initial commit, incomplete but it runs sorta.
David Barts <n5jrn@me.com>
parents:
diff
changeset
|
123 } |
22 | 124 |
125 fun handleMessagedException(e: MessagedException) = error(e.message) | |
126 | |
127 fun handleSubcommandException(e: SubcommandException): Unit { | |
128 if (e.message != null) { | |
129 error(e.message!!) | |
130 } | |
131 } |