members_public_keys: []Public_Key_Bytes,
}
+Block_User :: struct {
+ user_public_key: ed25519.Public_Key,
+}
+
+Set_Whitelist_State :: struct {
+ state: bool,
+}
+
+Add_To_Whitelist :: struct {
+ user_public_key: ed25519.Public_Key,
+}
+
+Remove_From_Whitelist :: struct {
+ user_public_key: ed25519.Public_Key,
+}
+
Public_Message :: struct {
room_id: string,
content: string,
encrypted_contents: map[Public_Key_Bytes][]u8,
}
-Block_User :: struct {
- user_public_key: ed25519.Public_Key,
-}
-
Client_Request_Content :: union {
// Client only.
- Block_User,
Create_Room,
Create_Group,
+ Block_User,
+
+ Set_Whitelist_State,
+ Add_To_Whitelist,
+ Remove_From_Whitelist,
+
// Common.
Public_Message,
Private_Message,
Client_Request :: struct {
public_key: ed25519.Public_Key,
content: Client_Request_Content,
- timestamp: u32,
+ timestamp: i64,
signature: [32]u8,
}
panic("TODO")
}
-client_request_verify :: proc(request: Client_Request, expiration: Maybe(u32)) -> bool {
+client_request_verify :: proc(request: Client_Request, expiration: Maybe(i64)) -> bool {
panic("TODO")
}
package main
+import "core:encoding/csv"
+import "core:encoding/json"
+import "core:fmt"
import "core:log"
import "core:net"
+import "core:os"
+
+import fpath "core:path/filepath"
import "../common"
-main :: proc() {
- context.logger = log.create_console_logger()
- defer log.destroy_console_logger(context.logger)
+Config :: struct {
+ selected_profile: Maybe(string),
+}
+
+App :: struct {
+ config: Config,
+ servers: map[string]net.TCP_Socket,
+}
+
+config_update :: proc(app: App, config: Config) {
+ home_path := os.get_env("HOME")
+ storage_path := fpath.join({ home_path, "mesange-cli" }, context.temp_allocator)
+
+ config_path := fpath.join({ storage_path, "config.json" }, context.temp_allocator)
+
+ config_file, err1 := os.open(config_path, O_WRONLY)
- server_endpoint := net.Endpoint{
- address = net.IP4_Address { 127, 0, 0, 1 },
- port = 3000,
+ if err1 != nil {
+ fmt.eprintln("Failed to open config file.")
+ return
+ }
+
+ config_file_stream := os.stream_from_handle(config_file)
+
+ marshal_options := json.Marshal_Options{
+ spec = .JSON,
+ pretty = true,
+ use_spaces = true,
+ use_enum_names = true,
}
- socket, err1 := net.dial_tcp(server_endpoint)
+ err2 := json.marshal_to_writer(config_file_stream, app.config, &marshal_options)
+
+ if err2 != nil {
+ fmt.eprintln("Failed to marshal config.")
+ return
+ }
+}
+
+init :: proc(app: ^App) {
+ home_path := os.get_env("HOME")
+ storage_path := fpath.join({ home_path, "mesange-cli" }, context.temp_allocator)
+
+ err1 := os.make_directory(storage_path)
if err1 != nil {
- log.errorf("Failed to connect to server with error %v.", err1)
+ fmt.eprintln("Failed to create storage directory.")
return
}
- defer net.close(socket)
+ { // Load config.
+ fmt.println("Loading config...")
+
+ config_path := fpath.join({ storage_path, "config.json" }, context.temp_allocator)
+
+ if !os.exists(config_path) {
+ // Init default config.
+ ok := os.write_entire_file(
+ config_path,
+ `
+{
+ "current_profile": null
+}
+ `,
+ )
+
+ if !ok {
+ fmt.eprintln("Failed to write to config file.")
+ return
+ }
+ }
- log.info("Connected to server.")
+ raw_config, ok := os.read_entire_file_from_filename(config_path)
- for {
+ if !ok {
+ fmt.eprintln("Failed to read config file.")
+ return
+ }
+
+ config: Config
+ err2 := json.unmarshal(raw_config, &config)
+
+ if err2 != nil {
+ fmt.eprintln("Invalid config file.")
+ return
+ }
+
+ app.config = config
}
}
+
+main :: proc() {
+ context.logger = log.create_console_logger()
+ defer log.destroy_console_logger(context.logger)
+
+ when ODIN_DEBUG {
+ track: mem.Tracking_Allocator
+ mem.tracking_allocator_init(&track, context.allocator)
+
+ context.allocator = mem.tracking_allocator(&track)
+
+ defer {
+ if len(track.allocation_map) > 0 {
+ fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map))
+
+ for _, entry in track.allocation_map {
+ fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location)
+ }
+ }
+
+ if len(track.bad_free_array) > 0 {
+ fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array))
+
+ for entry in track.bad_free_array {
+ fmt.eprintf("- %p @ %v\n", entry.memory, entry.location)
+ }
+ }
+
+ mem.tracking_allocator_destroy(&track)
+ }
+ }
+
+ app := App{
+ servers = make(map[string]net.TCP_Socket)
+ }
+
+ init()
+}
bytes := recv_buffer[:bytes_read]
- defer net.send(response)
+ defer net.send(client_socket, response)
request, ok := common.client_request_parse(bytes)
if !ok {
- response = "Invalid request"
+ response_string := "Invalid request"
+ response = transmute([]u8)response_string
+
continue
}
if !common.client_request_verify(request, 1 * 60 * 60 * 1_000_000_000) {
- response = "Invalid authentication"
+ response_string := "Invalid authentication"
+ response = transmute([]u8)response_string
+
continue
}
switch content in request.content {
+ case:
+ response_string := "Unhandled request type"
+ response = transmute([]u8)response_string
+ continue
}
-
- fmt.printf("<%v> %v\n", client_endpoint_string, message)
}
}
context.logger = log.create_console_logger()
defer log.destroy_console_logger(context.logger)
+ when ODIN_DEBUG {
+ track: mem.Tracking_Allocator
+ mem.tracking_allocator_init(&track, context.allocator)
+
+ context.allocator = mem.tracking_allocator(&track)
+
+ defer {
+ if len(track.allocation_map) > 0 {
+ fmt.eprintf("=== %v allocations not freed: ===\n", len(track.allocation_map))
+
+ for _, entry in track.allocation_map {
+ fmt.eprintf("- %v bytes @ %v\n", entry.size, entry.location)
+ }
+ }
+
+ if len(track.bad_free_array) > 0 {
+ fmt.eprintf("=== %v incorrect frees: ===\n", len(track.bad_free_array))
+
+ for entry in track.bad_free_array {
+ fmt.eprintf("- %p @ %v\n", entry.memory, entry.location)
+ }
+ }
+
+ mem.tracking_allocator_destroy(&track)
+ }
+ }
+
server_endpoint := net.Endpoint{
address = net.IP4_Address{ 127, 0, 0, 1 },
port = 3000,