From cb381871d518077649be6272af823dabec2fcd28 Mon Sep 17 00:00:00 2001 From: Ibrahim Mkusa Date: Sun, 9 Apr 2017 22:37:50 -0400 Subject: reorganized repo a bit better --- FP4-instructions.md | 93 ----------------- Gui_Exploration.rkt | 129 ----------------------- Hermes/client.rkt | 102 ++++++++++++++++++ Hermes/concurrentreadandprint.rkt | 77 ++++++++++++++ Hermes/server.rkt | 140 +++++++++++++++++++++++++ Hermes/tcpcommunication.rkt | 57 ++++++++++ README.md | 4 +- arch_diagram.png | Bin 23853 -> 0 bytes architecture_diagram.png | Bin 65212 -> 0 bytes client.rkt | 102 ------------------ concurrentreadandprint.rkt | 77 -------------- crpovertcp.rkt | 155 ---------------------------- docs/FP4-instructions.md | 93 +++++++++++++++++ ext/arch_diagram.png | Bin 0 -> 23853 bytes ext/architecture_diagram.png | Bin 0 -> 65212 bytes feasibility_analysis/gui/windows.rkt | 9 -- feasibility_analysis/gui/windows2.rkt | 15 --- feasibility_analysis/tcpevents/README.md | 1 - feasibility_analysis/tcpevents/server.rkt | 39 ------- feasibility_analysis/tcpvanilla/README.md | 20 ---- feasibility_analysis/tcpvanilla/client.rkt | 72 ------------- feasibility_analysis/tcpvanilla/client2.rkt | 43 -------- feasibility_analysis/tcpvanilla/server.rkt | 58 ----------- feasibility_analysis/tcpvanilla/tcptalk.rkt | 30 ------ server.rkt | 140 ------------------------- tcpcommunication.rkt | 57 ---------- tests/gui/Gui_Exploration.rkt | 129 +++++++++++++++++++++++ tests/gui/windows.rkt | 9 ++ tests/gui/windows2.rkt | 15 +++ tests/tcpevents/README.md | 1 + tests/tcpevents/crpovertcp.rkt | 155 ++++++++++++++++++++++++++++ tests/tcpevents/server.rkt | 39 +++++++ tests/tcpvanilla/README.md | 20 ++++ tests/tcpvanilla/client.rkt | 72 +++++++++++++ tests/tcpvanilla/client2.rkt | 43 ++++++++ tests/tcpvanilla/server.rkt | 58 +++++++++++ tests/tcpvanilla/tcptalk.rkt | 30 ++++++ 37 files changed, 1042 insertions(+), 1042 deletions(-) delete mode 100644 FP4-instructions.md delete mode 100644 Gui_Exploration.rkt create mode 100644 Hermes/client.rkt create mode 100644 Hermes/concurrentreadandprint.rkt create mode 100644 Hermes/server.rkt create mode 100644 Hermes/tcpcommunication.rkt delete mode 100644 arch_diagram.png delete mode 100644 architecture_diagram.png delete mode 100644 client.rkt delete mode 100644 concurrentreadandprint.rkt delete mode 100644 crpovertcp.rkt create mode 100644 docs/FP4-instructions.md create mode 100644 ext/arch_diagram.png create mode 100644 ext/architecture_diagram.png delete mode 100644 feasibility_analysis/gui/windows.rkt delete mode 100644 feasibility_analysis/gui/windows2.rkt delete mode 100644 feasibility_analysis/tcpevents/README.md delete mode 100644 feasibility_analysis/tcpevents/server.rkt delete mode 100644 feasibility_analysis/tcpvanilla/README.md delete mode 100644 feasibility_analysis/tcpvanilla/client.rkt delete mode 100644 feasibility_analysis/tcpvanilla/client2.rkt delete mode 100644 feasibility_analysis/tcpvanilla/server.rkt delete mode 100644 feasibility_analysis/tcpvanilla/tcptalk.rkt delete mode 100644 server.rkt delete mode 100644 tcpcommunication.rkt create mode 100644 tests/gui/Gui_Exploration.rkt create mode 100644 tests/gui/windows.rkt create mode 100644 tests/gui/windows2.rkt create mode 100644 tests/tcpevents/README.md create mode 100644 tests/tcpevents/crpovertcp.rkt create mode 100644 tests/tcpevents/server.rkt create mode 100644 tests/tcpvanilla/README.md create mode 100644 tests/tcpvanilla/client.rkt create mode 100644 tests/tcpvanilla/client2.rkt create mode 100644 tests/tcpvanilla/server.rkt create mode 100644 tests/tcpvanilla/tcptalk.rkt diff --git a/FP4-instructions.md b/FP4-instructions.md deleted file mode 100644 index 6a04e91..0000000 --- a/FP4-instructions.md +++ /dev/null @@ -1,93 +0,0 @@ -# FP4-proposal - -**do not fork this** there are different directions - -## tl;dr - -1. Create a repository in [our organization][oplorg] for your project; add your teammate(s) as collaborators -2. Copy-paste this [template file](template.md) as the `README.md` file in your new repo; edit to become project plan -3. Make 3-slide slide show to be presented in class; insert into [class desk][gslides] -4. Enter project details into a new [Google form][projform] -5. Make a 0.1 release of your project (tagging `@fgmart`) - -## Due Date -* Sun Apr 2, 2017 at 11p - -## Instructions - -Teams will submit a single proposal, with sections that each member has done individually detailing their proposed contributions. The submission will be the `README.md` file in your brand-new project repository, which you'll make. - -You must start using GitHub collaboratively from this point forward. - -Instructions: - -1. Create a new repository for your project as part of [our organization][oplorg] - * Give it a name that you like—it may be your real names, usernames, or project name - * Add your teammates as collaborators (Settings > Collaborators & Teams > Add Collaborator) -2. Copy the content from the [template file](template.md) into your `README.md` - * Click the “Raw” button on the `template.md` file and then copy-paste into your repo's `README.md` edit view - * Save it - * *Then start editing it to become your actual proposal* -3. Everyone on the team contributes their sections to your `README.md` file. - * Use GitHub's collaboration features to make sure that each team member contributes meaningful content to the file - * At the absolute minimum, respective team members must have commits that show they have authored the section describing their planned contributions -4. Create a [github Release](https://help.github.com/articles/creating-releases/) of your repository. - * Version: v0.1 - * Title: Proposal - * Description: tag `@fgmart` - -And now some detail on what to write _in_ the report. - -**Overall guidance:** *You should be proposing something that you have high confidence that you can achieve, and the proposal should project that confidence.* - -The proposal should be no longer than necessary, but long enough to include critical detail. Diagrams are welcome. - -Remember, you can do some neat [formatting things with Markdown.][markdown] - -In case you missed it, here again is the [template file](template.md) - -## In-Class Presentation -Teams will each deliver an in-class presentation. Your team will have two minutes to present. - -The presentation shall have exactly three slides: - -1. Title - * project title (10 words or fewer) - * your real names - * each real name followed by GitHub username - * a relevant image of some sort (optional) -2. Overview - * a few short phrases describing the project - * a different relevant image (optional) -3. Architecture Diagram - * visual diagram showing the major components of the project - * include external things that your project will connect to - * include arrows showing flow of information - * internal components annotated with Racket libraries that they will use - * _important:_ annotate each block with the GH username of the person who is primarily responsible for its creation - -Make the slides in [Google Slides][gslides]. - -Then, import your deck into the [slide deck][martinslides]. You have write privileges based on your membership in the class forum. - -You and your teammates will give the presentation in class the day that this assignment is due. - -## Fill out Project Information Form - -Enter project details into a new [Google form][projform]. - -**This is absolutely necessary so I can keep track of all of the projects.** - -## Grading -The proposal must be submitted on time to receive credit. Late submissions will not be accepted for credit. - -You personally must be present in class (and participate in the presentation when it is your turn) to receive credit for the presentation. If your teammates are there and you are not, they will receive presentation credit and you will not. - - - -[forum]: https://groups.google.com/forum/#!forum/uml-opl-spr17 -[markdown]: https://help.github.com/articles/markdown-basics/ -[gslides]:https://slides.google.com -[martinslides]:https://docs.google.com/presentation/d/1fzNX4nV4z6IkLiVBMB0YD4CctlJxR9pWXSbYTOFcQvc -[projform]:https://goo.gl/forms/Gfh9hWBgvg323j6M2 -[oplorg]:https://github.com/oplS17projects/ diff --git a/Gui_Exploration.rkt b/Gui_Exploration.rkt deleted file mode 100644 index ff4d2d3..0000000 --- a/Gui_Exploration.rkt +++ /dev/null @@ -1,129 +0,0 @@ -#lang racket -(require racket/gui/base) -;;Step 1. Create a window to draw into -(define frame(new frame% [label "Example"])) -;;I don't know what frame% means, but new must be a procedure -;;(send frame show #t) Running this command displays the frame -;;send appears to be a command to be a procedure that takes a frame -;; followed by a command and a boolean. -;;the boolean is fed into the command in this case -;;if you said #f it would close the window -;;that is usefull -;;Below is a slight expantion on example code -;;letting the button be a toggle -(define frame2 (new frame%[label "Example2"])) -(define msg (new message% [parent frame2] [label " Nothing "])) -(define thingy #t) -(define button-to-click (new button% - [parent frame2] - [label "Click"] - [callback (lambda (button event) - (if thingy - (begin (set! thingy #f) - (send msg set-label "Something")) - (begin (set! thingy #t) - (send msg set-label " Nothing "))))])) -;;Frames are okay ish for error messages but the real stuff is -;;in canvas stuff -(define my-canvas% - (class canvas% - (define/override (on-event event) - (send msg set-label "Canvas mouse")) - (define/override (on-char event) - (send msg set-label "Canvas keyboard")) - (super-new)));;Don't know what that one means - -(define canvas-thing (new my-canvas% [parent frame2]));;unfortunately -;;we still need to re-size it manually -;;Now I wonder if we could create a procedure to make any text -;;appear -(define frame3 (new frame%[label "Example3"])) -(define blank (new message% [parent frame3] [label " "])) -(define (make-text string) (begin (send blank set-label string))) -;(send frame3 show #t) -;(make-text "Hello World") works exactly fine. -;;Now lets do something more complicated -;;We want to create a procedure that creates a new line -;;each time it is called so... -(define frame4 (new frame%[label "Example4"])) -;;now blank4 should be a procedure to create multiple lines in the frame -(define (make-text-line string) (begin (new message% - [parent frame4] - [label string]))) -;;display with -;;(send frame4 show #t) -;;add text with -;;(make-text-line "Hello World!") -;;This works for not but there are a few problems -;;first of all the window starts really small and doesn't restrict -;;resizing. Second it is always in the middle of the frame -;;Third, once text is on screen there is no way to get it off -;;But we can do better -(define frame5 (new frame% - [label "Example5"] - [width 300] - [height 300])) -(define canvas5 (new canvas% [parent frame5] - [paint-callback - (lambda (canvas dc) - (send dc set-scale 3 3) - (send dc set-text-foreground "blue") - (send dc draw-text "Don't Panic!" 0 0))])) -;;above is the example code to write some simple text, however -;;we can apply this to what we learned above to make something abit -;;more -(define frame6 (new frame% - [label "Example6"] - [width 600] - [height 700])) -(define (make-color-text string color) - (begin (new canvas% - [parent frame6] - [paint-callback - (lambda (canvas dc) - (send dc set-text-foreground color) - (send dc draw-text string 0 0 #f))]))) -;;display with -;;(send frame6 show #t) -;;write text with -;;(make-color-text "Hello World!" "purple") -;;Okay that doesn't exactly work as planned... -;;the problem with this is that each message is it's own canvas now -;;not only that but it means we can only print each line in it's -;;own color. So new plan is to make it so it adds on new strings -;;to one canvas, adding \n as nessessary. Except nevermind since -;;\n doesn't exist in this apparently - -;;Lets switch back to text and we can change it later -(define frame7 (new frame% - [label "Example7"] - [width 600] - [height 200])) -(define (make-blank-line i) - (new message% - [parent frame7] - [label " "])) -;;80 space characters -;;the i is only there to make the build-list command happy -(define Message-list (build-list 10 make-blank-line)) -;;10 make-blank-lines -;;that build-list command is super usefull for something like this -(define (move-down-list list) - (if (eq? '() (cdr list)) - '() - (begin - (move-down-list (cdr list)) - (send (car (cdr list)) set-label (send (car list) get-label))))) -(define (send-word string) - (begin - (move-down-list Message-list) - (send (car Message-list) set-label string))) -;;display with -;;(send frame7 show #t) -;;add text with -;;(send-word "Hello World") -;;Now using the send-word command I can make each word appear on the -;;screen in the place where it used to be. Starting at the top of the -;;screen and working it's way down the more text is added. -;;on the bottom line, after adding 10 lines of text, it will remove the bottom -;;most line \ No newline at end of file diff --git a/Hermes/client.rkt b/Hermes/client.rkt new file mode 100644 index 0000000..25be149 --- /dev/null +++ b/Hermes/client.rkt @@ -0,0 +1,102 @@ +#lang racket +(require math/base) ;; for random number generation + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them + +;; Notes connect to server on localhost +;; use client template of tcpvanilla +;; use event for read-write + +;; modify read-loop-i +; read a value and send it to server via output-port + +; is there something in the input port. If yes? display it +; in the hello world + +; make connection to server +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + (display in) + (displayln out) + ;; binds to multiple values akin to unpacking tuples in python + (display "What's your name?\n") + (define username (read-line)) + + ; (thread (lambda () + ;; make threads 2 lines + (define a (thread + (lambda () + (let loop [] + (receive-messages in) + (sleep 1) + (loop))))) + (define t (thread + (lambda () + (let loop [] + (send-messages username out) + (sleep 1) + (loop))))) + (thread-wait t) ;; returns prompt back to drracket + (close-input-port in) + (close-output-port out)) + (custodian-shutdown-all main-client-cust)) + + +;; the send-messages +(define (send-messages username out) + ;; intelligent read, quits when user types in "quit" + ;(semaphore-wait fair) + ; (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + ;; (cond ((string=? input "quit") (begin (kill-thread a) + ;(kill-thread t)))) + (cond ((string=? input "quit") (exit))) + ;; modify to send messages to out port + (displayln (string-append username ": " input) out) + (flush-output out) + + ;(semaphore-post fair) + ; (read-loop-i out) +) + + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (receive-messages in) + ; (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + (define evt (sync/timeout 30 (read-line-evt in))) + (cond [(eof-object? evt) + (displayln "Server connection closed") + (exit)] + [(string? evt) + (displayln evt)] ; could time stamp here or to send message + [else + (displayln (string-append "Nothing received from server for 2 minutes."))] + ) + ;(semaphore-post fair) +) + +(define stop (client 4321)) + diff --git a/Hermes/concurrentreadandprint.rkt b/Hermes/concurrentreadandprint.rkt new file mode 100644 index 0000000..f67f1dd --- /dev/null +++ b/Hermes/concurrentreadandprint.rkt @@ -0,0 +1,77 @@ +#lang racket +(require math/base) ;; for random number generation + + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt +(define fair (make-semaphore 1)) + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") diff --git a/Hermes/server.rkt b/Hermes/server.rkt new file mode 100644 index 0000000..d1f5a98 --- /dev/null +++ b/Hermes/server.rkt @@ -0,0 +1,140 @@ +#lang racket +(require math/base) ;; for random number generation + +;; globals +;; must control access via semaphore as listener thread or broadcast thread +;; might need to access it +(define connections '()) ;; maintains a list of open ports +;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) +(define connections-s (make-semaphore 1)) ;; control access to connections + +;; every 5 seconds run to broadcast top message in list +;; and remove it from list +(define messages-s (make-semaphore 1)) ;; control access to messages +(define messages '("hello, world!")) ;; stores a list of messages(strings) from currents + +(define threads-s (make-semaphore 1)) ;; control access to threads +;; lets keep thread descriptor values +(define threads '()) ;; stores a list of client serving threads as thread descriptor values + + + +;; + +;; This is a relay server making two clients communicate +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop) + ;; Create a thread whose job is to simply call broadcast iteratively + (thread (lambda () + (let loopb [] + (sleep 30) ;; wait 30 secs before beginning to broadcast + (broadcast) + (sleep 10) ;; sleep for 10 seconds between broadcasts + (loopb))))) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + ; discard request header + ; Discard the request header (up to blank line): + (regexp-match #rx"(\r\n|^)\r\n" in) + (semaphore-wait connections-s) + ;; keep track of open ports + (set! connections (append connections (list (list in out)))) + (semaphore-post connections-s) + + ; start a thread to deal with specific client and add descriptor value to the list of threads + (set! threads (append threads (list (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out)))) + ) + ) + ;; Watcher thread: + ;; kills current thread for waiting too long for connection from + ;; clients + (thread (lambda () + (sleep 360) + (custodian-shutdown-all cust))))) + +; (define (handle connections) +; ()) +;; each thread needs 2 new threads +(define (handle in out) + ; define function to deal with incoming messages from client + (define (something-to-say in) + (define evt-t0 (sync/timeout 30 (read-line-evt in 'linefeed))) + (cond [(eof-object? evt-t0) + (displayln (string-append "Connection closed " (current-thread) "exiting")) + (exit) + ] + [(string? evt-t0) + (semaphore-wait messages-s) + ; append the message to list of messages + (display (string-append evt-t0 "\n")) + (set! messages (append messages (list evt-t0))) + (semaphore-post messages-s)] + [else + (displayln (string-append "Nothing received from " (current-thread)))])) + + + ; define function to deal with out + (define (something-to-send out) + (define evt-t1 (sync/timeout 120 (thread-receive-evt))) + ;; send message to client + (fprintf out "~a~n" (thread-receive)) + (flush-output out) + ) + ; thread them each + + ;; i could bind to values, and call wait on them + ;; thread that deals with incoming messages for that particular thread + (thread (lambda () + (let loop [] + (something-to-say in) + (sleep 1) + (loop)))) + + (thread (lambda () + (let loop [] + (something-to-send out) + (sleep 1) + (loop)))) + ; (server-loop in out) + ; (sleep 5) ;; wait 5 seconds to guarantee client has already send message + 'ok + ) + +;; define a broadcast function +(define broadcast + (lambda () + (semaphore-wait messages-s) + (semaphore-wait threads-s) + (if (not (null? messages)) + (begin (map (lambda (thread-descriptor) + (thread-send thread-descriptor (first messages))) + threads) + (set! messages (rest messages)) + ) + (display "No message to display\n") ; for later create file port for errors and save error messages to that file + ) + (semaphore-post threads-s) + (semaphore-post messages-s))) + +(define stop (serve 4321)) ;; start server then close with stop \ No newline at end of file diff --git a/Hermes/tcpcommunication.rkt b/Hermes/tcpcommunication.rkt new file mode 100644 index 0000000..27a5151 --- /dev/null +++ b/Hermes/tcpcommunication.rkt @@ -0,0 +1,57 @@ +#lang racket +(require math/base) ;; for random number generation + +(define listener (tcp-listen 4326 5 #t)) +(define a (thread (lambda () + (define-values (s-in s-out) (tcp-accept listener)) + ; Discard the request header (up to blank line): + ;(regexp-match #rx"(\r\n|^)\r\n" s-in) + (sleep 10) + (define (echo) + (define input (read-line s-in)) + (displayln input s-out) + (flush-output s-out) + (if (eof-object? input) + (displayln "Done talking\n") + (echo))) + (echo) + (close-input-port s-in) + (close-output-port s-out) + (tcp-close listener) + 'ok))) + +(define t (thread (lambda () + (define-values (c-in c-out) (tcp-connect "localhost" 4326)) + (define input-prompt "input: ") + (define output-prompt "output: ") + + ;; prompt for username and bind to a variable username + (display "What's your name?\n") + (define username (read-line)) + (define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + (define fair (make-semaphore 1)) + + ;; intelligent read, quits when user types in "quit" + (define (read-loop-i) + ;(semaphore-wait fair) + ; (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (exit))) + (display (string-append output-prompt input "\n") c-out) + (flush-output c-out) + (displayln (read-line c-in)) ;; server echoes back sent input + ;(semaphore-post fair) + (read-loop-i) + ) + (read-loop-i) + 'ok))) + +;(kill-thread a) +;(kill-thread t) +(thread-wait t) +(display "DONE!!\n") + diff --git a/README.md b/README.md index 4b247b0..2807b00 100644 --- a/README.md +++ b/README.md @@ -72,11 +72,11 @@ satisfactorily we would have met our goals. ## Architecture Diagram #### Preliminary design -![Architecture](https://github.com/oplS17projects/Hermes/blob/master/arch_diagram.png) +![Architecture](https://github.com/oplS17projects/Hermes/blob/master/ext/arch_diagram.png) #### The Game plan -![Diagram](https://github.com/oplS17projects/Hermes/blob/master/architecture_diagram.png) +![Diagram](https://github.com/oplS17projects/Hermes/blob/master/ext/architecture_diagram.png) ## Schedule diff --git a/arch_diagram.png b/arch_diagram.png deleted file mode 100644 index 6bb8803..0000000 Binary files a/arch_diagram.png and /dev/null differ diff --git a/architecture_diagram.png b/architecture_diagram.png deleted file mode 100644 index 1949ae0..0000000 Binary files a/architecture_diagram.png and /dev/null differ diff --git a/client.rkt b/client.rkt deleted file mode 100644 index 25be149..0000000 --- a/client.rkt +++ /dev/null @@ -1,102 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them - -;; Notes connect to server on localhost -;; use client template of tcpvanilla -;; use event for read-write - -;; modify read-loop-i -; read a value and send it to server via output-port - -; is there something in the input port. If yes? display it -; in the hello world - -; make connection to server -(define (client port-no) - (define main-client-cust (make-custodian)) - (parameterize ([current-custodian main-client-cust]) - ;; connect to server at port 8080 - (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values - (display in) - (displayln out) - ;; binds to multiple values akin to unpacking tuples in python - (display "What's your name?\n") - (define username (read-line)) - - ; (thread (lambda () - ;; make threads 2 lines - (define a (thread - (lambda () - (let loop [] - (receive-messages in) - (sleep 1) - (loop))))) - (define t (thread - (lambda () - (let loop [] - (send-messages username out) - (sleep 1) - (loop))))) - (thread-wait t) ;; returns prompt back to drracket - (close-input-port in) - (close-output-port out)) - (custodian-shutdown-all main-client-cust)) - - -;; the send-messages -(define (send-messages username out) - ;; intelligent read, quits when user types in "quit" - ;(semaphore-wait fair) - ; (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - ;; (cond ((string=? input "quit") (begin (kill-thread a) - ;(kill-thread t)))) - (cond ((string=? input "quit") (exit))) - ;; modify to send messages to out port - (displayln (string-append username ": " input) out) - (flush-output out) - - ;(semaphore-post fair) - ; (read-loop-i out) -) - - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (receive-messages in) - ; (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - (define evt (sync/timeout 30 (read-line-evt in))) - (cond [(eof-object? evt) - (displayln "Server connection closed") - (exit)] - [(string? evt) - (displayln evt)] ; could time stamp here or to send message - [else - (displayln (string-append "Nothing received from server for 2 minutes."))] - ) - ;(semaphore-post fair) -) - -(define stop (client 4321)) - diff --git a/concurrentreadandprint.rkt b/concurrentreadandprint.rkt deleted file mode 100644 index f67f1dd..0000000 --- a/concurrentreadandprint.rkt +++ /dev/null @@ -1,77 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them -(define (read-loop) - (display (read-line)) - (display "\n") - (read-loop) - ) - -(define input-prompt "input: ") -(define output-prompt "output: ") - -;; prompt for username and bind to a variable username -(display "What's your name?\n") -(define username (read-line)) -(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt -(define fair (make-semaphore 1)) - -;; intelligent read, quits when user types in "quit" -(define (read-loop-i) - - - ;(semaphore-wait fair) - (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (begin (kill-thread a) - (kill-thread t)))) - (display (string-append output-prompt input "\n")) - ;(semaphore-post fair) - (read-loop-i) - ) - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (hello-world) - (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - ;; at this time we simulate the input from different users - (define what-to-print (random-integer 0 2)) - (if (= what-to-print 0) - (display "Doug: What's up, up?\n") - (display "Fred: Looking good, good!\n")) - ;(semaphore-post fair) - (hello-world)) - -(define t (thread (lambda () - (read-loop-i)))) -(define a (thread (lambda () - (hello-world)))) - -(thread-wait t) ;; returns prompt back to drracket -;; below doesn't execute -; (sleep 10) -; (kill-thread t) -; (define a (thread (display "hello world!\n"))) -; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") diff --git a/crpovertcp.rkt b/crpovertcp.rkt deleted file mode 100644 index 57874a8..0000000 --- a/crpovertcp.rkt +++ /dev/null @@ -1,155 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -;; globals -;; must control access via semaphore as listener thread or broadcast thread -;; might need to access it -(define connections '()) ;; maintains a list of open ports -;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) - -;; lets keep thread descriptor values -; - -(define fair (make-semaphore 1)) ;; managing connections above - -(define can-i-broadcast (make-semaphore 1)) - - -;; - -;; This is a relay server making two clients communicate -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (serve 8080)) -;; (stop) to close the server - -(define (serve port-no) - (define main-cust (make-custodian)) - (parameterize ([current-custodian main-cust]) - (define listener (tcp-listen port-no 5 #t)) - (define (loop) - (accept-and-handle listener) - (loop)) - (thread loop)) - (lambda () - (displayln "\nGoodbye, shutting down all services\n") - (custodian-shutdown-all main-cust))) - -(define (accept-and-handle listener) - (define cust (make-custodian)) - (parameterize ([current-custodian cust]) - (define-values (in out) (tcp-accept listener)) - (semaphore-wait fair) - ;; keep track of open ports - (append connections (list (list in out))) - (semaphore-wait fiar) - - ; thread will communicate to all clients at once in a broadcast - ; manner - (thread (lambda () - (handle in out) ;; this handles connection with that specific client - (close-input-port in) - (close-output-port out))) - ) - ;; Watcher thread: - ;; kills current thread for waiting too long for connection from - ;; clients - (thread (lambda () - (sleep 120) - (custodian-shutdown-all cust)))) - -; (define (handle connections) -; ()) -;; each thread needs 2 new threads -(define (handle in out) - ; define function to deal with in - (define (something-to-say in) - (sync/timeout 4 (read-line-evt in 'linefeed))) - ; define function to deal with out - ; thread them each - ; (server-loop in out) - (sleep 5) ;; wait 5 seconds to guarantee client has already send message - (define echo (read-line in)) ;; bind message to echo - (displayln (string-append echo "\n")) - ; echo back the message, appending echo - ; could regex match the input to extract the name - (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back - (flush-output out) -) -;; This is a single server communicating directly to the client -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -;; author: Ibrahim Mkusa -;; about: print and read concurrently -;; notes: output may need to be aligned and formatted nicely -;; look into -;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 - -;; create custodian for managing all resources -;; so we can shutdown everything at once -;(define guard (make-custodian (current-custodian))) -;(current-custodian guard) -;; reads values continously from stdin and redisplays them -(define (read-loop) - (display (read-line)) - (display "\n") - (read-loop) - ) - -(define input-prompt "input: ") -(define output-prompt "output: ") - -;; prompt for username and bind to a variable username -(display "What's your name?\n") -(define username (read-line)) -(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt - -;; intelligent read, quits when user types in "quit" -(define (read-loop-i) - - - ;(semaphore-wait fair) - (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (begin (kill-thread a) - (kill-thread t)))) - (display (string-append output-prompt input "\n")) - ;(semaphore-post fair) - (read-loop-i) - ) - - -;; print hello world continously -;; "(hello-world)" can be executed as part of background thread -;; that prints in the event there is something in the input port -(define (hello-world) - (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms - ;; with server - ;(semaphore-wait fair) - ;; we will retrieve the line printed below from the server - ;; at this time we simulate the input from different users - (define what-to-print (random-integer 0 2)) - (if (= what-to-print 0) - (display "Doug: What's up, up?\n") - (display "Fred: Looking good, good!\n")) - ;(semaphore-post fair) - (hello-world)) - -(define t (thread (lambda () - (read-loop-i)))) -(define a (thread (lambda () - (hello-world)))) - -(thread-wait t) ;; returns prompt back to drracket -;; below doesn't execute -; (sleep 10) -; (kill-thread t) -; (define a (thread (display "hello world!\n"))) -; (display "John: hello soso\n") -; (display "Emmanuel: cumbaya!!!!\n") diff --git a/docs/FP4-instructions.md b/docs/FP4-instructions.md new file mode 100644 index 0000000..6a04e91 --- /dev/null +++ b/docs/FP4-instructions.md @@ -0,0 +1,93 @@ +# FP4-proposal + +**do not fork this** there are different directions + +## tl;dr + +1. Create a repository in [our organization][oplorg] for your project; add your teammate(s) as collaborators +2. Copy-paste this [template file](template.md) as the `README.md` file in your new repo; edit to become project plan +3. Make 3-slide slide show to be presented in class; insert into [class desk][gslides] +4. Enter project details into a new [Google form][projform] +5. Make a 0.1 release of your project (tagging `@fgmart`) + +## Due Date +* Sun Apr 2, 2017 at 11p + +## Instructions + +Teams will submit a single proposal, with sections that each member has done individually detailing their proposed contributions. The submission will be the `README.md` file in your brand-new project repository, which you'll make. + +You must start using GitHub collaboratively from this point forward. + +Instructions: + +1. Create a new repository for your project as part of [our organization][oplorg] + * Give it a name that you like—it may be your real names, usernames, or project name + * Add your teammates as collaborators (Settings > Collaborators & Teams > Add Collaborator) +2. Copy the content from the [template file](template.md) into your `README.md` + * Click the “Raw” button on the `template.md` file and then copy-paste into your repo's `README.md` edit view + * Save it + * *Then start editing it to become your actual proposal* +3. Everyone on the team contributes their sections to your `README.md` file. + * Use GitHub's collaboration features to make sure that each team member contributes meaningful content to the file + * At the absolute minimum, respective team members must have commits that show they have authored the section describing their planned contributions +4. Create a [github Release](https://help.github.com/articles/creating-releases/) of your repository. + * Version: v0.1 + * Title: Proposal + * Description: tag `@fgmart` + +And now some detail on what to write _in_ the report. + +**Overall guidance:** *You should be proposing something that you have high confidence that you can achieve, and the proposal should project that confidence.* + +The proposal should be no longer than necessary, but long enough to include critical detail. Diagrams are welcome. + +Remember, you can do some neat [formatting things with Markdown.][markdown] + +In case you missed it, here again is the [template file](template.md) + +## In-Class Presentation +Teams will each deliver an in-class presentation. Your team will have two minutes to present. + +The presentation shall have exactly three slides: + +1. Title + * project title (10 words or fewer) + * your real names + * each real name followed by GitHub username + * a relevant image of some sort (optional) +2. Overview + * a few short phrases describing the project + * a different relevant image (optional) +3. Architecture Diagram + * visual diagram showing the major components of the project + * include external things that your project will connect to + * include arrows showing flow of information + * internal components annotated with Racket libraries that they will use + * _important:_ annotate each block with the GH username of the person who is primarily responsible for its creation + +Make the slides in [Google Slides][gslides]. + +Then, import your deck into the [slide deck][martinslides]. You have write privileges based on your membership in the class forum. + +You and your teammates will give the presentation in class the day that this assignment is due. + +## Fill out Project Information Form + +Enter project details into a new [Google form][projform]. + +**This is absolutely necessary so I can keep track of all of the projects.** + +## Grading +The proposal must be submitted on time to receive credit. Late submissions will not be accepted for credit. + +You personally must be present in class (and participate in the presentation when it is your turn) to receive credit for the presentation. If your teammates are there and you are not, they will receive presentation credit and you will not. + + + +[forum]: https://groups.google.com/forum/#!forum/uml-opl-spr17 +[markdown]: https://help.github.com/articles/markdown-basics/ +[gslides]:https://slides.google.com +[martinslides]:https://docs.google.com/presentation/d/1fzNX4nV4z6IkLiVBMB0YD4CctlJxR9pWXSbYTOFcQvc +[projform]:https://goo.gl/forms/Gfh9hWBgvg323j6M2 +[oplorg]:https://github.com/oplS17projects/ diff --git a/ext/arch_diagram.png b/ext/arch_diagram.png new file mode 100644 index 0000000..6bb8803 Binary files /dev/null and b/ext/arch_diagram.png differ diff --git a/ext/architecture_diagram.png b/ext/architecture_diagram.png new file mode 100644 index 0000000..1949ae0 Binary files /dev/null and b/ext/architecture_diagram.png differ diff --git a/feasibility_analysis/gui/windows.rkt b/feasibility_analysis/gui/windows.rkt deleted file mode 100644 index 4524673..0000000 --- a/feasibility_analysis/gui/windows.rkt +++ /dev/null @@ -1,9 +0,0 @@ -#lang racket - -(require racket/gui/base) - -;; Create a new window via the frame class -(define frame (new frame% [label "Example"])) - -;; Show frame(window) by calling it show method -(send frame show #t) ;; you call object methods via send diff --git a/feasibility_analysis/gui/windows2.rkt b/feasibility_analysis/gui/windows2.rkt deleted file mode 100644 index 3f60c80..0000000 --- a/feasibility_analysis/gui/windows2.rkt +++ /dev/null @@ -1,15 +0,0 @@ -#lang racket - -(require racket/gui/base) - -(define frame (new frame% - [label "Example"] - [width 300] - [height 300])) -(new canvas% [parent frame] - [paint-callback - (lambda (canvas dc) - (send dc set-scale 3 3) - (send dc set-text-foreground "blue") - (send dc draw-text "Don't Panic!" 0 0))]) -(send frame show #t) diff --git a/feasibility_analysis/tcpevents/README.md b/feasibility_analysis/tcpevents/README.md deleted file mode 100644 index 7c3ec21..0000000 --- a/feasibility_analysis/tcpevents/README.md +++ /dev/null @@ -1 +0,0 @@ -TCP communication racket concepts of events. For more see the racket guide. diff --git a/feasibility_analysis/tcpevents/server.rkt b/feasibility_analysis/tcpevents/server.rkt deleted file mode 100644 index 4313bda..0000000 --- a/feasibility_analysis/tcpevents/server.rkt +++ /dev/null @@ -1,39 +0,0 @@ -#lang racket - -(define (serve in-port out-port) - (let loop [] - (define evt (sync/timeout 2 - (read-line-evt in-port 'any) - (thread-receive-evt))) - (cond - [(not evt) - (displayln "Timed out, exiting") - (tcp-abandon-port in-port) - (tcp-abandon-port out-port)] - [(string? evt) - (fprintf out-port "~a~n" evt) - (flush-output out-port) - (loop)] - [else - (printf "Received a message in mailbox: ~a~n" - (thread-receive)) - (loop)]))) - -(define port-num 4321) -(define (start-server) - (define listener (tcp-listen port-num)) - (thread - (lambda () - (define-values [in-port out-port] (tcp-accept listener)) - (serve in-port out-port)))) - -(start-server) - -(define client-thread - (thread - (lambda () - (define-values [in-port out-port] (tcp-connect "localhost" port-num)) - (display "first\nsecond\nthird\n" out-port) - (flush-output out-port) - ; copy-port will block until EOF is read from in-port - (copy-port in-port (current-output-port))))) diff --git a/feasibility_analysis/tcpvanilla/README.md b/feasibility_analysis/tcpvanilla/README.md deleted file mode 100644 index b8e2883..0000000 --- a/feasibility_analysis/tcpvanilla/README.md +++ /dev/null @@ -1,20 +0,0 @@ -a simple experiment on communication via tcp ports - -a server runs continously servicing clients. Clients connect, send a message, and -server replies with a message. Message should appear in each separate REPL area -prompt - -run server.rkt in a REPL -``` -,en server.rkt -(define stop (serve 8080)) ;; starts serve listening at port 8080 -(stop) ;; to stop server and free the ports - -``` - -run client.rkt in a separate REPL -``` -,en client.rkt -(define stop (client 8080)) ;; starts client talking to server at port 8080 - -``` diff --git a/feasibility_analysis/tcpvanilla/client.rkt b/feasibility_analysis/tcpvanilla/client.rkt deleted file mode 100644 index 967d2b9..0000000 --- a/feasibility_analysis/tcpvanilla/client.rkt +++ /dev/null @@ -1,72 +0,0 @@ -#lang racket - -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (client 8080)) -;; use your web browser to connect localhost:8080 greeted with "hello world" -;; (stop) to close the server - -(define (client port-no) - (define main-client-cust (make-custodian)) - (parameterize ([current-custodian main-client-cust]) - ;; connect to server at port 8080 - (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values - ;; binds to multiple values akin to unpacking tuples in python - ; (thread (lambda () - (chat in out) - (close-input-port in) - (close-output-port out)) - (custodian-shutdown-all main-client-cust)) - - ; (sleep 60) ;; run for 3 minutes then close - ; (define (loop) - ; (write (read-line (current-input-port)) out) - ; (flush-output out) - ; (write (read-line in) (current-output-port)) - ; (define listener (tcp-listen port-no 5 #t)) - ; (define (loop) - ; (accept-and-handle listener) - ; (loop)) - ; (thread loop))) - ; (custodian-shutdown-all main-client-cust) - #| (lambda () |# - ; (displayln "Goodbye, shutting down client\n") - #| (custodian-shutdown-all main-client-cust)) |# - -(define (chat in out) - ; (driver-loop in out) - (writeln "Ibrahim: Hello, anyone in chat?" out) - (flush-output out) ;; ports are buffered in racket must flush or you - ;; will read #eof - (sleep 10) ;; wait 10 seconds - (define serv-message (read-line in)) - (displayln serv-message) ;; read the servers replay message which is original - ;; with echo appended to it - ) - -; (define input-prompt "Hermes: ") - -(define (driver-loop in out) - ; (prompt-for-input input-prompt) - (display ">>> ") - (define input (read)) - (writeln (string-append "Ibrahim: " input) out) - (flush-output out) - ; (sleep 10) - (define output (read-line in)) - (displayln output) - (driver-loop in out)) - - -#| (let ((input (read))) |# -; ) -; (let ((input (read))) -; (let ((output (mc-eval input the-global-environment))) -; (announce-output output-prompt) -; (user-print output))) -; (driver-loop)) -; -; (define (announce-output string) -; (display string)) -#| |# diff --git a/feasibility_analysis/tcpvanilla/client2.rkt b/feasibility_analysis/tcpvanilla/client2.rkt deleted file mode 100644 index 47e3052..0000000 --- a/feasibility_analysis/tcpvanilla/client2.rkt +++ /dev/null @@ -1,43 +0,0 @@ -#lang racket - -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (client 8080)) -;; use your web browser to connect localhost:8080 greeted with "hello world" -;; (stop) to close the server - -(define (client port-no) - (define main-client-cust (make-custodian)) - (parameterize ([current-custodian main-client-cust]) - ;; connect to server at port 8080 - (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values - ;; binds to multiple values akin to unpacking tuples in python - (thread (lambda () - (send-message in out) - (close-input-port in) - (close-output-port out)))) - (sleep 20) - ; (define (loop) - ; (write (read-line (current-input-port)) out) - ; (flush-output out) - ; (write (read-line in) (current-output-port)) - ; (define listener (tcp-listen port-no 5 #t)) - ; (define (loop) - ; (accept-and-handle listener) - ; (loop)) - ; (thread loop))) - (custodian-shutdown-all main-client-cust) - #| (lambda () |# - ; (displayln "Goodbye, shutting down client\n") - #| (custodian-shutdown-all main-client-cust)) |#) - -(define (send-message input-port output-port) - (writeln "Doug: Hello, how's it going?" output-port) - (flush-output output-port) ;; ports are buffered in racket must flush or you - ;; will read #eof - (sleep 10) ;; wait 10 seconds - (define serv-message (read-line input-port)) - (displayln serv-message) ;; read the servers replay message which is original - ;; with echo appended to it - ) diff --git a/feasibility_analysis/tcpvanilla/server.rkt b/feasibility_analysis/tcpvanilla/server.rkt deleted file mode 100644 index bf72aff..0000000 --- a/feasibility_analysis/tcpvanilla/server.rkt +++ /dev/null @@ -1,58 +0,0 @@ -#lang racket - -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (serve 8080)) -;; use your web browser to connect localhost:8080 greeted with "hello world" -;; (stop) to close the server - -(define (serve port-no) - (define main-cust (make-custodian)) - (parameterize ([current-custodian main-cust]) - (define listener (tcp-listen port-no 5 #t)) - (define (loop) - (accept-and-handle listener) - (loop)) - (thread loop)) - (lambda () - (displayln "\nGoodbye, shutting down all services\n") - (custodian-shutdown-all main-cust))) - -(define (accept-and-handle listener) - (define cust (make-custodian)) - (parameterize ([current-custodian cust]) - (define-values (in out) (tcp-accept listener)) - (thread (lambda () - (handle in out) ;; this handles connection with that specific client - (close-input-port in) - (close-output-port out)))) - ;; Watcher thread: - (thread (lambda () - (sleep 120) - (custodian-shutdown-all cust)))) - -(define (handle in out) - ; (server-loop in out) - (sleep 5) ;; wait 5 seconds to guarantee client has already send message - (define echo (read-line in)) ;; bind message to echo - (displayln (string-append echo "\n")) - ; echo back the message, appending echo - ; could regex match the input to extract the name - (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back - (flush-output out) -) - -(define input-prompt "Hermes: ") - -(define (server-loop in out) - (define echo (read-line in)) - (displayln echo) - (display ">>> ") - - (define input (read)) - (writeln (string-append "Admin: " input) out) - (flush-output out) - ; (sleep 10) - (server-loop in out)) - diff --git a/feasibility_analysis/tcpvanilla/tcptalk.rkt b/feasibility_analysis/tcpvanilla/tcptalk.rkt deleted file mode 100644 index d069851..0000000 --- a/feasibility_analysis/tcpvanilla/tcptalk.rkt +++ /dev/null @@ -1,30 +0,0 @@ -#lang racket - -(define listener (tcp-listen 8083 5 #t)) ;; listener to service connection requests -;; client attempts to connect. Receives an input and output port -(define-values (client-in client-out) (tcp-connect "localhost" 8083)) -;; server accepts the connection request. Also gets a pair of ports -(define-values (server-in server-out) (tcp-accept listener)) - -;; client sends identifying message -(display (string-append "Client:My name is " "Ibrahim" "\n") - client-out) -(flush-output client-out) ;; must flush as ports are buffered in racket - -;; server receives and reads it -;; cooler if on separate racket instances -(read-line server-in) ;; --> "Client:My name is #hostname. -;; server replies -(display (string-append "Server:Hi " "Ibrahim" "\n") server-out) -(flush-output server-out) ;; flush flush - -;; client displays server message -(read-line client-in) -(close-output-port server-out) -(close-output-port client-out) -(read-line client-in) ;; --> eof object #eof -(read-line server-in) ;; --> eof object #eof -(tcp-close listener) -; (custodian-shutdown-all (current-custodian)) ;; release all resources including - ;; tcp, file, custom ports - ;; application exits diff --git a/server.rkt b/server.rkt deleted file mode 100644 index d1f5a98..0000000 --- a/server.rkt +++ /dev/null @@ -1,140 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -;; globals -;; must control access via semaphore as listener thread or broadcast thread -;; might need to access it -(define connections '()) ;; maintains a list of open ports -;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) -(define connections-s (make-semaphore 1)) ;; control access to connections - -;; every 5 seconds run to broadcast top message in list -;; and remove it from list -(define messages-s (make-semaphore 1)) ;; control access to messages -(define messages '("hello, world!")) ;; stores a list of messages(strings) from currents - -(define threads-s (make-semaphore 1)) ;; control access to threads -;; lets keep thread descriptor values -(define threads '()) ;; stores a list of client serving threads as thread descriptor values - - - -;; - -;; This is a relay server making two clients communicate -;; Both `server' and `accept-and-handle' change -;; to use a custodian. -;; To start server -;; (define stop (serve 8080)) -;; (stop) to close the server - -(define (serve port-no) - (define main-cust (make-custodian)) - (parameterize ([current-custodian main-cust]) - (define listener (tcp-listen port-no 5 #t)) - (define (loop) - (accept-and-handle listener) - (loop)) - (thread loop) - ;; Create a thread whose job is to simply call broadcast iteratively - (thread (lambda () - (let loopb [] - (sleep 30) ;; wait 30 secs before beginning to broadcast - (broadcast) - (sleep 10) ;; sleep for 10 seconds between broadcasts - (loopb))))) - (lambda () - (displayln "\nGoodbye, shutting down all services\n") - (custodian-shutdown-all main-cust))) - -(define (accept-and-handle listener) - (define cust (make-custodian)) - (parameterize ([current-custodian cust]) - (define-values (in out) (tcp-accept listener)) - ; discard request header - ; Discard the request header (up to blank line): - (regexp-match #rx"(\r\n|^)\r\n" in) - (semaphore-wait connections-s) - ;; keep track of open ports - (set! connections (append connections (list (list in out)))) - (semaphore-post connections-s) - - ; start a thread to deal with specific client and add descriptor value to the list of threads - (set! threads (append threads (list (thread (lambda () - (handle in out) ;; this handles connection with that specific client - (close-input-port in) - (close-output-port out)))) - ) - ) - ;; Watcher thread: - ;; kills current thread for waiting too long for connection from - ;; clients - (thread (lambda () - (sleep 360) - (custodian-shutdown-all cust))))) - -; (define (handle connections) -; ()) -;; each thread needs 2 new threads -(define (handle in out) - ; define function to deal with incoming messages from client - (define (something-to-say in) - (define evt-t0 (sync/timeout 30 (read-line-evt in 'linefeed))) - (cond [(eof-object? evt-t0) - (displayln (string-append "Connection closed " (current-thread) "exiting")) - (exit) - ] - [(string? evt-t0) - (semaphore-wait messages-s) - ; append the message to list of messages - (display (string-append evt-t0 "\n")) - (set! messages (append messages (list evt-t0))) - (semaphore-post messages-s)] - [else - (displayln (string-append "Nothing received from " (current-thread)))])) - - - ; define function to deal with out - (define (something-to-send out) - (define evt-t1 (sync/timeout 120 (thread-receive-evt))) - ;; send message to client - (fprintf out "~a~n" (thread-receive)) - (flush-output out) - ) - ; thread them each - - ;; i could bind to values, and call wait on them - ;; thread that deals with incoming messages for that particular thread - (thread (lambda () - (let loop [] - (something-to-say in) - (sleep 1) - (loop)))) - - (thread (lambda () - (let loop [] - (something-to-send out) - (sleep 1) - (loop)))) - ; (server-loop in out) - ; (sleep 5) ;; wait 5 seconds to guarantee client has already send message - 'ok - ) - -;; define a broadcast function -(define broadcast - (lambda () - (semaphore-wait messages-s) - (semaphore-wait threads-s) - (if (not (null? messages)) - (begin (map (lambda (thread-descriptor) - (thread-send thread-descriptor (first messages))) - threads) - (set! messages (rest messages)) - ) - (display "No message to display\n") ; for later create file port for errors and save error messages to that file - ) - (semaphore-post threads-s) - (semaphore-post messages-s))) - -(define stop (serve 4321)) ;; start server then close with stop \ No newline at end of file diff --git a/tcpcommunication.rkt b/tcpcommunication.rkt deleted file mode 100644 index 27a5151..0000000 --- a/tcpcommunication.rkt +++ /dev/null @@ -1,57 +0,0 @@ -#lang racket -(require math/base) ;; for random number generation - -(define listener (tcp-listen 4326 5 #t)) -(define a (thread (lambda () - (define-values (s-in s-out) (tcp-accept listener)) - ; Discard the request header (up to blank line): - ;(regexp-match #rx"(\r\n|^)\r\n" s-in) - (sleep 10) - (define (echo) - (define input (read-line s-in)) - (displayln input s-out) - (flush-output s-out) - (if (eof-object? input) - (displayln "Done talking\n") - (echo))) - (echo) - (close-input-port s-in) - (close-output-port s-out) - (tcp-close listener) - 'ok))) - -(define t (thread (lambda () - (define-values (c-in c-out) (tcp-connect "localhost" 4326)) - (define input-prompt "input: ") - (define output-prompt "output: ") - - ;; prompt for username and bind to a variable username - (display "What's your name?\n") - (define username (read-line)) - (define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt - (define fair (make-semaphore 1)) - - ;; intelligent read, quits when user types in "quit" - (define (read-loop-i) - ;(semaphore-wait fair) - ; (display usernamei) - (define input (read-line)) - ;; do something over here with input maybe send it out - - ;; Tests input if its a quit then kills all threads - ;; An if would be better here tbh - (cond ((string=? input "quit") (exit))) - (display (string-append output-prompt input "\n") c-out) - (flush-output c-out) - (displayln (read-line c-in)) ;; server echoes back sent input - ;(semaphore-post fair) - (read-loop-i) - ) - (read-loop-i) - 'ok))) - -;(kill-thread a) -;(kill-thread t) -(thread-wait t) -(display "DONE!!\n") - diff --git a/tests/gui/Gui_Exploration.rkt b/tests/gui/Gui_Exploration.rkt new file mode 100644 index 0000000..ff4d2d3 --- /dev/null +++ b/tests/gui/Gui_Exploration.rkt @@ -0,0 +1,129 @@ +#lang racket +(require racket/gui/base) +;;Step 1. Create a window to draw into +(define frame(new frame% [label "Example"])) +;;I don't know what frame% means, but new must be a procedure +;;(send frame show #t) Running this command displays the frame +;;send appears to be a command to be a procedure that takes a frame +;; followed by a command and a boolean. +;;the boolean is fed into the command in this case +;;if you said #f it would close the window +;;that is usefull +;;Below is a slight expantion on example code +;;letting the button be a toggle +(define frame2 (new frame%[label "Example2"])) +(define msg (new message% [parent frame2] [label " Nothing "])) +(define thingy #t) +(define button-to-click (new button% + [parent frame2] + [label "Click"] + [callback (lambda (button event) + (if thingy + (begin (set! thingy #f) + (send msg set-label "Something")) + (begin (set! thingy #t) + (send msg set-label " Nothing "))))])) +;;Frames are okay ish for error messages but the real stuff is +;;in canvas stuff +(define my-canvas% + (class canvas% + (define/override (on-event event) + (send msg set-label "Canvas mouse")) + (define/override (on-char event) + (send msg set-label "Canvas keyboard")) + (super-new)));;Don't know what that one means + +(define canvas-thing (new my-canvas% [parent frame2]));;unfortunately +;;we still need to re-size it manually +;;Now I wonder if we could create a procedure to make any text +;;appear +(define frame3 (new frame%[label "Example3"])) +(define blank (new message% [parent frame3] [label " "])) +(define (make-text string) (begin (send blank set-label string))) +;(send frame3 show #t) +;(make-text "Hello World") works exactly fine. +;;Now lets do something more complicated +;;We want to create a procedure that creates a new line +;;each time it is called so... +(define frame4 (new frame%[label "Example4"])) +;;now blank4 should be a procedure to create multiple lines in the frame +(define (make-text-line string) (begin (new message% + [parent frame4] + [label string]))) +;;display with +;;(send frame4 show #t) +;;add text with +;;(make-text-line "Hello World!") +;;This works for not but there are a few problems +;;first of all the window starts really small and doesn't restrict +;;resizing. Second it is always in the middle of the frame +;;Third, once text is on screen there is no way to get it off +;;But we can do better +(define frame5 (new frame% + [label "Example5"] + [width 300] + [height 300])) +(define canvas5 (new canvas% [parent frame5] + [paint-callback + (lambda (canvas dc) + (send dc set-scale 3 3) + (send dc set-text-foreground "blue") + (send dc draw-text "Don't Panic!" 0 0))])) +;;above is the example code to write some simple text, however +;;we can apply this to what we learned above to make something abit +;;more +(define frame6 (new frame% + [label "Example6"] + [width 600] + [height 700])) +(define (make-color-text string color) + (begin (new canvas% + [parent frame6] + [paint-callback + (lambda (canvas dc) + (send dc set-text-foreground color) + (send dc draw-text string 0 0 #f))]))) +;;display with +;;(send frame6 show #t) +;;write text with +;;(make-color-text "Hello World!" "purple") +;;Okay that doesn't exactly work as planned... +;;the problem with this is that each message is it's own canvas now +;;not only that but it means we can only print each line in it's +;;own color. So new plan is to make it so it adds on new strings +;;to one canvas, adding \n as nessessary. Except nevermind since +;;\n doesn't exist in this apparently + +;;Lets switch back to text and we can change it later +(define frame7 (new frame% + [label "Example7"] + [width 600] + [height 200])) +(define (make-blank-line i) + (new message% + [parent frame7] + [label " "])) +;;80 space characters +;;the i is only there to make the build-list command happy +(define Message-list (build-list 10 make-blank-line)) +;;10 make-blank-lines +;;that build-list command is super usefull for something like this +(define (move-down-list list) + (if (eq? '() (cdr list)) + '() + (begin + (move-down-list (cdr list)) + (send (car (cdr list)) set-label (send (car list) get-label))))) +(define (send-word string) + (begin + (move-down-list Message-list) + (send (car Message-list) set-label string))) +;;display with +;;(send frame7 show #t) +;;add text with +;;(send-word "Hello World") +;;Now using the send-word command I can make each word appear on the +;;screen in the place where it used to be. Starting at the top of the +;;screen and working it's way down the more text is added. +;;on the bottom line, after adding 10 lines of text, it will remove the bottom +;;most line \ No newline at end of file diff --git a/tests/gui/windows.rkt b/tests/gui/windows.rkt new file mode 100644 index 0000000..4524673 --- /dev/null +++ b/tests/gui/windows.rkt @@ -0,0 +1,9 @@ +#lang racket + +(require racket/gui/base) + +;; Create a new window via the frame class +(define frame (new frame% [label "Example"])) + +;; Show frame(window) by calling it show method +(send frame show #t) ;; you call object methods via send diff --git a/tests/gui/windows2.rkt b/tests/gui/windows2.rkt new file mode 100644 index 0000000..3f60c80 --- /dev/null +++ b/tests/gui/windows2.rkt @@ -0,0 +1,15 @@ +#lang racket + +(require racket/gui/base) + +(define frame (new frame% + [label "Example"] + [width 300] + [height 300])) +(new canvas% [parent frame] + [paint-callback + (lambda (canvas dc) + (send dc set-scale 3 3) + (send dc set-text-foreground "blue") + (send dc draw-text "Don't Panic!" 0 0))]) +(send frame show #t) diff --git a/tests/tcpevents/README.md b/tests/tcpevents/README.md new file mode 100644 index 0000000..7c3ec21 --- /dev/null +++ b/tests/tcpevents/README.md @@ -0,0 +1 @@ +TCP communication racket concepts of events. For more see the racket guide. diff --git a/tests/tcpevents/crpovertcp.rkt b/tests/tcpevents/crpovertcp.rkt new file mode 100644 index 0000000..57874a8 --- /dev/null +++ b/tests/tcpevents/crpovertcp.rkt @@ -0,0 +1,155 @@ +#lang racket +(require math/base) ;; for random number generation + +;; globals +;; must control access via semaphore as listener thread or broadcast thread +;; might need to access it +(define connections '()) ;; maintains a list of open ports +;; ((in1, out1), (in2, out2), (in3, out3), (in4, out4) ...) + +;; lets keep thread descriptor values +; + +(define fair (make-semaphore 1)) ;; managing connections above + +(define can-i-broadcast (make-semaphore 1)) + + +;; + +;; This is a relay server making two clients communicate +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop)) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + (semaphore-wait fair) + ;; keep track of open ports + (append connections (list (list in out))) + (semaphore-wait fiar) + + ; thread will communicate to all clients at once in a broadcast + ; manner + (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out))) + ) + ;; Watcher thread: + ;; kills current thread for waiting too long for connection from + ;; clients + (thread (lambda () + (sleep 120) + (custodian-shutdown-all cust)))) + +; (define (handle connections) +; ()) +;; each thread needs 2 new threads +(define (handle in out) + ; define function to deal with in + (define (something-to-say in) + (sync/timeout 4 (read-line-evt in 'linefeed))) + ; define function to deal with out + ; thread them each + ; (server-loop in out) + (sleep 5) ;; wait 5 seconds to guarantee client has already send message + (define echo (read-line in)) ;; bind message to echo + (displayln (string-append echo "\n")) + ; echo back the message, appending echo + ; could regex match the input to extract the name + (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back + (flush-output out) +) +;; This is a single server communicating directly to the client +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;; author: Ibrahim Mkusa +;; about: print and read concurrently +;; notes: output may need to be aligned and formatted nicely +;; look into +;; https://docs.racket-lang.org/gui/text-field_.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._text-field~25%29._get-editor%29%29 + +;; create custodian for managing all resources +;; so we can shutdown everything at once +;(define guard (make-custodian (current-custodian))) +;(current-custodian guard) +;; reads values continously from stdin and redisplays them +(define (read-loop) + (display (read-line)) + (display "\n") + (read-loop) + ) + +(define input-prompt "input: ") +(define output-prompt "output: ") + +;; prompt for username and bind to a variable username +(display "What's your name?\n") +(define username (read-line)) +(define usernamei (string-append username ": ")) ;; make username appear nicer in a prompt + +;; intelligent read, quits when user types in "quit" +(define (read-loop-i) + + + ;(semaphore-wait fair) + (display usernamei) + (define input (read-line)) + ;; do something over here with input maybe send it out + + ;; Tests input if its a quit then kills all threads + ;; An if would be better here tbh + (cond ((string=? input "quit") (begin (kill-thread a) + (kill-thread t)))) + (display (string-append output-prompt input "\n")) + ;(semaphore-post fair) + (read-loop-i) + ) + + +;; print hello world continously +;; "(hello-world)" can be executed as part of background thread +;; that prints in the event there is something in the input port +(define (hello-world) + (sleep (random-integer 0 15)) ;; sleep between 0 and 15 seconds to simulate coms + ;; with server + ;(semaphore-wait fair) + ;; we will retrieve the line printed below from the server + ;; at this time we simulate the input from different users + (define what-to-print (random-integer 0 2)) + (if (= what-to-print 0) + (display "Doug: What's up, up?\n") + (display "Fred: Looking good, good!\n")) + ;(semaphore-post fair) + (hello-world)) + +(define t (thread (lambda () + (read-loop-i)))) +(define a (thread (lambda () + (hello-world)))) + +(thread-wait t) ;; returns prompt back to drracket +;; below doesn't execute +; (sleep 10) +; (kill-thread t) +; (define a (thread (display "hello world!\n"))) +; (display "John: hello soso\n") +; (display "Emmanuel: cumbaya!!!!\n") diff --git a/tests/tcpevents/server.rkt b/tests/tcpevents/server.rkt new file mode 100644 index 0000000..4313bda --- /dev/null +++ b/tests/tcpevents/server.rkt @@ -0,0 +1,39 @@ +#lang racket + +(define (serve in-port out-port) + (let loop [] + (define evt (sync/timeout 2 + (read-line-evt in-port 'any) + (thread-receive-evt))) + (cond + [(not evt) + (displayln "Timed out, exiting") + (tcp-abandon-port in-port) + (tcp-abandon-port out-port)] + [(string? evt) + (fprintf out-port "~a~n" evt) + (flush-output out-port) + (loop)] + [else + (printf "Received a message in mailbox: ~a~n" + (thread-receive)) + (loop)]))) + +(define port-num 4321) +(define (start-server) + (define listener (tcp-listen port-num)) + (thread + (lambda () + (define-values [in-port out-port] (tcp-accept listener)) + (serve in-port out-port)))) + +(start-server) + +(define client-thread + (thread + (lambda () + (define-values [in-port out-port] (tcp-connect "localhost" port-num)) + (display "first\nsecond\nthird\n" out-port) + (flush-output out-port) + ; copy-port will block until EOF is read from in-port + (copy-port in-port (current-output-port))))) diff --git a/tests/tcpvanilla/README.md b/tests/tcpvanilla/README.md new file mode 100644 index 0000000..b8e2883 --- /dev/null +++ b/tests/tcpvanilla/README.md @@ -0,0 +1,20 @@ +a simple experiment on communication via tcp ports + +a server runs continously servicing clients. Clients connect, send a message, and +server replies with a message. Message should appear in each separate REPL area +prompt + +run server.rkt in a REPL +``` +,en server.rkt +(define stop (serve 8080)) ;; starts serve listening at port 8080 +(stop) ;; to stop server and free the ports + +``` + +run client.rkt in a separate REPL +``` +,en client.rkt +(define stop (client 8080)) ;; starts client talking to server at port 8080 + +``` diff --git a/tests/tcpvanilla/client.rkt b/tests/tcpvanilla/client.rkt new file mode 100644 index 0000000..967d2b9 --- /dev/null +++ b/tests/tcpvanilla/client.rkt @@ -0,0 +1,72 @@ +#lang racket + +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (client 8080)) +;; use your web browser to connect localhost:8080 greeted with "hello world" +;; (stop) to close the server + +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + ;; binds to multiple values akin to unpacking tuples in python + ; (thread (lambda () + (chat in out) + (close-input-port in) + (close-output-port out)) + (custodian-shutdown-all main-client-cust)) + + ; (sleep 60) ;; run for 3 minutes then close + ; (define (loop) + ; (write (read-line (current-input-port)) out) + ; (flush-output out) + ; (write (read-line in) (current-output-port)) + ; (define listener (tcp-listen port-no 5 #t)) + ; (define (loop) + ; (accept-and-handle listener) + ; (loop)) + ; (thread loop))) + ; (custodian-shutdown-all main-client-cust) + #| (lambda () |# + ; (displayln "Goodbye, shutting down client\n") + #| (custodian-shutdown-all main-client-cust)) |# + +(define (chat in out) + ; (driver-loop in out) + (writeln "Ibrahim: Hello, anyone in chat?" out) + (flush-output out) ;; ports are buffered in racket must flush or you + ;; will read #eof + (sleep 10) ;; wait 10 seconds + (define serv-message (read-line in)) + (displayln serv-message) ;; read the servers replay message which is original + ;; with echo appended to it + ) + +; (define input-prompt "Hermes: ") + +(define (driver-loop in out) + ; (prompt-for-input input-prompt) + (display ">>> ") + (define input (read)) + (writeln (string-append "Ibrahim: " input) out) + (flush-output out) + ; (sleep 10) + (define output (read-line in)) + (displayln output) + (driver-loop in out)) + + +#| (let ((input (read))) |# +; ) +; (let ((input (read))) +; (let ((output (mc-eval input the-global-environment))) +; (announce-output output-prompt) +; (user-print output))) +; (driver-loop)) +; +; (define (announce-output string) +; (display string)) +#| |# diff --git a/tests/tcpvanilla/client2.rkt b/tests/tcpvanilla/client2.rkt new file mode 100644 index 0000000..47e3052 --- /dev/null +++ b/tests/tcpvanilla/client2.rkt @@ -0,0 +1,43 @@ +#lang racket + +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (client 8080)) +;; use your web browser to connect localhost:8080 greeted with "hello world" +;; (stop) to close the server + +(define (client port-no) + (define main-client-cust (make-custodian)) + (parameterize ([current-custodian main-client-cust]) + ;; connect to server at port 8080 + (define-values (in out) (tcp-connect "localhost" port-no)) ;; define values + ;; binds to multiple values akin to unpacking tuples in python + (thread (lambda () + (send-message in out) + (close-input-port in) + (close-output-port out)))) + (sleep 20) + ; (define (loop) + ; (write (read-line (current-input-port)) out) + ; (flush-output out) + ; (write (read-line in) (current-output-port)) + ; (define listener (tcp-listen port-no 5 #t)) + ; (define (loop) + ; (accept-and-handle listener) + ; (loop)) + ; (thread loop))) + (custodian-shutdown-all main-client-cust) + #| (lambda () |# + ; (displayln "Goodbye, shutting down client\n") + #| (custodian-shutdown-all main-client-cust)) |#) + +(define (send-message input-port output-port) + (writeln "Doug: Hello, how's it going?" output-port) + (flush-output output-port) ;; ports are buffered in racket must flush or you + ;; will read #eof + (sleep 10) ;; wait 10 seconds + (define serv-message (read-line input-port)) + (displayln serv-message) ;; read the servers replay message which is original + ;; with echo appended to it + ) diff --git a/tests/tcpvanilla/server.rkt b/tests/tcpvanilla/server.rkt new file mode 100644 index 0000000..bf72aff --- /dev/null +++ b/tests/tcpvanilla/server.rkt @@ -0,0 +1,58 @@ +#lang racket + +;; Both `server' and `accept-and-handle' change +;; to use a custodian. +;; To start server +;; (define stop (serve 8080)) +;; use your web browser to connect localhost:8080 greeted with "hello world" +;; (stop) to close the server + +(define (serve port-no) + (define main-cust (make-custodian)) + (parameterize ([current-custodian main-cust]) + (define listener (tcp-listen port-no 5 #t)) + (define (loop) + (accept-and-handle listener) + (loop)) + (thread loop)) + (lambda () + (displayln "\nGoodbye, shutting down all services\n") + (custodian-shutdown-all main-cust))) + +(define (accept-and-handle listener) + (define cust (make-custodian)) + (parameterize ([current-custodian cust]) + (define-values (in out) (tcp-accept listener)) + (thread (lambda () + (handle in out) ;; this handles connection with that specific client + (close-input-port in) + (close-output-port out)))) + ;; Watcher thread: + (thread (lambda () + (sleep 120) + (custodian-shutdown-all cust)))) + +(define (handle in out) + ; (server-loop in out) + (sleep 5) ;; wait 5 seconds to guarantee client has already send message + (define echo (read-line in)) ;; bind message to echo + (displayln (string-append echo "\n")) + ; echo back the message, appending echo + ; could regex match the input to extract the name + (writeln "Admin: Hello there" out) ;; append "echo " to echo and send back + (flush-output out) +) + +(define input-prompt "Hermes: ") + +(define (server-loop in out) + (define echo (read-line in)) + (displayln echo) + (display ">>> ") + + (define input (read)) + (writeln (string-append "Admin: " input) out) + (flush-output out) + ; (sleep 10) + (server-loop in out)) + diff --git a/tests/tcpvanilla/tcptalk.rkt b/tests/tcpvanilla/tcptalk.rkt new file mode 100644 index 0000000..d069851 --- /dev/null +++ b/tests/tcpvanilla/tcptalk.rkt @@ -0,0 +1,30 @@ +#lang racket + +(define listener (tcp-listen 8083 5 #t)) ;; listener to service connection requests +;; client attempts to connect. Receives an input and output port +(define-values (client-in client-out) (tcp-connect "localhost" 8083)) +;; server accepts the connection request. Also gets a pair of ports +(define-values (server-in server-out) (tcp-accept listener)) + +;; client sends identifying message +(display (string-append "Client:My name is " "Ibrahim" "\n") + client-out) +(flush-output client-out) ;; must flush as ports are buffered in racket + +;; server receives and reads it +;; cooler if on separate racket instances +(read-line server-in) ;; --> "Client:My name is #hostname. +;; server replies +(display (string-append "Server:Hi " "Ibrahim" "\n") server-out) +(flush-output server-out) ;; flush flush + +;; client displays server message +(read-line client-in) +(close-output-port server-out) +(close-output-port client-out) +(read-line client-in) ;; --> eof object #eof +(read-line server-in) ;; --> eof object #eof +(tcp-close listener) +; (custodian-shutdown-all (current-custodian)) ;; release all resources including + ;; tcp, file, custom ports + ;; application exits -- cgit v1.2.3