|
1 | | -#include <cstdio> |
2 | | -#include <expected> |
3 | | -#include <filesystem> |
4 | | -#include <iostream> |
5 | | -#include <optional> |
6 | | -#include <string> |
7 | | -#include <string_view> |
8 | | -#include <vector> |
9 | | - |
10 | | -#include "eventide/deco/macro.h" |
11 | | -#include "eventide/deco/runtime.h" |
12 | | -#include "eventide/serde/config.h" |
13 | | -#include "server/protocol.h" |
14 | | -#include "server/runtime.h" |
15 | | - |
16 | | -namespace { |
17 | | - |
18 | | -using clice::server::Mode; |
19 | | -using clice::server::Options; |
20 | | - |
21 | | -struct ModeOption { |
22 | | - Mode value = Mode::Pipe; |
23 | | - |
24 | | - auto into(std::string_view text) -> std::optional<std::string_view> { |
25 | | - if(text == "pipe") { |
26 | | - value = Mode::Pipe; |
27 | | - return std::nullopt; |
28 | | - } |
29 | | - if(text == "socket") { |
30 | | - value = Mode::Socket; |
31 | | - return std::nullopt; |
32 | | - } |
33 | | - if(text == "worker") { |
34 | | - value = Mode::Worker; |
35 | | - return std::nullopt; |
36 | | - } |
37 | | - return "invalid --mode, expected: pipe|socket|worker"; |
38 | | - } |
39 | | -}; |
40 | | - |
41 | | -struct CliOptions { |
42 | | - DECO_CFG_START(required = false;); |
43 | | - |
44 | | - DecoFlag(names = {"-h", "--help"}; help = "Show this help message and exit"; required = false;) |
45 | | - help = false; |
46 | | - |
47 | | - DecoFlag(names = {std::string_view(clice::server::k_worker_mode)}; |
48 | | - help = "Run as worker process"; |
49 | | - required = false;) |
50 | | - worker_mode = false; |
51 | | - |
52 | | - DecoKVStyled(deco::decl::KVStyle::Joined, names = {"--mode=", "--mode"}; meta_var = "MODE"; |
53 | | - help = "Server mode: pipe|socket|worker"; |
54 | | - required = false;) |
55 | | - <ModeOption> mode; |
56 | | - |
57 | | - DecoKVStyled(deco::decl::KVStyle::Joined, names = {"--host=", "--host"}; meta_var = "HOST"; |
58 | | - help = "Socket host (default: 127.0.0.1)"; |
59 | | - required = false;) |
60 | | - <std::string> host; |
61 | | - |
62 | | - DecoKVStyled(deco::decl::KVStyle::Joined, names = {"--port=", "--port"}; meta_var = "PORT"; |
63 | | - help = "Socket port (default: 50051)"; |
64 | | - required = false) |
65 | | - <int> port; |
66 | | - |
67 | | - DecoKVStyled(deco::decl::KVStyle::Joined, names = {"--worker-count=", "--worker-count"}; |
68 | | - meta_var = "N"; |
69 | | - help = "Worker process count (default: 2)"; |
70 | | - required = false) |
71 | | - <std::size_t> worker_count; |
72 | | - |
73 | | - DecoKVStyled(deco::decl::KVStyle::Joined, |
74 | | - names = {"--worker-doc-capacity=", "--worker-doc-capacity"}; |
75 | | - meta_var = "N"; |
76 | | - help = "Per-worker AST cache capacity (default: 32)"; |
77 | | - required = false;) |
78 | | - <std::size_t> worker_document_capacity; |
79 | | - |
80 | | - DecoKVStyled(deco::decl::KVStyle::Joined, |
81 | | - names = {"--master-doc-capacity=", "--master-doc-capacity"}; |
82 | | - meta_var = "N"; |
83 | | - help = "Master ownership cache capacity (default: 256)"; |
84 | | - required = false;) |
85 | | - <std::size_t> master_document_capacity; |
86 | | - |
87 | | - DECO_CFG_END(); |
88 | | -}; |
89 | | - |
90 | | -auto resolve_self_path(int argc, const char** argv) -> std::string { |
91 | | - if(argc <= 0 || argv == nullptr || argv[0] == nullptr) { |
92 | | - return "clice"; |
93 | | - } |
94 | | - |
95 | | - std::error_code ec; |
96 | | - auto absolute = std::filesystem::absolute(argv[0], ec); |
97 | | - if(ec) { |
98 | | - return std::string(argv[0]); |
99 | | - } |
100 | | - return absolute.string(); |
101 | | -} |
102 | | - |
103 | | -auto build_options(const CliOptions& cli_options, int argc, const char** argv) |
104 | | - -> std::expected<Options, std::string> { |
105 | | - Options options; |
106 | | - options.self_path = resolve_self_path(argc, argv); |
107 | | - |
108 | | - if(cli_options.mode.value.has_value()) { |
109 | | - options.mode = cli_options.mode->value; |
110 | | - } else if(cli_options.worker_mode.value.value_or(false)) { |
111 | | - options.mode = Mode::Worker; |
112 | | - } |
113 | | - |
114 | | - if(cli_options.host.value.has_value()) { |
115 | | - options.host = *cli_options.host; |
116 | | - } |
117 | | - if(cli_options.port.value.has_value()) { |
118 | | - if(*cli_options.port <= 0) { |
119 | | - return std::unexpected("--port must be a positive integer"); |
120 | | - } |
121 | | - options.port = *cli_options.port; |
122 | | - } |
123 | | - if(cli_options.worker_count.value.has_value()) { |
124 | | - if(*cli_options.worker_count == 0) { |
125 | | - return std::unexpected("--worker-count must be a positive integer"); |
126 | | - } |
127 | | - options.worker_count = *cli_options.worker_count; |
128 | | - } |
129 | | - if(cli_options.worker_document_capacity.value.has_value()) { |
130 | | - if(*cli_options.worker_document_capacity == 0) { |
131 | | - return std::unexpected("--worker-doc-capacity must be a positive integer"); |
132 | | - } |
133 | | - options.worker_document_capacity = *cli_options.worker_document_capacity; |
134 | | - } |
135 | | - if(cli_options.master_document_capacity.value.has_value()) { |
136 | | - if(*cli_options.master_document_capacity == 0) { |
137 | | - return std::unexpected("--master-doc-capacity must be a positive integer"); |
138 | | - } |
139 | | - options.master_document_capacity = *cli_options.master_document_capacity; |
140 | | - } |
141 | | - |
142 | | - return options; |
143 | | -} |
144 | | - |
145 | | -auto print_usage() -> void { |
146 | | - deco::cli::Dispatcher<CliOptions> dispatcher("clice [OPTIONS]"); |
147 | | - dispatcher.usage(std::cerr, true); |
148 | | -} |
149 | | - |
150 | | -auto run_with_options(const Options& options) -> int { |
151 | | - switch(options.mode) { |
152 | | - case Mode::Pipe: return clice::server::run_pipe_mode(options); |
153 | | - case Mode::Socket: return clice::server::run_socket_mode(options); |
154 | | - case Mode::Worker: return clice::server::run_worker_mode(options); |
155 | | - } |
156 | | - return 1; |
157 | | -} |
158 | | - |
159 | | -} // namespace |
160 | | - |
161 | 1 | int main(int argc, const char** argv) { |
162 | | - eventide::serde::config::set_field_rename_policy<eventide::serde::rename_policy::lower_camel>(); |
163 | | - |
164 | | - auto args = deco::util::argvify(argc, argv); |
165 | | - auto parsed = deco::cli::parse<CliOptions>(args); |
166 | | - if(!parsed) { |
167 | | - std::fprintf(stderr, "%s\n", parsed.error().message.c_str()); |
168 | | - print_usage(); |
169 | | - return 1; |
170 | | - } |
171 | | - |
172 | | - const auto& cli_options = parsed->options; |
173 | | - if(cli_options.help.value.value_or(false)) { |
174 | | - print_usage(); |
175 | | - return 0; |
176 | | - } |
177 | | - |
178 | | - auto options = build_options(cli_options, argc, argv); |
179 | | - if(!options) { |
180 | | - std::fprintf(stderr, "%s\n", options.error().c_str()); |
181 | | - print_usage(); |
182 | | - return 1; |
183 | | - } |
184 | | - |
185 | | - return run_with_options(*options); |
| 2 | + return 0; |
186 | 3 | } |
0 commit comments