Compare commits
22 Commits
muwire-0.6
...
muwire-0.6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fec81808e5 | ||
![]() |
4db890484d | ||
![]() |
dfd5e06889 | ||
![]() |
71da8e14da | ||
![]() |
7dc37e3e0d | ||
![]() |
3de058a078 | ||
![]() |
4d70c7adce | ||
![]() |
5b41106476 | ||
![]() |
6240b22e66 | ||
![]() |
0e26f5afd7 | ||
![]() |
114bc06dbb | ||
![]() |
5fa2f2753c | ||
![]() |
cacdd2a7a9 | ||
![]() |
d56f7c6184 | ||
![]() |
f7f4513109 | ||
![]() |
dd15d893ba | ||
![]() |
bf5ab9c82e | ||
![]() |
edd5a29b10 | ||
![]() |
38eb89f2f7 | ||
![]() |
73f1d64428 | ||
![]() |
bc1cae2d75 | ||
![]() |
a0ab07a7c0 |
@@ -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
|
||||
|
||||
```
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -84,6 +84,7 @@ class ResultsSender {
|
||||
infohash : it.getInfoHash(),
|
||||
pieceSize : pieceSize,
|
||||
uuid : uuid,
|
||||
browse : settings.browseFiles,
|
||||
sources : suggested,
|
||||
comment : comment,
|
||||
certificates : certificates,
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
@@ -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() {
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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 = {
|
||||
|
@@ -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))
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user