Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ jobs:
# Write and read notes from a file to avoid quoting breaking things
echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt

gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/server/*
gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/server/target/distrib/*

announce:
needs:
Expand Down
3 changes: 3 additions & 0 deletions builder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,9 @@ fn run_prerelease() -> io::Result<()> {
// Clean out all bundled files before the rebuild.
remove_dir_all_if_exists("../client/static/bundled")?;
run_install(true)?;
run_cmd!(
cargo test export_bindings;
)?;
run_script("npm", &["run", "dist"], "../client", true)?;
Ok(())
}
Expand Down
35 changes: 16 additions & 19 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codechat-editor-client",
"version": "0.1.20",
"version": "0.1.21",
"description": "The CodeChat Editor Client, part of a web-based literate programming editor (the CodeChat Editor).",
"homepage": "https://github.com/bjones1/CodeChat_Editor",
"type": "module",
Expand Down
3 changes: 3 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Changelog

* [Github master](https://github.com/bjones1/CodeChat_Editor):
* No changes.
* v0.1.21, 2025-Jul-18:
* Allow specifying the host address the server binds to.
* Send server logs to the console by default.
* v0.1.20, 2025-Jul-18:
* Correct data corruption in Client on delete/insert diff operations.
* v0.1.19, 2025-Jul-17: 
Expand Down
11 changes: 5 additions & 6 deletions extensions/VSCode/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion extensions/VSCode/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codechat-editor-client",
"version": "0.1.20",
"version": "0.1.21",
"publisher": "CodeChat",
"engines": {
"vscode": "^1.61.0"
Expand Down
6 changes: 3 additions & 3 deletions server/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ license = "GPL-3.0-only"
name = "codechat-editor-server"
readme = "../README.md"
repository = "https://github.com/bjones1/CodeChat_Editor"
version = "0.1.20"
version = "0.1.21"

# This library allows other packages to use core CodeChat Editor features.
[lib]
Expand Down
3 changes: 0 additions & 3 deletions server/log4rs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ appenders:
kind: console
encoder:
pattern: "{d} {l} {t} {L} - {m}{n}"
filters:
- kind: threshold
level: warn

# File appender for INFO, WARN, and ERROR levels
file_appender:
Expand Down
71 changes: 59 additions & 12 deletions server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
use std::{
env, fs,
io::{self, Read},
net::{IpAddr, Ipv4Addr, SocketAddr},
ops::RangeInclusive,
path::PathBuf,
process::{Child, Command, Stdio},
time::SystemTime,
Expand All @@ -34,7 +36,7 @@ use clap::{Parser, Subcommand};
use log::LevelFilter;

// ### Local
use code_chat_editor::webserver::{self, GetServerUrlError, IP_ADDRESS, path_to_url};
use code_chat_editor::webserver::{self, GetServerUrlError, path_to_url};

// Data structures
// ---------------
Expand All @@ -48,8 +50,12 @@ struct Cli {
#[command(subcommand)]
command: Commands,

/// Select the port to use for the server.
#[arg(short, long, default_value_t = 8080)]
/// The address to serve.
#[arg(long, default_value_t = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))]
host: IpAddr,

/// The port to use for the server.
#[arg(short, long, default_value_t = 8080, value_parser = port_in_range)]
port: u16,

/// Used for testing only.
Expand Down Expand Up @@ -88,7 +94,7 @@ enum Commands {
// The following code implements the command-line interface for the CodeChat
// Editor.
impl Cli {
fn run(self) -> Result<(), Box<dyn std::error::Error>> {
fn run(self, addr: &SocketAddr) -> Result<(), Box<dyn std::error::Error>> {
match &self.command {
Commands::Serve { log } => {
#[cfg(debug_assertions)]
Expand All @@ -98,15 +104,17 @@ impl Cli {
return Ok(());
}
webserver::configure_logger(log.unwrap_or(LevelFilter::Info))?;
webserver::main(self.port).unwrap();
webserver::main(addr).unwrap();
}
Commands::Start { open } => {
// Poll the server to ensure it starts.
let mut process: Option<Child> = None;
let now = SystemTime::now();
// If host is 0.0.0.0, use localhost to monitor it.
let ping_addr = fix_addr(addr);
loop {
// Look for a ping/pong response from the server.
match minreq::get(format!("http://{IP_ADDRESS}:{}/ping", self.port))
match minreq::get(format!("http://{ping_addr}/ping"))
.with_timeout(3)
.send()
{
Expand All @@ -122,7 +130,7 @@ impl Cli {
// -- if `open` used `$BROWSER` (following
// Pyhton), it should work.
if let Some(open_path) = open {
let address = get_server_url(self.port)?;
let address = get_server_url(ping_addr.port())?;
let open_path = fs::canonicalize(open_path)?;
let open_path =
path_to_url(&format!("{address}/fw/fsb"), None, &open_path);
Expand All @@ -146,7 +154,7 @@ impl Cli {
break 'err_print;
}
}
eprintln!("Failed to connect to server: {err}");
eprintln!("Failed to connect to server at {addr}: {err}");
}
}
}
Expand Down Expand Up @@ -182,7 +190,15 @@ impl Cli {
}
}
process = match cmd
.args(["--port", &self.port.to_string(), "serve", "--log", "off"])
.args([
"--host",
&self.host.to_string(),
"--port",
&self.port.to_string(),
"serve",
"--log",
"off",
])
// Subtle: the default of
// `stdout(Stdio::inherit())` causes a parent
// process to block, since the child process
Expand Down Expand Up @@ -245,13 +261,15 @@ impl Cli {
}
Commands::Stop => {
println!("Stopping server...");
let stop_addr = fix_addr(addr);

// TODO: Use https://crates.io/crates/sysinfo to find the server
// process and kill it if it doesn't respond to a stop request.
return match minreq::get(format!("http://{IP_ADDRESS}:{}/stop", self.port))
return match minreq::get(format!("http://{stop_addr}/stop"))
.with_timeout(3)
.send()
{
Err(err) => Err(format!("Failed to stop server: {err}").into()),
Err(err) => Err(format!("Failed to stop server at {stop_addr}: {err}").into()),
Ok(response) => {
let status_code = response.status_code;
if status_code == 204 {
Expand All @@ -273,10 +291,39 @@ impl Cli {
}
}

const PORT_RANGE: RangeInclusive<usize> = 1..=65535;

// Copied from the [clap docs](https://docs.rs/clap/latest/clap/_derive/_tutorial/index.html#validated-values).
fn port_in_range(s: &str) -> Result<u16, String> {
let port: usize = s
.parse()
.map_err(|_| format!("`{s}` isn't a port number"))?;
if PORT_RANGE.contains(&port) {
Ok(port as u16)
} else {
Err(format!(
"port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))
}
}

fn fix_addr(addr: &SocketAddr) -> SocketAddr {
if addr.ip() == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) {
let mut addr = *addr;
addr.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
addr
} else {
*addr
}
}

#[cfg(not(tarpaulin_include))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
cli.run()?;
let addr = SocketAddr::new(cli.host, cli.port);
cli.run(&addr)?;

Ok(())
}
Expand Down
Loading
Loading