Compare commits

..

22 Commits

Author SHA1 Message Date
Zlatin Balevsky
fec81808e5 Release 0.6.5 2019-11-14 05:15:26 +00:00
Zlatin Balevsky
4db890484d do not rejoin console 2019-11-14 04:49:13 +00:00
Zlatin Balevsky
dfd5e06889 add browse ability from chat room view 2019-11-14 04:40:15 +00:00
Zlatin Balevsky
71da8e14da name button earlier 2019-11-14 04:25:45 +00:00
Zlatin Balevsky
7dc37e3e0d change button to connect/disconnect 2019-11-14 04:20:57 +00:00
Zlatin Balevsky
3de058a078 send rejoins to the console pt2 2019-11-14 03:59:01 +00:00
Zlatin Balevsky
4d70c7adce send rejoins to the console 2019-11-14 03:58:36 +00:00
Zlatin Balevsky
5b41106476 start and stop poller thread on events 2019-11-14 03:45:21 +00:00
Zlatin Balevsky
6240b22e66 fix reconnecting to server, start with fresh member list upon rejoin 2019-11-14 03:13:01 +00:00
Zlatin Balevsky
0e26f5afd7 rejoin rooms on reconnect 2019-11-14 02:40:22 +00:00
Zlatin Balevsky
114bc06dbb If the user explicitly shares a file, remove it form the negative tree. #26 2019-11-13 22:00:10 +00:00
Zlatin Balevsky
5fa2f2753c Release 0.6.4 2019-11-13 20:06:53 +00:00
Zlatin Balevsky
cacdd2a7a9 add browse and chat buttons to trusted panel 2019-11-13 19:40:28 +00:00
Zlatin Balevsky
d56f7c6184 add right-click menu to trusted table 2019-11-13 19:33:34 +00:00
Zlatin Balevsky
f7f4513109 better help and welcome message 2019-11-13 17:50:50 +00:00
Zlatin Balevsky
dd15d893ba Call for help for Web UI 2019-11-13 17:26:14 +00:00
Zlatin Balevsky
bf5ab9c82e ) 2019-11-13 14:10:26 +00:00
Zlatin Balevsky
edd5a29b10 make private chat room ids unique across servers 2019-11-13 14:09:09 +00:00
Zlatin Balevsky
38eb89f2f7 prepend server name to room id in order to make ids unique across server connections 2019-11-13 13:44:22 +00:00
Zlatin Balevsky
73f1d64428 indentation of text field 2019-11-13 12:24:21 +00:00
Zlatin Balevsky
bc1cae2d75 enable sharing of directories from button 2019-11-13 12:03:23 +00:00
Zlatin Balevsky
a0ab07a7c0 show browse status for local results correctly 2019-11-13 11:58:55 +00:00
15 changed files with 189 additions and 41 deletions

View File

