room_id = room_get_id(&room),
}
- request_id, err := request_host(app, request, &app.profile.private_key)
+ callback :: proc(app: ^App, response: common.Server_Response) {
+
+ }
+
+ err := request_host(app, request, &app.profile.private_key, callback)
if err != nil {
app_set_info_bar(app, "Could not subscribe to room.")
return .Command_Failed
}
- response := wait_host_response(app, request_id)
-
app_add_room(app, room)
app_set_info_bar(app, "Room added.")
room_id = room_get_id(&room),
}
- request_id, err := request_host(app, request, &app.profile.private_key)
+ callback :: proc(app: ^App, response: common.Server_Response) {
+ log.debug("Response %v", response)
+ }
+
+ err := request_host(app, request, &app.profile.private_key, callback)
if err != nil {
app_set_info_bar(app, "Could not subscribe to room.")
return .Command_Failed
}
- response := wait_host_response(app, request_id)
-
- log.infof("Response %v", response)
-
app_add_room(app, room)
app_set_info_bar(app, "Room generated.")
room_id = room_get_id(room),
}
- // request_id, err := request_host(app, request, &app.profile.private_key)
-
- // if err != nil {
- // app_set_info_bar(app, "Could not subscribe to room.")
- // return .Command_Failed
- // }
+ callback :: proc(app: ^App, response: common.Server_Response) {
+
+ }
- // response := wait_host_response(app, request_id)
+ err := request_host(app, request, &app.profile.private_key, callback)
- // log.infof("Response %v", response)
+ if err != nil {
+ app_set_info_bar(app, "Could not subscribe to room.")
+ return .Command_Failed
+ }
app_remove_room(app, app.selected_room)
app_set_info_bar(app, "Room removed.")
import "core:crypto/ed25519"
import "core:encoding/endian"
import "core:io"
-import "core:log"
import "core:math/rand"
import "core:mem"
import "core:net"
import "../common"
+Request_Callback :: proc(app: ^App, response: common.Server_Response)
+
request_host :: proc(
app: ^App,
inner: common.Client_Request_Inner,
- private_key: ^ed25519.Private_Key
-) -> (id: u32, err: common.Error) {
+ private_key: ^ed25519.Private_Key,
+ callback: Request_Callback,
+) -> common.Error {
request: common.Client_Request
ed25519.public_key_set_priv(&request.public_key, private_key)
request.inner = inner
id_bytes: [size_of(u32)]u8
_ = rand.read(id_bytes[:])
- id, _ = endian.get_u32(id_bytes[:], .Little)
+ id, _ := endian.get_u32(id_bytes[:], .Little)
_, _ = io.write(request_stream, id_bytes[:])
- log.infof("ID %v", id_bytes)
-
// Request.
_ = common.client_request_to_bytes(request_stream, request)
_ = net.send_tcp(app.host.?, request_bytes) or_return
- return id, nil
+ return nil
}
receive_host :: proc(app: ^App) -> (id: u32, message: common.Server_Message, err: common.Error) {
return common.server_message_from_bytes(app.host.?, packet_stream)
}
-
-wait_host_response :: proc(app: ^App, id: u32) -> common.Server_Response {
- for {
- time.sleep(1_000_000)
-
- sync.mutex_lock(&app.mutex)
- defer sync.mutex_unlock(&app.mutex)
-
- for res_id, response in app.waiting_responses {
- if res_id == id {
- delete_key(&app.waiting_responses, res_id)
- return response
- }
- }
- }
-}
seed_phrase_checksum: u8,
host: Maybe(net.TCP_Socket),
- waiting_responses: map[u32]common.Server_Response,
+ requests_callbacks: map[u32]Request_Callback,
selected_room: int,
}
info_bar = info_bar,
input_window = input_window,
- waiting_responses = make(map[u32]common.Server_Response),
+ requests_callbacks= make(map[u32]Request_Callback),
}
app_update_info_bar(&app)
sync.mutex_lock(&app.mutex)
defer sync.mutex_unlock(&app.mutex)
- for _, response in app.waiting_responses {
- common.server_response_deinit(response)
- }
-
- delete(app.waiting_responses)
+ delete(app.requests_callbacks)
if host, ok := app.host.?; ok {
net.close(host)
profile_deinit(app.profile)
- if len(app.profile_password) != 0 {
+ if app.profile_password != "" {
delete(app.profile_password)
}
config_deinit(app.config)
- if len(app.info_bar_content) != 0 {
+ if app.info_bar_content != "" {
delete(app.info_bar_content)
}
}
app_set_info_bar :: proc(app: ^App, format: string, args: ..any) {
- if len(app.info_bar_content) != 0 {
- delete(app.info_bar_content)
+ // FIXME
+ // ==========
+ // Setting info bar to empty string fucks up allocations
+ // for some reason ? If anyone got a fix please tell me.
+ //
+ // If you're wondering what I'm talking about, remove the
+ // if statement below and read the logs in debug mode.
+ // ==========
+ if format == "" {
+ return
}
sync.mutex_lock(&app.mutex)
defer sync.mutex_unlock(&app.mutex)
- if len(format) == 0 {
- app.info_bar_content = ""
- app_update_info_bar(app)
+ if app.info_bar_content != "" {
+ delete(app.info_bar_content)
+ }
+
+ defer app_update_info_bar(app)
+ if format == "" {
+ app.info_bar_content = ""
return
}
info_bar_content_builder: strings.Builder
-
strings.builder_init_none(&info_bar_content_builder)
- defer strings.builder_destroy(&info_bar_content_builder)
fmt.sbprintf(&info_bar_content_builder, format, ..args)
- app.info_bar_content = strings.clone(strings.to_string(info_bar_content_builder))
- app_update_info_bar(app)
-
- log.infof("Info bar %v", app.info_bar_content)
+ app.info_bar_content = strings.to_string(info_bar_content_builder)
}
app_set_box_message :: proc(app: ^App, lines: []string) {
}
}
+handle_host :: proc(app: ^App) {
+ for {
+ defer {
+ time.sleep(1_000_000)
+ free_all(context.temp_allocator)
+ }
+
+ state: State
+
+ {
+ sync.mutex_lock(&app.mutex)
+ defer sync.mutex_unlock(&app.mutex)
+
+ state = app.state
+ }
+
+ #partial switch state {
+ case .Room_List, .Room:
+ message_id, server_message, err := receive_host(app)
+
+ if err != nil {
+ log.errorf("Failed to receive server message with error %v", err)
+ continue
+ }
+
+ #partial switch message in server_message {
+ case common.Server_Response:
+ response := message
+ callback: Request_Callback
+
+ {
+ sync.mutex_lock(&app.mutex)
+ defer sync.mutex_unlock(&app.mutex)
+
+ callback = app.requests_callbacks[message_id]
+ delete_key(&app.requests_callbacks, message_id)
+ }
+
+ callback(app, response)
+ }
+ }
+ }
+}
+
main :: proc() {
home_path := os.get_env("HOME")
defer delete(home_path)
thread.destroy(handle_state_thread)
}
- for app.running {
+ // Setup host thread context.
+ handle_host_thread_context := runtime.default_context()
+ handle_host_thread_context.allocator = context.allocator
+ handle_host_thread_context.logger = context.logger
+ handle_host_thread_context.random_generator = context.random_generator
+
+ defer free_all(handle_host_thread_context.temp_allocator)
+
+ handle_host_thread := thread.create_and_start_with_poly_data(&app, handle_host, handle_host_thread_context)
+
+ defer {
+ thread.terminate(handle_host_thread, 0)
+ thread.destroy(handle_host_thread)
+ }
+
+ for {
defer {
time.sleep(1_000_000)
free_all(context.temp_allocator)
}
- state: State
-
- {
- sync.mutex_lock(&app.mutex)
- defer sync.mutex_unlock(&app.mutex)
+ sync.mutex_lock(&app.mutex)
+ defer sync.mutex_unlock(&app.mutex)
- state = app.state
+ if !app.running {
+ break
}
-
- // #partial switch state {
- // case .Room_List, .Room:
- // message_id, server_message, err := receive_host(&app)
-
- // if err != nil {
- // log.errorf("Failed to receive server message with error %v", err)
- // continue
- // }
-
- // #partial switch message in server_message {
- // case common.Server_Response:
- // response := message
-
- // sync.mutex_lock(&app.mutex)
- // defer sync.mutex_unlock(&app.mutex)
-
- // app.waiting_responses[message_id] = response
- // }
- // }
}
}
encrypted_message = encrypted_message,
}
- _, err := request_host(app, request, &app.profile.private_key)
+ callback :: proc(app: ^App, response: common.Server_Response) {
+
+ }
+
+ err := request_host(app, request, &app.profile.private_key, callback)
if err != nil {
app_set_info_bar(app, "Failed to send message.")
import "core:crypto/sha3"
import "core:encoding/endian"
import "core:io"
-import "core:log"
import "core:net"
import "core:math/rand"
import "core:mem"
}
client_request_inner_from_bytes :: proc(stream: io.Stream) -> (request: Client_Request_Inner, err: Error) {
- kind, err1 := io.read_byte(stream)
- if err1 != nil do return {}, err1
+ kind := io.read_byte(stream) or_return
inner: Client_Request_Inner
switch kind {
case 0: inner = write_request_from_bytes(stream) or_return
+
case 1: inner = subscribe_request_from_bytes(stream) or_return
case 2: inner = unsubscribe_request_from_bytes(stream) or_return
+
case: return {}, Client_Request_From_Bytes_Error.Invalid_Inner_Kind
}
client_request_inner_to_bytes :: proc(stream: io.Stream, inner: Client_Request_Inner) -> Error {
switch i in inner {
case Write_Request:
- io.write_byte(stream, 2) or_return
+ io.write_byte(stream, 0) or_return
write_request_to_bytes(stream, i) or_return
case Subscribe_Request:
- io.write_byte(stream, 0) or_return
+ io.write_byte(stream, 1) or_return
subscribe_request_to_bytes(stream, i) or_return
case Unsubscribe_Request:
- io.write_byte(stream, 1) or_return
+ io.write_byte(stream, 2) or_return
unsubscribe_request_to_bytes(stream, i) or_return
}
}
client_request_from_bytes :: proc(stream: io.Stream) -> (request: Client_Request, err: Error) {
+ // Pulic key.
public_key_bytes: [ed25519.PUBLIC_KEY_SIZE]u8
_ = io.read(stream, public_key_bytes[:]) or_return
- log.infof("PK %v", public_key_bytes)
-
public_key: ed25519.Public_Key
ok := ed25519.public_key_set_bytes(&public_key, public_key_bytes[:])
if !ok do return {}, .Invalid_Public_Key
+ // Inner.
inner := client_request_inner_from_bytes(stream) or_return
+ // Timestamp.
timestamp_bytes: [size_of(i64)]u8
_ = io.read(stream, timestamp_bytes[:]) or_return
timestamp, _ := endian.get_i64(timestamp_bytes[:], .Little)
+ // Signature.
signature: [ed25519.SIGNATURE_SIZE]u8
_ = io.read(stream, signature[:]) or_return
ed25519.public_key_bytes(&request.public_key, public_key_bytes[:])
_ = io.write(stream, public_key_bytes[:]) or_return
- log.infof("PK %v", public_key_bytes)
-
client_request_inner_to_bytes(stream, request.inner) or_return
timestamp_bytes: [size_of(i64)]u8
client_request_signature :: proc(request: Client_Request, private_key: ^ed25519.Private_Key) -> [ed25519.SIGNATURE_SIZE]u8 {
bytes_buf: [10_000]u8
- bytes_buffer: bytes.Buffer
- bytes_buffer.buf = slice.into_dynamic(bytes_buf[:])
+ bytes_buffer := buffer_from_slice(bytes_buf[:])
request_stream := bytes.buffer_to_stream(&bytes_buffer)
_ = client_request_to_bytes_signatureless(request_stream, request)
}
bytes_buf: [10_000]u8
- bytes_buffer: bytes.Buffer
- bytes_buffer.buf = slice.into_dynamic(bytes_buf[:])
+ bytes_buffer := buffer_from_slice(bytes_buf[:])
request_stream := bytes.buffer_to_stream(&bytes_buffer)
_ = client_request_to_bytes_signatureless(request_stream, request)
--- /dev/null
+package common
+
+import "base:runtime"
+
+import "core:bytes"
+import "core:slice"
+
+buffer_from_slice :: proc(s: []u8) -> bytes.Buffer {
+ bytes_buffer: bytes.Buffer
+ bytes_buffer.buf = slice.into_dynamic(s)
+ (^runtime.Raw_Dynamic_Array)(&bytes_buffer.buf).len = len(s)
+
+ return bytes_buffer
+}
import "core:bytes"
import "core:encoding/endian"
import "core:io"
-import "core:log"
import "core:net"
import "core:slice"
id_bytes := packet[:size_of(u32)]
id, _ = endian.get_u32(id_bytes[:], .Little)
- log.infof("ID %v", id_bytes)
-
request_bytes := packet[size_of(u32):]
- request_buffer: bytes.Buffer
- request_buffer.buf = slice.into_dynamic(request_bytes[:])
+
+ request_buffer := common.buffer_from_slice(request_bytes)
request_stream := bytes.buffer_to_stream(&request_buffer)
request, err = common.client_request_from_bytes(request_stream)
send_response :: proc(client: net.TCP_Socket, id: u32, content: string) -> common.Error {
bytes_buf: [1_000]u8
- bytes_buffer: bytes.Buffer
- bytes_buffer.buf = slice.into_dynamic(bytes_buf[:])
+ bytes_buffer := common.buffer_from_slice(bytes_buf[:])
response_stream := bytes.buffer_to_stream(&bytes_buffer)
// Message type.
recv_buffer: [10_000]u8
send_buffer: [10_000]u8
- response: []u8
+ response: string
for {
- defer net.send_tcp(client_socket, response)
-
request_id, request, err1 := receive_request(client_socket)
+ defer send_response(client_socket, request_id, response)
if err1 != nil {
#partial switch err in err1 {
}
}
- log.infof("Request error %v", err1)
-
- response_string := "Invalid request"
- response = transmute([]u8)response_string
+ response := "Invalid request"
continue
}
if err2 := common.client_request_verify(request, 1 * 60 * 60 * 1_000_000_000); err2 != nil {
- response_string := "Invalid authentication"
- response = transmute([]u8)response_string
-
+ response := "Invalid authentication"
continue
}
#partial switch inner in request.inner {
case:
- response_string := "Unhandled request type"
- response = transmute([]u8)response_string
-
+ response := "Unhandled request type"
continue
}
}