1 /* 2 * Copyright (C) 2018 Julien Viet 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 module hunt.database.driver.postgresql.impl.codec.InitCommandCodec; 18 19 import hunt.database.driver.postgresql.impl.codec.ErrorResponse; 20 import hunt.database.driver.postgresql.impl.codec.PasswordMessage; 21 import hunt.database.driver.postgresql.impl.codec.CommandCodec; 22 import hunt.database.driver.postgresql.impl.codec.PgEncoder; 23 import hunt.database.driver.postgresql.impl.codec.StartupMessage; 24 25 import hunt.database.base.impl.TxStatus; 26 import hunt.database.base.impl.command.CommandResponse; 27 import hunt.database.base.impl.Connection; 28 import hunt.database.base.impl.command.InitCommand; 29 import hunt.database.driver.postgresql.impl.PostgreSQLSocketConnection; 30 31 import hunt.logging; 32 import hunt.Exceptions; 33 34 class InitCommandCodec : CommandCodec!(DbConnection, InitCommand) { 35 36 private PgEncoder encoder; 37 private string encoding; 38 private PgSocketConnection pgConnection; 39 40 this(InitCommand cmd) { 41 super(cmd); 42 pgConnection = cast(PgSocketConnection)cmd.connection(); 43 } 44 45 override 46 void encode(PgEncoder encoder) { 47 version(HUNT_DB_DEBUG) tracef("encoding..."); 48 this.encoder = encoder; 49 encoder.writeStartupMessage(new StartupMessage(cmd.username(), cmd.database(), cmd.properties())); 50 // encoder.flush(); 51 } 52 53 override 54 void handleAuthenticationMD5Password(byte[] salt) { 55 version(HUNT_DB_DEBUG_MORE) tracef("salt: %(%02X %)", salt); 56 encoder.writePasswordMessage(new PasswordMessage(cmd.username(), cmd.password(), salt)); 57 encoder.flush(); 58 } 59 60 override 61 void handleAuthenticationClearTextPassword() { 62 version(HUNT_DB_DEBUG) tracef("running here"); 63 encoder.writePasswordMessage(new PasswordMessage(cmd.username(), cmd.password(), null)); 64 encoder.flush(); 65 } 66 67 override 68 void handleAuthenticationOk() { 69 version(HUNT_DB_DEBUG) info("TODO: Authentication done."); 70 // TODO: Tasks pending completion -@zxp at Fri, 20 Sep 2019 02:31:50 GMT 71 // Return the server setup information. 72 // handler.handle(Future.succeededFuture(conn)); 73 // handler = null; 74 } 75 76 override 77 void handleParameterStatus(string name, string value) { 78 version(HUNT_DB_DEBUG_MORE) tracef("key: %s, value: %s", name, value); 79 // FIXME: Needing refactor or cleanup -@zxp at Fri, 20 Sep 2019 02:25:36 GMT 80 // handle more status 81 // pgjdbc\src\main\java\org\postgresql\core\v3\QueryExecutorImpl.java 82 83 switch(name) { 84 case "client_encoding": 85 encoding = value; break; 86 87 case "standard_conforming_strings": 88 pgConnection.setStandardConformingStrings(value == "on"); 89 break; 90 91 default: break; 92 } 93 94 if (name == "standard_conforming_strings") { 95 96 } 97 } 98 99 override 100 void handleBackendKeyData(int processId, int secretKey) { 101 version(HUNT_DB_DEBUG) tracef("processId: %d, secretKey: %d", processId, secretKey); 102 pgConnection.processId = processId; 103 pgConnection.secretKey = secretKey; 104 } 105 106 override 107 void handleErrorResponse(ErrorResponse errorResponse) { 108 version(HUNT_DB_DEBUG) warningf("errorResponse: %s", errorResponse.toString()); 109 CommandResponse!(DbConnection) resp = failedResponse!DbConnection(errorResponse.toException()); 110 if(completionHandler !is null) { 111 // resp.cmd = cmd; 112 completionHandler(resp); 113 } 114 } 115 116 override 117 void handleReadyForQuery(TxStatus txStatus) { 118 version(HUNT_DB_DEBUG) tracef("txStatus: %s, encoding: %s", txStatus, encoding); 119 // The final phase before returning the connection 120 // We should make sure we are supporting only UTF8 121 // https://www.postgresql.org/docs/9.5/static/multibyte.html#MULTIBYTE-CHARSET-SUPPORTED 122 // Charset cs = null; 123 // try { 124 // cs = Charset.forName(encoding); 125 // } catch (Exception ignore) { 126 // } 127 128 if(completionHandler !is null) { 129 CommandResponse!(DbConnection) resp; 130 if(encoding != "UTF8") { 131 resp = failedResponse!(DbConnection)(encoding ~ " is not supported in the client only UTF8"); 132 } else { 133 resp = succeededResponse!(DbConnection)(cmd.connection()); 134 } 135 // resp.cmd = cmd; 136 completionHandler(resp); 137 } 138 } 139 }