@@ -35,6 +35,10 @@ Look inside `cli-lanterna/build/distributions`. Untar/unzip one of the `shadow`
The CLI is under active development and doesn't have all the features of the GUI.
### Web UI
If you are a Grails/Scala/JRuby/Kotlin developer and are interested in building a Web UI for MuWire, please get in touch. The MuWire core is written in Groovy and should be easy to integrate with any JVM-based language.
### GPG Fingerprint
```

View File

@@ -32,7 +32,7 @@ import com.muwire.core.UILoadedEvent
import com.muwire.core.files.AllFilesLoadedEvent
class CliLanterna {
private static final String MW_VERSION = "0.6.3"
private static final String MW_VERSION = "0.6.5"
private static volatile Core core

View File

@@ -436,7 +436,7 @@ public class Core {
}
}
Core core = new Core(props, home, "0.6.3")
Core core = new Core(props, home, "0.6.5")
core.startServices()
// ... at the end, sleep or execute script

View File

@@ -52,7 +52,7 @@ class ChatServer {
running.set(true)
connections.put(me.destination, LocalChatLink.INSTANCE)
joinRoom(me, CONSOLE)
processHelp(me.destination)
echo("/SAY Welcome to my chat server! Type /HELP for list of available commands.",me.destination)
}
private void sendPings() {
@@ -106,7 +106,7 @@ class ChatServer {
connections.put(endpoint.destination, connection)
joinRoom(client, CONSOLE)
connection.start()
processHelp(connection.endpoint.destination)
echo("/SAY Welcome to my chat server! Type /HELP for help on available commands",connection.endpoint.destination)
}
void onChatDisconnectionEvent(ChatDisconnectionEvent e) {
@@ -263,7 +263,15 @@ class ChatServer {
}
private void processHelp(Destination d) {
String help = "/SAY Available commands: /JOIN /LEAVE /SAY /LIST /INFO /HELP"
String help = """/SAY
Available commands: /JOIN /LEAVE /SAY /LIST /INFO /HELP
/JOIN <room name> - joins a room, or creates one if it does not exist. You must type this in the console
/LEAVE - leaves a room. You must type this in the room you want to leave
/SAY - optional, says something in the room you're in
/LIST - lists the existing rooms on this server. You must type this in the console
/INFO - shows information about this server. You must type this in the console
/HELP - prints this help message
"""
echo(help, d)
}

View File

@@ -7,7 +7,7 @@ class FileTree {
private final TreeNode root = new TreeNode()
private final Map<File, TreeNode> fileToNode = new ConcurrentHashMap<>()
void add(File file) {
synchronized void add(File file) {
List<File> path = new ArrayList<>()
path.add(file)
while (file.getParentFile() != null) {
@@ -31,7 +31,7 @@ class FileTree {
}
}
boolean remove(File file) {
synchronized boolean remove(File file) {
TreeNode node = fileToNode.remove(file)
if (node == null) {
return false

View File

@@ -84,6 +84,7 @@ class ResultsSender {
infohash : it.getInfoHash(),
pieceSize : pieceSize,
uuid : uuid,
browse : settings.browseFiles,
sources : suggested,
comment : comment,
certificates : certificates,

View File

@@ -1,5 +1,5 @@
group = com.muwire
version = 0.6.3
version = 0.6.5
i2pVersion = 0.9.43
groovyVersion = 2.4.15
slf4jVersion = 1.7.25

View File

@@ -72,7 +72,7 @@ class ChatRoomController {
params['host'] = model.host
params['roomTabName'] = newRoom
mvcGroup.parentGroup.createMVCGroup("chat-room", newRoom, params)
mvcGroup.parentGroup.createMVCGroup("chat-room", model.host.getHumanReadableName()+"-"+newRoom, params)
}
}
if (command.action == ChatAction.LEAVE && !model.console) {
@@ -101,7 +101,8 @@ class ChatRoomController {
Persona p = view.getSelectedPersona()
if (p == null)
return
if (p != model.core.me && !mvcGroup.parentGroup.childrenGroups.containsKey(p.getHumanReadableName()+"-private-chat")) {
String groupId = model.host.getHumanReadableName() + "-" + p.getHumanReadableName() +"-private-chat"
if (p != model.core.me && !mvcGroup.parentGroup.childrenGroups.containsKey(groupId)) {
def params = [:]
params['core'] = model.core
params['tabName'] = model.tabName
@@ -110,7 +111,7 @@ class ChatRoomController {
params['host'] = model.host
params['roomTabName'] = p.getHumanReadableName()
mvcGroup.parentGroup.createMVCGroup("chat-room", p.getHumanReadableName()+"-private-chat", params)
mvcGroup.parentGroup.createMVCGroup("chat-room", groupId, params)
}
}
@@ -140,6 +141,17 @@ class ChatRoomController {
view.refreshMembersTable()
}
void browse() {
Persona p = view.getSelectedPersona()
if (p == null)
return
String groupId = p.getHumanReadableName() + "-browse"
def params = [:]
params['host'] = p
params['core'] = model.core
mvcGroup.createMVCGroup("browse",groupId,params)
}
void leaveRoom() {
if (leftRoom)
return
@@ -232,4 +244,27 @@ class ChatRoomController {
view.roomTextArea.replaceRange(null, line0Start, line0End)
}
}
void rejoinRoom() {
if (model.room == "Console")
return
model.members.clear()
model.members.add(model.core.me)
UUID uuid = UUID.randomUUID()
long now = System.currentTimeMillis()
String join = "/JOIN $model.room"
byte [] sig = ChatConnection.sign(uuid, now, ChatServer.CONSOLE, join, model.core.me, model.host, model.core.spk)
def event = new ChatMessageEvent(
uuid : uuid,
payload : join,
sender : model.core.me,
host : model.host,
room : ChatServer.CONSOLE,
chatTime : now,
sig : sig
)
model.core.eventBus.publish(event)
}
}

View File

@@ -15,6 +15,14 @@ class ChatServerController {
@ControllerAction
void disconnect() {
model.core.eventBus.publish(new UIDisconnectChatEvent(host : model.host))
switch(model.buttonText) {
case "Disconnect" :
model.buttonText = "Connect"
model.core.eventBus.publish(new UIDisconnectChatEvent(host : model.host))
break
case "Connect" :
model.connect()
break
}
}
}

View File

@@ -234,8 +234,11 @@ class MainFrameController {
int row = view.getSelectedTrustTablesRow(tableName)
if (row < 0)
return
String reason = null
if (level != TrustLevel.NEUTRAL)
reason = JOptionPane.showInputDialog("Enter reason (optional)")
builder.getVariable(tableName).model.fireTableDataChanged()
core.eventBus.publish(new TrustEvent(persona : list[row].persona, level : level))
core.eventBus.publish(new TrustEvent(persona : list[row].persona, level : level, reason : reason))
}
@ControllerAction
@@ -322,6 +325,31 @@ class MainFrameController {
return null
model.subscriptions[row]
}
@ControllerAction
void browseFromTrusted() {
int row = view.getSelectedTrustTablesRow("trusted-table")
if (row < 0)
return
Persona p = model.trusted[row].persona
String groupId = p.getHumanReadableName() + "-browse"
def params = [:]
params['host'] = p
params['core'] = model.core
mvcGroup.createMVCGroup("browse",groupId,params)
}
@ControllerAction
void chatFromTrusted() {
int row = view.getSelectedTrustTablesRow("trusted-table")
if (row < 0)
return
Persona p = model.trusted[row].persona
startChat(p)
view.showChatWindow.call()
}
void unshareSelectedFile() {
def sf = view.selectedSharedFiles()
@@ -462,7 +490,8 @@ class MainFrameController {
params['core'] = model.core
params['host'] = p
mvcGroup.createMVCGroup("chat-server", p.getHumanReadableName(), params)
}
} else
mvcGroup.getChildrenGroups().get(p.getHumanReadableName()).model.connect()
}
void saveMuWireSettings() {

View File

@@ -99,7 +99,7 @@ class SearchTabController {
if (sender == null)
return
String groupId = sender.getHumanReadableName()
String groupId = sender.getHumanReadableName() + "-browse"
Map<String,Object> params = new HashMap<>()
params['host'] = sender
params['core'] = core

View File

@@ -24,6 +24,7 @@ class ChatServerModel {
Core core
@Observable boolean disconnectActionEnabled
@Observable String buttonText = "Disconnect"
@Observable ChatConnectionAttemptStatus status
volatile ChatLink link
@@ -32,40 +33,64 @@ class ChatServerModel {
void mvcGroupInit(Map<String, String> params) {
disconnectActionEnabled = host != core.me // can't disconnect from myself
core.eventBus.with {
register(ChatConnectionEvent.class, this)
publish(new UIConnectChatEvent(host : host))
core.eventBus.register(ChatConnectionEvent.class, this)
connect()
}
void connect() {
runInsideUIAsync {
buttonText = "Disconnect"
}
core.eventBus.publish(new UIConnectChatEvent(host : host))
}
void mvcGroupDestroy() {
stopPoller()
core.eventBus.unregister(ChatConnectionEvent.class, this)
}
private void startPoller() {
if (running)
return
running = true
poller = new Thread({eventLoop()} as Runnable)
poller.setDaemon(true)
poller.start()
}
void mvcGroupDestroy() {
private void stopPoller() {
running = false
poller?.interrupt()
link = null
}
void onChatConnectionEvent(ChatConnectionEvent e) {
if (e.persona == host) {
runInsideUIAsync {
status = e.status
}
}
ChatLink link = e.connection
if (link == null)
if (e.persona != host)
return
if (link.getPersona() == host)
this.link = link
else if (link.getPersona() == null && host == core.me)
this.link = link
runInsideUIAsync {
status = e.status
}
if (e.status == ChatConnectionAttemptStatus.SUCCESSFUL) {
ChatLink link = e.connection
if (link == null)
return
this.link = e.connection
startPoller()
mvcGroup.childrenGroups.each {k,v ->
v.controller.rejoinRoom()
}
} else {
stopPoller()
}
}
private void eventLoop() {
Thread.sleep(1000)
while(running) {
ChatLink link = this.link
if (link == null || !link.isUp()) {
@@ -97,7 +122,7 @@ class ChatServerModel {
}
if (chatCommand.action == ChatAction.SAY &&
room == core.me.toBase64()) {
String groupId = e.sender.getHumanReadableName() + "-private-chat"
String groupId = host.getHumanReadableName()+"-"+e.sender.getHumanReadableName() + "-private-chat"
if (!mvcGroup.childrenGroups.containsKey(groupId)) {
def params = [:]
params['core'] = core
@@ -110,7 +135,8 @@ class ChatServerModel {
mvcGroup.createMVCGroup("chat-room",groupId, params)
}
room = groupId
}
} else
room = host.getHumanReadableName()+"-"+room
mvcGroup.childrenGroups[room]?.controller?.handleChatMessage(e)
}

View File

@@ -80,6 +80,7 @@ class ChatRoomView {
}
panel(constraints : BorderLayout.SOUTH) {
borderLayout()
label(text : "Say something here: ", constraints : BorderLayout.WEST)
sayField = textField(actionPerformed : {controller.say()}, constraints : BorderLayout.CENTER)
button(text : "Say", constraints : BorderLayout.EAST, sayAction)
}
@@ -133,6 +134,9 @@ class ChatRoomView {
JMenuItem privateChat = new JMenuItem("Start Private Chat")
privateChat.addActionListener({controller.privateMessage()})
menu.add(privateChat)
JMenuItem browse = new JMenuItem("Browse")
browse.addActionListener({controller.browse()})
menu.add(browse)
JMenuItem markTrusted = new JMenuItem("Mark Trusted")
markTrusted.addActionListener({controller.markTrusted()})
menu.add(markTrusted)

View File

@@ -31,7 +31,7 @@ class ChatServerView {
gridLayout(rows : 1, cols : 3)
panel {}
panel {
button(text : "Disconnect", enabled : bind {model.disconnectActionEnabled}, disconnectAction)
button(text : bind {model.buttonText}, enabled : bind {model.disconnectActionEnabled}, disconnectAction)
}
panel {
label(text : "Connection Status ")
@@ -69,7 +69,7 @@ class ChatServerView {
params['roomTabName'] = 'Console'
params['console'] = true
params['host'] = model.host
mvcGroup.createMVCGroup("chat-room",ChatServer.CONSOLE, params)
mvcGroup.createMVCGroup("chat-room",model.host.getHumanReadableName()+"-"+ChatServer.CONSOLE, params)
}
def closeTab = {

View File

@@ -306,7 +306,7 @@ class MainFrameView {
radioButton(text : "Table", selected : false, buttonGroup : sharedViewType, actionPerformed : showSharedFilesTable)
}
panel {
button(text : "Share files", actionPerformed : shareFiles)
button(text : "Share", actionPerformed : shareFiles)
button(text : "Add Comment", enabled : bind {model.addCommentButtonEnabled}, addCommentAction)
button(text : "Certify", enabled : bind {model.addCommentButtonEnabled}, issueCertificateAction)
}
@@ -434,6 +434,8 @@ class MainFrameView {
button(text : "Subscribe", enabled : bind {model.subscribeButtonEnabled}, constraints : gbc(gridx: 0, gridy : 0), subscribeAction)
button(text : "Mark Neutral", enabled : bind {model.markNeutralFromTrustedButtonEnabled}, constraints : gbc(gridx: 1, gridy: 0), markNeutralFromTrustedAction)
button(text : "Mark Distrusted", enabled : bind {model.markDistrustedButtonEnabled}, constraints : gbc(gridx: 2, gridy:0), markDistrustedAction)
button(text : "Browse", constraints:gbc(gridx:3, gridy:0), browseFromTrustedAction)
button(text : "Chat", constraints : gbc(gridx:4, gridy:0), chatFromTrustedAction)
}
}
panel (border : etchedBorder()){
@@ -509,7 +511,9 @@ class MainFrameView {
public boolean importData(TransferHandler.TransferSupport support) {
def files = support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor)
files.each {
model.core.eventBus.publish(new FileSharedEvent(file : it))
File canonical = it.getCanonicalFile()
model.core.fileManager.negativeTree.remove(canonical)
model.core.eventBus.publish(new FileSharedEvent(file : canonical))
}
showUploadsWindow.call()
true
@@ -777,6 +781,34 @@ class MainFrameView {
model.markNeutralFromTrustedButtonEnabled = true
}
})
JPopupMenu trustMenu = new JPopupMenu()
JMenuItem subscribeItem = new JMenuItem("Subscribe")
subscribeItem.addActionListener({mvcGroup.controller.subscribe()})
trustMenu.add(subscribeItem)
JMenuItem markNeutralItem = new JMenuItem("Mark Neutral")
markNeutralItem.addActionListener({mvcGroup.controller.markNeutralFromTrusted()})
trustMenu.add(markNeutralItem)
JMenuItem markDistrustedItem = new JMenuItem("Mark Distrusted")
markDistrustedItem.addActionListener({mvcGroup.controller.markDistrusted()})
trustMenu.add(markDistrustedItem)
JMenuItem browseItem = new JMenuItem("Browse")
browseItem.addActionListener({mvcGroup.controller.browseFromTrusted()})
trustMenu.add(browseItem)
JMenuItem chatItem = new JMenuItem("Chat")
chatItem.addActionListener({mvcGroup.controller.chatFromTrusted()})
trustMenu.add(chatItem)
trustedTable.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger() || e.button == MouseEvent.BUTTON3)
showPopupMenu(trustMenu, e)
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger() || e.button == MouseEvent.BUTTON3)
showPopupMenu(trustMenu, e)
}
})
// distrusted table
def distrustedTable = builder.getVariable("distrusted-table")
@@ -1069,13 +1101,14 @@ class MainFrameView {
def shareFiles = {
def chooser = new JFileChooser()
chooser.setFileHidingEnabled(!model.core.muOptions.shareHiddenFiles)
chooser.setDialogTitle("Select file to share")
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY)
chooser.setDialogTitle("Select files or directories to share")
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES)
chooser.setMultiSelectionEnabled(true)
int rv = chooser.showOpenDialog(null)
if (rv == JFileChooser.APPROVE_OPTION) {
chooser.getSelectedFiles().each {
File canonical = it.getCanonicalFile()
model.core.fileManager.negativeTree.remove(canonical)
model.core.eventBus.publish(new FileSharedEvent(file : canonical))
}
}