diff --git a/Projs/PD1/internal/client/client.go b/Projs/PD1/internal/client/client.go index f253c5a..b57b8fe 100644 --- a/Projs/PD1/internal/client/client.go +++ b/Projs/PD1/internal/client/client.go @@ -1,7 +1,60 @@ package client -import "fmt" +import ( + "PD1/internal/protocol" + "PD1/internal/utils/networking" + "flag" + "fmt" +) func Run() { - fmt.Println("Client is running...") + var userFile string + flag.StringVar(&userFile, "user", "userdata.p12", "Specify user data file") + flag.Parse() + + if flag.NArg() == 0 { + panic("No command provided. Use 'help' for instructions.") + } + + command := flag.Arg(0) + switch command { + case "send": + if flag.NArg() < 3 { + panic("Insufficient arguments for 'send' command. Usage: send ") + } + uid := flag.Arg(1) + subject := flag.Arg(2) + // Read message content from stdin + messageContent := readMessageContent() + cl := networking.NewClient[protocol.Packet]() + defer cl.Connection.Conn.Close() + + // TODO: cipherSubject := CHAMAR CRYPTO + // TODO: cipherBody := CHAMAR CRYPTO + submitMessage(cl,uid,cipherSubject,cipherBody) + + case "askqueue": + cl = networking.NewClient[protocol.Packet]() + defer cl.Connection.Conn.Close() + + case "getmsg": + if flag.NArg() < 2 { + panic("Insufficient arguments for 'getmsg' command. Usage: getmsg ") + } + num := flag.Arg(1) + cl = networking.NewClient[protocol.Packet]() + defer cl.Connection.Conn.Close() + + case "help": + showHelp() + + default: + fmt.Println("Invalid command. Use 'help' for instructions.") + } + +} + +func submitMessage(cl networking.Client[protocol.Packet],uid string,subject []byte,body []byte) { + pack := protocol.NewSubmitMessage(uid, subject, body) + cl.Connection.Send(pack) } diff --git a/Projs/PD1/internal/client/interface.go b/Projs/PD1/internal/client/interface.go index da13c8e..05b8dfb 100644 --- a/Projs/PD1/internal/client/interface.go +++ b/Projs/PD1/internal/client/interface.go @@ -1 +1,23 @@ package client + +import ( + "bufio" + "fmt" + "os" +) + +func readMessageContent() string { + fmt.Println("Enter message content (limited to 1000 bytes):") + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + return scanner.Text() +} + +func showHelp() { + fmt.Println("Comandos da aplicação cliente:") + fmt.Println("-user : Especifica o ficheiro com dados do utilizador. Por omissão, será assumido que esse ficheiro é userdata.p12.") + fmt.Println("send : Envia uma mensagem com assunto destinada ao utilizador com identificador . O conteúdo da mensagem será lido do stdin, e o tamanho deve ser limitado a 1000 bytes.") + fmt.Println("askqueue: Solicita ao servidor que lhe envie a lista de mensagens não lidas da queue do utilizador.") + fmt.Println("getmsg : Solicita ao servidor o envio da mensagem da sua queue com número .") + fmt.Println("help: Imprime instruções de uso do programa.") +} diff --git a/Projs/PD1/internal/protocol/protocol.go b/Projs/PD1/internal/protocol/protocol.go index bb6d636..f7d4fac 100644 --- a/Projs/PD1/internal/protocol/protocol.go +++ b/Projs/PD1/internal/protocol/protocol.go @@ -1,60 +1,122 @@ package protocol import ( - "time" + "time" ) type PacketType int const ( - ReqPK PacketType = iota - ReqAllMsg - ReqMsg + ReqPK PacketType = iota + ReqAllMsg + ReqMsg SubmitMsg - SendPK + SendPK Msg ) -type PacketBody interface {} +type PacketBody interface{} type Packet struct { - Flag PacketType - Body PacketBody + Flag PacketType + Body PacketBody } // Client --> Server: Ask for a user's public key type RequestPubKey struct { - FromUID string - KeyUID string + FromUID string + KeyUID string +} + +func NewRequestPubKey(fromUID, keyUID string) Packet { + return Packet{ + Flag: ReqPK, + Body: RequestPubKey{ + FromUID: fromUID, + KeyUID: keyUID, + }, + } } // Client --> Server: Ask for all the client's messages in the queue type RequestAllMsg struct { - FromUID string + FromUID string +} + +func NewRequestAllMsg(fromUID string) Packet { + return Packet{ + Flag: ReqAllMsg, + Body: RequestAllMsg{ + FromUID: fromUID, + }, + } } // Client --> Server: Ask for a specific message in the queue type RequestMsg struct { - Num uint16 + Num uint16 } -// Client --> Server: Send message from client to server +func NewRequestMsg(num uint16) Packet { + return Packet{ + Flag: ReqMsg, + Body: RequestMsg{ + Num: num, + }, + } +} + +// Client --> Server: Send message from client to server type SubmitMessage struct { - ToUID string - Subject []byte - Body []byte + ToUID string + Subject []byte + Body []byte +} + +func NewSubmitMessage(toUID string, subject, body []byte) Packet { + return Packet{ + Flag: SubmitMsg, + Body: SubmitMessage{ + ToUID: toUID, + Subject: subject, + Body: body, + }, + } } // Server --> Client: Send the client the requested public key type SendPubKey struct { - Key []byte + Key []byte +} + +func NewSendPubKey(key []byte) Packet { + return Packet{ + Flag: SendPK, + Body: SendPubKey{ + Key: key, + }, + } } // Server --> Client: Send the client a message type Message struct { - FromUID string - ToUID string - Subject []byte - Body []byte + FromUID string + ToUID string + Subject []byte + Body []byte Timestamp time.Time } + +func NewMessage(fromUID, toUID string, subject, body []byte, timestamp time.Time) Packet { + return Packet{ + Flag: Msg, + Body: Message{ + FromUID: fromUID, + ToUID: toUID, + Subject: subject, + Body: body, + Timestamp: timestamp, + }, + } +} + diff --git a/Projs/PD1/internal/server/server.go b/Projs/PD1/internal/server/server.go index 53b37fe..25a7978 100644 --- a/Projs/PD1/internal/server/server.go +++ b/Projs/PD1/internal/server/server.go @@ -3,19 +3,14 @@ package server import ( "PD1/internal/protocol" "PD1/internal/utils/networking" - "encoding/json" "fmt" ) func clientHandler(connection networking.Connection[protocol.Packet]) { - defer connection.Conn.Close() - - jd := json.NewDecoder(connection.Conn) + defer connection.Conn.Close() for { - var pac protocol.Packet - jd.Decode(&pac) - + pac := connection.Receive() switch pac.Flag { case protocol.ReqPK: fmt.Println("ReqPK") @@ -24,7 +19,7 @@ func clientHandler(connection networking.Connection[protocol.Packet]) { case protocol.ReqMsg: fmt.Println("ReqMsg") case protocol.SubmitMsg: - fmt.Println("SubmitMsh") + fmt.Println("SubmitMsg") } } @@ -35,7 +30,7 @@ func Run(port int) { go server.ListenLoop() for { - //Receive connection via channel + //Receive Connection via channel conn := <-server.C //Launch client handler via clientHandler go clientHandler(conn) diff --git a/Projs/PD1/internal/utils/networking/client.go b/Projs/PD1/internal/utils/networking/client.go new file mode 100644 index 0000000..d9d8a58 --- /dev/null +++ b/Projs/PD1/internal/utils/networking/client.go @@ -0,0 +1,16 @@ +package networking + +import "net" + +type Client[T any] struct { + Connection Connection[T] +} + +func NewClient[T any]() Client[T] { + dialConn, err := net.Dial("tcp", "localhost:8080") + if err != nil { + panic("Could not open connection to server") + } + conn := NewConnection[T](dialConn) + return Client[T]{Connection: conn} +} diff --git a/Projs/PD1/internal/utils/networking/connection.go b/Projs/PD1/internal/utils/networking/connection.go new file mode 100644 index 0000000..d6ab641 --- /dev/null +++ b/Projs/PD1/internal/utils/networking/connection.go @@ -0,0 +1,35 @@ +package networking + +import ( + "encoding/json" + "net" +) + +type Connection[T any] struct { + Conn net.Conn + encoder *json.Encoder + decoder *json.Decoder +} + + +func NewConnection[T any](netConn net.Conn) Connection[T] { + return Connection[T]{ + Conn: netConn, + encoder: json.NewEncoder(netConn), + decoder: json.NewDecoder(netConn), + } +} + +func (jc Connection[T]) Send(obj T) { + if err := jc.encoder.Encode(&obj); err != nil { + panic("Failed encoding data or sending it to connection") + } +} + +func (jc Connection[T]) Receive() T { + var obj T + if err := jc.decoder.Decode(&obj); err != nil { + panic("Failed decoding data or reading it from connection") + } + return obj +} diff --git a/Projs/PD1/internal/utils/networking/networking.go b/Projs/PD1/internal/utils/networking/networking.go deleted file mode 100644 index e4caa88..0000000 --- a/Projs/PD1/internal/utils/networking/networking.go +++ /dev/null @@ -1,76 +0,0 @@ -package networking - -import ( - "encoding/json" - "fmt" - "net" -) - -type Server[T any] struct { - listener net.Listener - C chan Connection[T] -} - -type Client[T any] struct { - conn net.Conn -} - -type Connection[T any] struct { - Conn net.Conn - encoder *json.Encoder - decoder *json.Decoder -} - -func NewServer[T any](port int) Server[T]{ - - listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) - if err != nil { - panic("Server could not bind to address") - } - return Server[T]{ - listener:listener, - C: make(chan Connection[T]), - } -} - -func (s *Server[T]) ListenLoop() { - - for { - listenerConn, err := s.listener.Accept() - if err != nil { - panic("Server could not accept connection") - } - conn := NewConnection[T](listenerConn) - s.C <- conn - } -} - -func (c Client[T]) Connect() Connection[T] { - dialConn, err := net.Dial("tcp", "localhost:8080") - if err != nil { - panic("Could not open connection to server") - } - return NewConnection[T](dialConn) -} - -func NewConnection[T any](netConn net.Conn) Connection[T] { - return Connection[T]{ - Conn: netConn, - encoder: json.NewEncoder(netConn), - decoder: json.NewDecoder(netConn), - } -} - -func (jc Connection[T]) Send(obj T) { - if err := jc.encoder.Encode(&obj); err != nil { - panic("Failed encoding data or sending it to connection") - } -} - -func (jc Connection[T]) Receive() T { - var obj T - if err := jc.decoder.Decode(&obj); err != nil { - panic("Failed decoding data or reading it from connection") - } - return obj -} diff --git a/Projs/PD1/internal/utils/networking/server.go b/Projs/PD1/internal/utils/networking/server.go new file mode 100644 index 0000000..38e5d1c --- /dev/null +++ b/Projs/PD1/internal/utils/networking/server.go @@ -0,0 +1,35 @@ +package networking + +import ( + "fmt" + "net" +) + +type Server[T any] struct { + listener net.Listener + C chan Connection[T] +} + +func NewServer[T any](port int) Server[T]{ + + listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port)) + if err != nil { + panic("Server could not bind to address") + } + return Server[T]{ + listener:listener, + C: make(chan Connection[T]), + } +} + +func (s *Server[T]) ListenLoop() { + + for { + listenerConn, err := s.listener.Accept() + if err != nil { + panic("Server could not accept connection") + } + conn := NewConnection[T](listenerConn) + s.C <- conn + } +} diff --git a/Projs/PD1/tokefile.toml b/Projs/PD1/tokefile.toml index 7e9df95..61d046d 100644 --- a/Projs/PD1/tokefile.toml +++ b/Projs/PD1/tokefile.toml @@ -1,9 +1,9 @@ [targets.setup] -wildcards=[["golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest","github.com/kisielk/errcheck@latest"]] +wildcards=[["golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest"]] cmd="go install @@" [targets.check] -wildcards=[["go vet ./...","shadow ./...","errcheck ./..."]] +wildcards=[["go vet ./...","shadow ./..."]] cmd="@@" [targets.build]